]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
rewrote server sendstates building code, no longer builds two
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4
5 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
6 cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0", "use glBegin(GL_TRIANGLES);glArrayElement();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
7 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
8 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
9 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
10
11 cvar_t r_render = {0, "r_render", "1", "enables rendering calls (you want this on!)"};
12 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
13 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
14 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
15 cvar_t gl_lockarrays = {0, "gl_lockarrays", "0", "enables use of glLockArraysEXT, may cause glitches with some broken drivers, and may be slower than normal"};
16 cvar_t gl_lockarrays_minimumvertices = {0, "gl_lockarrays_minimumvertices", "1", "minimum number of vertices required for use of glLockArraysEXT, setting this too low may reduce performance"};
17 cvar_t gl_vbo = {0, "gl_vbo", "1", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering"};
18
19 int gl_maxdrawrangeelementsvertices;
20 int gl_maxdrawrangeelementsindices;
21
22 #ifdef DEBUGGL
23 int errornumber = 0;
24
25 void GL_PrintError(int errornumber, char *filename, int linenumber)
26 {
27         switch(errornumber)
28         {
29 #ifdef GL_INVALID_ENUM
30         case GL_INVALID_ENUM:
31                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
32                 break;
33 #endif
34 #ifdef GL_INVALID_VALUE
35         case GL_INVALID_VALUE:
36                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
37                 break;
38 #endif
39 #ifdef GL_INVALID_OPERATION
40         case GL_INVALID_OPERATION:
41                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
42                 break;
43 #endif
44 #ifdef GL_STACK_OVERFLOW
45         case GL_STACK_OVERFLOW:
46                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
47                 break;
48 #endif
49 #ifdef GL_STACK_UNDERFLOW
50         case GL_STACK_UNDERFLOW:
51                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
52                 break;
53 #endif
54 #ifdef GL_OUT_OF_MEMORY
55         case GL_OUT_OF_MEMORY:
56                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
57                 break;
58 #endif
59 #ifdef GL_TABLE_TOO_LARGE
60         case GL_TABLE_TOO_LARGE:
61                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
62                 break;
63 #endif
64         default:
65                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
66                 break;
67         }
68 }
69 #endif
70
71 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active");
72
73 void SCR_ScreenShot_f (void);
74
75 static matrix4x4_t backend_viewmatrix;
76 static matrix4x4_t backend_modelmatrix;
77 static matrix4x4_t backend_modelviewmatrix;
78 static matrix4x4_t backend_projectmatrix;
79
80 static unsigned int backendunits, backendimageunits, backendarrayunits, backendactive;
81
82 /*
83 note: here's strip order for a terrain row:
84 0--1--2--3--4
85 |\ |\ |\ |\ |
86 | \| \| \| \|
87 A--B--C--D--E
88 clockwise
89
90 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
91
92 *elements++ = i + row;
93 *elements++ = i;
94 *elements++ = i + row + 1;
95 *elements++ = i;
96 *elements++ = i + 1;
97 *elements++ = i + row + 1;
98
99
100 for (y = 0;y < rows - 1;y++)
101 {
102         for (x = 0;x < columns - 1;x++)
103         {
104                 i = y * rows + x;
105                 *elements++ = i + columns;
106                 *elements++ = i;
107                 *elements++ = i + columns + 1;
108                 *elements++ = i;
109                 *elements++ = i + 1;
110                 *elements++ = i + columns + 1;
111         }
112 }
113
114 alternative:
115 0--1--2--3--4
116 | /| /|\ | /|
117 |/ |/ | \|/ |
118 A--B--C--D--E
119 counterclockwise
120
121 for (y = 0;y < rows - 1;y++)
122 {
123         for (x = 0;x < columns - 1;x++)
124         {
125                 i = y * rows + x;
126                 *elements++ = i;
127                 *elements++ = i + columns;
128                 *elements++ = i + columns + 1;
129                 *elements++ = i + columns;
130                 *elements++ = i + columns + 1;
131                 *elements++ = i + 1;
132         }
133 }
134 */
135
136 int polygonelements[(POLYGONELEMENTS_MAXPOINTS-2)*3];
137 int quadelements[QUADELEMENTS_MAXQUADS*6];
138
139 void GL_Backend_AllocArrays(void)
140 {
141 }
142
143 void GL_Backend_FreeArrays(void)
144 {
145 }
146
147 void GL_VBOStats_f(void)
148 {
149         GL_Mesh_ListVBOs(true);
150 }
151
152 typedef struct gl_bufferobjectinfo_s
153 {
154         int target;
155         int object;
156         size_t size;
157         char name[MAX_QPATH];
158 }
159 gl_bufferobjectinfo_t;
160
161 memexpandablearray_t gl_bufferobjectinfoarray;
162
163 static void gl_backend_start(void)
164 {
165         Con_Print("OpenGL Backend starting...\n");
166         CHECKGLERROR
167
168         if (qglDrawRangeElements != NULL)
169         {
170                 CHECKGLERROR
171                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
172                 CHECKGLERROR
173                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
174                 CHECKGLERROR
175                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
176         }
177
178         backendunits = bound(1, gl_textureunits, MAX_TEXTUREUNITS);
179         backendimageunits = backendunits;
180         backendarrayunits = backendunits;
181         if (gl_support_fragment_shader)
182         {
183                 CHECKGLERROR
184                 qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, (int *)&backendimageunits);
185                 CHECKGLERROR
186                 qglGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, (int *)&backendarrayunits);
187                 CHECKGLERROR
188                 Con_Printf("GLSL shader support detected: texture units = %i texenv, %i image, %i array\n", backendunits, backendimageunits, backendarrayunits);
189                 backendimageunits = bound(1, backendimageunits, MAX_TEXTUREUNITS);
190                 backendarrayunits = bound(1, backendarrayunits, MAX_TEXTUREUNITS);
191         }
192         else if (backendunits > 1)
193                 Con_Printf("multitexture detected: texture units = %i\n", backendunits);
194         else
195                 Con_Printf("singletexture\n");
196
197         GL_Backend_AllocArrays();
198
199         Mem_ExpandableArray_NewArray(&gl_bufferobjectinfoarray, r_main_mempool, sizeof(gl_bufferobjectinfo_t), 128);
200
201         Con_Printf("OpenGL backend started.\n");
202
203         CHECKGLERROR
204
205         backendactive = true;
206 }
207
208 static void gl_backend_shutdown(void)
209 {
210         backendunits = 0;
211         backendimageunits = 0;
212         backendarrayunits = 0;
213         backendactive = false;
214
215         Con_Print("OpenGL Backend shutting down\n");
216
217         Mem_ExpandableArray_FreeArray(&gl_bufferobjectinfoarray);
218
219         GL_Backend_FreeArrays();
220 }
221
222 static void gl_backend_newmap(void)
223 {
224 }
225
226 void gl_backend_init(void)
227 {
228         int i;
229
230         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
231         {
232                 polygonelements[i * 3 + 0] = 0;
233                 polygonelements[i * 3 + 1] = i + 1;
234                 polygonelements[i * 3 + 2] = i + 2;
235         }
236         // elements for rendering a series of quads as triangles
237         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
238         {
239                 quadelements[i * 6 + 0] = i * 4;
240                 quadelements[i * 6 + 1] = i * 4 + 1;
241                 quadelements[i * 6 + 2] = i * 4 + 2;
242                 quadelements[i * 6 + 3] = i * 4;
243                 quadelements[i * 6 + 4] = i * 4 + 2;
244                 quadelements[i * 6 + 5] = i * 4 + 3;
245         }
246
247         Cvar_RegisterVariable(&r_render);
248         Cvar_RegisterVariable(&r_waterwarp);
249         Cvar_RegisterVariable(&gl_polyblend);
250         Cvar_RegisterVariable(&gl_dither);
251         Cvar_RegisterVariable(&gl_lockarrays);
252         Cvar_RegisterVariable(&gl_lockarrays_minimumvertices);
253         Cvar_RegisterVariable(&gl_vbo);
254         Cvar_RegisterVariable(&gl_paranoid);
255         Cvar_RegisterVariable(&gl_printcheckerror);
256 #ifdef NORENDER
257         Cvar_SetValue("r_render", 0);
258 #endif
259
260         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
261         Cvar_RegisterVariable(&gl_mesh_testarrayelement);
262         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
263
264         Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them\n");
265
266         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
267 }
268
269 void GL_SetupView_Orientation_Identity (void)
270 {
271         backend_viewmatrix = identitymatrix;
272         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
273 }
274
275 void GL_SetupView_Orientation_FromEntity(const matrix4x4_t *matrix)
276 {
277         matrix4x4_t tempmatrix, basematrix;
278         Matrix4x4_Invert_Simple(&tempmatrix, matrix);
279         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
280         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
281         Matrix4x4_Concat(&backend_viewmatrix, &basematrix, &tempmatrix);
282         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
283         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
284         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
285         //Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
286         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
287 }
288
289 void GL_SetupView_Mode_Perspective (double frustumx, double frustumy, double zNear, double zFar)
290 {
291         double m[16];
292
293         // set up viewpoint
294         CHECKGLERROR
295         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
296         qglLoadIdentity();CHECKGLERROR
297         // set view pyramid
298         qglFrustum(-frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);CHECKGLERROR
299         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
300         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
301         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
302         GL_SetupView_Orientation_Identity();
303         CHECKGLERROR
304 }
305
306 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double frustumx, double frustumy, double zNear)
307 {
308         double nudge, m[16];
309
310         // set up viewpoint
311         CHECKGLERROR
312         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
313         qglLoadIdentity();CHECKGLERROR
314         // set view pyramid
315         nudge = 1.0 - 1.0 / (1<<23);
316         m[ 0] = 1.0 / frustumx;
317         m[ 1] = 0;
318         m[ 2] = 0;
319         m[ 3] = 0;
320         m[ 4] = 0;
321         m[ 5] = 1.0 / frustumy;
322         m[ 6] = 0;
323         m[ 7] = 0;
324         m[ 8] = 0;
325         m[ 9] = 0;
326         m[10] = -nudge;
327         m[11] = -1;
328         m[12] = 0;
329         m[13] = 0;
330         m[14] = -2 * zNear * nudge;
331         m[15] = 0;
332         qglLoadMatrixd(m);CHECKGLERROR
333         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
334         GL_SetupView_Orientation_Identity();
335         CHECKGLERROR
336         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
337 }
338
339 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
340 {
341         double m[16];
342
343         // set up viewpoint
344         CHECKGLERROR
345         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
346         qglLoadIdentity();CHECKGLERROR
347         qglOrtho(x1, x2, y2, y1, zNear, zFar);CHECKGLERROR
348         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
349         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
350         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
351         GL_SetupView_Orientation_Identity();
352         CHECKGLERROR
353 }
354
355 typedef struct gltextureunit_s
356 {
357         const void *pointer_texcoord;
358         size_t pointer_texcoord_offset;
359         int pointer_texcoord_buffer;
360         int t1d, t2d, t3d, tcubemap;
361         int arrayenabled;
362         unsigned int arraycomponents;
363         int rgbscale, alphascale;
364         int combinergb, combinealpha;
365         // FIXME: add more combine stuff
366         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
367         int texmatrixenabled;
368         matrix4x4_t matrix;
369 }
370 gltextureunit_t;
371
372 static struct gl_state_s
373 {
374         int cullface;
375         int cullfaceenable;
376         int blendfunc1;
377         int blendfunc2;
378         int blend;
379         GLboolean depthmask;
380         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
381         int depthtest;
382         float depthrange[2];
383         int alphatest;
384         int scissortest;
385         unsigned int unit;
386         unsigned int clientunit;
387         gltextureunit_t units[MAX_TEXTUREUNITS];
388         float color4f[4];
389         int lockrange_first;
390         int lockrange_count;
391         int vertexbufferobject;
392         int elementbufferobject;
393         qboolean pointer_color_enabled;
394         const void *pointer_vertex;
395         const void *pointer_color;
396         size_t pointer_vertex_offset;
397         size_t pointer_color_offset;
398         int pointer_vertex_buffer;
399         int pointer_color_buffer;
400 }
401 gl_state;
402
403 static void GL_BindVBO(int bufferobject)
404 {
405         if (gl_state.vertexbufferobject != bufferobject)
406         {
407                 gl_state.vertexbufferobject = bufferobject;
408                 CHECKGLERROR
409                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);
410                 CHECKGLERROR
411         }
412 }
413
414 static void GL_BindEBO(int bufferobject)
415 {
416         if (gl_state.elementbufferobject != bufferobject)
417         {
418                 gl_state.elementbufferobject = bufferobject;
419                 CHECKGLERROR
420                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);
421                 CHECKGLERROR
422         }
423 }
424
425 void GL_SetupTextureState(void)
426 {
427         unsigned int i;
428         gltextureunit_t *unit;
429         CHECKGLERROR
430         gl_state.unit = MAX_TEXTUREUNITS;
431         gl_state.clientunit = MAX_TEXTUREUNITS;
432         for (i = 0;i < MAX_TEXTUREUNITS;i++)
433         {
434                 unit = gl_state.units + i;
435                 unit->t1d = 0;
436                 unit->t2d = 0;
437                 unit->t3d = 0;
438                 unit->tcubemap = 0;
439                 unit->arrayenabled = false;
440                 unit->arraycomponents = 0;
441                 unit->pointer_texcoord = NULL;
442                 unit->pointer_texcoord_buffer = 0;
443                 unit->pointer_texcoord_offset = 0;
444                 unit->rgbscale = 1;
445                 unit->alphascale = 1;
446                 unit->combinergb = GL_MODULATE;
447                 unit->combinealpha = GL_MODULATE;
448                 unit->texmatrixenabled = false;
449                 unit->matrix = identitymatrix;
450         }
451
452         for (i = 0;i < backendimageunits;i++)
453         {
454                 GL_ActiveTexture(i);
455                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
456                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
457                 if (gl_texture3d)
458                 {
459                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
460                 }
461                 if (gl_texturecubemap)
462                 {
463                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
464                 }
465         }
466
467         for (i = 0;i < backendarrayunits;i++)
468         {
469                 GL_ClientActiveTexture(i);
470                 GL_BindVBO(0);
471                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
472                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
473         }
474
475         for (i = 0;i < backendunits;i++)
476         {
477                 GL_ActiveTexture(i);
478                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
479                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
480                 if (gl_texture3d)
481                 {
482                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
483                 }
484                 if (gl_texturecubemap)
485                 {
486                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
487                 }
488                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
489                 qglLoadIdentity();CHECKGLERROR
490                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
491                 if (gl_combine.integer)
492                 {
493                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
494                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
495                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
496                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
497                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
498                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
499                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
500                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
501                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
502                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
503                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
504                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
505                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
506                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
507                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
508                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
509                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
510                 }
511                 else
512                 {
513                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
514                 }
515                 CHECKGLERROR
516         }
517         CHECKGLERROR
518 }
519
520 void GL_Backend_ResetState(void)
521 {
522         memset(&gl_state, 0, sizeof(gl_state));
523         gl_state.depthtest = true;
524         gl_state.alphatest = false;
525         gl_state.blendfunc1 = GL_ONE;
526         gl_state.blendfunc2 = GL_ZERO;
527         gl_state.blend = false;
528         gl_state.depthmask = GL_TRUE;
529         gl_state.colormask = 15;
530         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
531         gl_state.lockrange_first = 0;
532         gl_state.lockrange_count = 0;
533         gl_state.cullface = GL_FRONT; // quake is backwards, this culls back faces
534         gl_state.cullfaceenable = true;
535
536         CHECKGLERROR
537
538         qglColorMask(1, 1, 1, 1);
539         qglAlphaFunc(GL_GEQUAL, 0.5);CHECKGLERROR
540         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
541         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
542         qglDisable(GL_BLEND);CHECKGLERROR
543         qglCullFace(gl_state.cullface);CHECKGLERROR
544         qglEnable(GL_CULL_FACE);CHECKGLERROR
545         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
546         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
547         qglDepthMask(gl_state.depthmask);CHECKGLERROR
548
549         if (gl_support_arb_vertex_buffer_object)
550         {
551                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
552                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
553         }
554
555         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
556         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
557
558         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
559         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
560
561         GL_Color(0, 0, 0, 0);
562         GL_Color(1, 1, 1, 1);
563
564         GL_SetupTextureState();
565 }
566
567 void GL_ActiveTexture(unsigned int num)
568 {
569         if (gl_state.unit != num)
570         {
571                 gl_state.unit = num;
572                 if (qglActiveTexture)
573                 {
574                         CHECKGLERROR
575                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
576                         CHECKGLERROR
577                 }
578         }
579 }
580
581 void GL_ClientActiveTexture(unsigned int num)
582 {
583         if (gl_state.clientunit != num)
584         {
585                 gl_state.clientunit = num;
586                 if (qglActiveTexture)
587                 {
588                         CHECKGLERROR
589                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
590                         CHECKGLERROR
591                 }
592         }
593 }
594
595 void GL_BlendFunc(int blendfunc1, int blendfunc2)
596 {
597         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
598         {
599                 CHECKGLERROR
600                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
601                 if (gl_state.blendfunc2 == GL_ZERO)
602                 {
603                         if (gl_state.blendfunc1 == GL_ONE)
604                         {
605                                 if (gl_state.blend)
606                                 {
607                                         gl_state.blend = 0;
608                                         qglDisable(GL_BLEND);CHECKGLERROR
609                                 }
610                         }
611                         else
612                         {
613                                 if (!gl_state.blend)
614                                 {
615                                         gl_state.blend = 1;
616                                         qglEnable(GL_BLEND);CHECKGLERROR
617                                 }
618                         }
619                 }
620                 else
621                 {
622                         if (!gl_state.blend)
623                         {
624                                 gl_state.blend = 1;
625                                 qglEnable(GL_BLEND);CHECKGLERROR
626                         }
627                 }
628         }
629 }
630
631 void GL_DepthMask(int state)
632 {
633         if (gl_state.depthmask != state)
634         {
635                 CHECKGLERROR
636                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
637         }
638 }
639
640 void GL_DepthTest(int state)
641 {
642         if (gl_state.depthtest != state)
643         {
644                 gl_state.depthtest = state;
645                 CHECKGLERROR
646                 if (gl_state.depthtest)
647                 {
648                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
649                 }
650                 else
651                 {
652                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
653                 }
654         }
655 }
656
657 void GL_DepthRange(float nearfrac, float farfrac)
658 {
659         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
660         {
661                 gl_state.depthrange[0] = nearfrac;
662                 gl_state.depthrange[1] = farfrac;
663                 qglDepthRange(nearfrac, farfrac);
664         }
665 }
666
667 void GL_CullFace(int state)
668 {
669         CHECKGLERROR
670         if (state != GL_NONE)
671         {
672                 if (!gl_state.cullfaceenable)
673                 {
674                         gl_state.cullfaceenable = true;
675                         qglEnable(GL_CULL_FACE);CHECKGLERROR
676                 }
677                 if (gl_state.cullface != state)
678                 {
679                         gl_state.cullface = state;
680                         qglCullFace(gl_state.cullface);CHECKGLERROR
681                 }
682         }
683         else
684         {
685                 if (gl_state.cullfaceenable)
686                 {
687                         gl_state.cullfaceenable = false;
688                         qglDisable(GL_CULL_FACE);CHECKGLERROR
689                 }
690         }
691 }
692
693 void GL_AlphaTest(int state)
694 {
695         if (gl_state.alphatest != state)
696         {
697                 gl_state.alphatest = state;
698                 CHECKGLERROR
699                 if (gl_state.alphatest)
700                 {
701                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
702                 }
703                 else
704                 {
705                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
706                 }
707         }
708 }
709
710 void GL_ColorMask(int r, int g, int b, int a)
711 {
712         int state = r*8 + g*4 + b*2 + a*1;
713         if (gl_state.colormask != state)
714         {
715                 gl_state.colormask = state;
716                 CHECKGLERROR
717                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
718         }
719 }
720
721 void GL_Color(float cr, float cg, float cb, float ca)
722 {
723         if (gl_state.pointer_color_enabled || gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
724         {
725                 gl_state.color4f[0] = cr;
726                 gl_state.color4f[1] = cg;
727                 gl_state.color4f[2] = cb;
728                 gl_state.color4f[3] = ca;
729                 CHECKGLERROR
730                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
731                 CHECKGLERROR
732         }
733 }
734
735 void GL_LockArrays(int first, int count)
736 {
737         if (count < gl_lockarrays_minimumvertices.integer)
738         {
739                 first = 0;
740                 count = 0;
741         }
742         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
743         {
744                 if (gl_state.lockrange_count)
745                 {
746                         gl_state.lockrange_count = 0;
747                         CHECKGLERROR
748                         qglUnlockArraysEXT();
749                         CHECKGLERROR
750                 }
751                 if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
752                 {
753                         gl_state.lockrange_first = first;
754                         gl_state.lockrange_count = count;
755                         CHECKGLERROR
756                         qglLockArraysEXT(first, count);
757                         CHECKGLERROR
758                 }
759         }
760 }
761
762 void GL_Scissor (int x, int y, int width, int height)
763 {
764         CHECKGLERROR
765         qglScissor(x, vid.height - (y + height),width,height);
766         CHECKGLERROR
767 }
768
769 void GL_ScissorTest(int state)
770 {
771         if(gl_state.scissortest == state)
772                 return;
773
774         CHECKGLERROR
775         if((gl_state.scissortest = state))
776                 qglEnable(GL_SCISSOR_TEST);
777         else
778                 qglDisable(GL_SCISSOR_TEST);
779         CHECKGLERROR
780 }
781
782 void GL_Clear(int mask)
783 {
784         CHECKGLERROR
785         qglClear(mask);CHECKGLERROR
786 }
787
788 void GL_TransformToScreen(const vec4_t in, vec4_t out)
789 {
790         vec4_t temp;
791         float iw;
792         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
793         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
794         iw = 1.0f / out[3];
795         out[0] = r_view.x + (out[0] * iw + 1.0f) * r_view.width * 0.5f;
796         out[1] = r_view.y + r_view.height - (out[1] * iw + 1.0f) * r_view.height * 0.5f;
797         out[2] = r_view.z + (out[2] * iw + 1.0f) * r_view.depth * 0.5f;
798 }
799
800 // called at beginning of frame
801 void R_Mesh_Start(void)
802 {
803         BACKENDACTIVECHECK
804         CHECKGLERROR
805         if (gl_printcheckerror.integer && !gl_paranoid.integer)
806         {
807                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
808                 Cvar_SetValueQuick(&gl_paranoid, 1);
809         }
810         GL_Backend_ResetState();
811 }
812
813 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
814 {
815         int shaderobject;
816         int shadercompiled;
817         char compilelog[MAX_INPUTLINE];
818         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
819         if (!shaderobject)
820                 return false;
821         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
822         qglCompileShaderARB(shaderobject);CHECKGLERROR
823         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
824         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
825         if (compilelog[0])
826                 Con_DPrintf("%s shader compile log:\n%s\n", shadertype, compilelog);
827         if (!shadercompiled)
828         {
829                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
830                 return false;
831         }
832         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
833         qglDeleteObjectARB(shaderobject);CHECKGLERROR
834         return true;
835 }
836
837 unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int geometrystrings_count, const char **geometrystrings_list, int fragmentstrings_count, const char **fragmentstrings_list)
838 {
839         GLint programlinked;
840         GLuint programobject = 0;
841         char linklog[MAX_INPUTLINE];
842         CHECKGLERROR
843
844         programobject = qglCreateProgramObjectARB();CHECKGLERROR
845         if (!programobject)
846                 return 0;
847
848         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
849                 goto cleanup;
850
851 #ifdef GL_GEOMETRY_SHADER_ARB
852         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
853                 goto cleanup;
854 #endif
855
856         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
857                 goto cleanup;
858
859         qglLinkProgramARB(programobject);CHECKGLERROR
860         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
861         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
862         if (linklog[0])
863         {
864                 Con_DPrintf("program link log:\n%s\n", linklog);
865                 // software vertex shader is ok but software fragment shader is WAY
866                 // too slow, fail program if so.
867                 // NOTE: this string might be ATI specific, but that's ok because the
868                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
869                 // software fragment shader due to low instruction and dependent
870                 // texture limits.
871                 if (strstr(linklog, "fragment shader will run in software"))
872                         programlinked = false;
873         }
874         if (!programlinked)
875                 goto cleanup;
876         return programobject;
877 cleanup:
878         qglDeleteObjectARB(programobject);CHECKGLERROR
879         return 0;
880 }
881
882 void GL_Backend_FreeProgram(unsigned int prog)
883 {
884         CHECKGLERROR
885         qglDeleteObjectARB(prog);
886         CHECKGLERROR
887 }
888
889 int gl_backend_rebindtextures;
890
891 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
892 {
893         int i;
894         if (offset)
895         {
896                 for (i = 0;i < count;i++)
897                         *out++ = *in++ + offset;
898         }
899         else
900                 memcpy(out, in, sizeof(*out) * count);
901 }
902
903 // renders triangles using vertices from the active arrays
904 int paranoidblah = 0;
905 void R_Mesh_Draw(int firstvertex, int numvertices, int numtriangles, const int *elements, int bufferobject, size_t bufferoffset)
906 {
907         unsigned int numelements = numtriangles * 3;
908         if (numvertices < 3 || numtriangles < 1)
909         {
910                 Con_Printf("R_Mesh_Draw(%d, %d, %d, %8p, %i, %p);\n", firstvertex, numvertices, numtriangles, elements, bufferobject, (void *)bufferoffset);
911                 return;
912         }
913         if (!gl_vbo.integer)
914                 bufferobject = 0;
915         CHECKGLERROR
916         r_refdef.stats.meshes++;
917         r_refdef.stats.meshes_elements += numelements;
918         if (gl_paranoid.integer)
919         {
920                 unsigned int i, j, size;
921                 const int *p;
922                 // note: there's no validation done here on buffer objects because it
923                 // is somewhat difficult to get at the data, and gl_paranoid can be
924                 // used without buffer objects if the need arises
925                 // (the data could be gotten using glMapBuffer but it would be very
926                 //  slow due to uncachable video memory reads)
927                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
928                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
929                 CHECKGLERROR
930                 if (gl_state.pointer_vertex)
931                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
932                                 paranoidblah += *p;
933                 if (gl_state.pointer_color_enabled)
934                 {
935                         if (!qglIsEnabled(GL_COLOR_ARRAY))
936                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
937                         CHECKGLERROR
938                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
939                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
940                                         paranoidblah += *p;
941                 }
942                 for (i = 0;i < backendarrayunits;i++)
943                 {
944                         if (gl_state.units[i].arrayenabled)
945                         {
946                                 GL_ClientActiveTexture(i);
947                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
948                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
949                                 CHECKGLERROR
950                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
951                                         for (j = 0, size = numvertices * gl_state.units[i].arraycomponents, p = (int *)((float *)gl_state.units[i].pointer_texcoord + firstvertex * gl_state.units[i].arraycomponents);j < size;j++, p++)
952                                                 paranoidblah += *p;
953                         }
954                 }
955                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
956                 {
957                         if (elements[i] < firstvertex || elements[i] >= firstvertex + numvertices)
958                         {
959                                 Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in elements list\n", elements[i], firstvertex, firstvertex + numvertices);
960                                 return;
961                         }
962                 }
963                 CHECKGLERROR
964         }
965         if (r_render.integer)
966         {
967                 CHECKGLERROR
968                 if (gl_mesh_testmanualfeeding.integer)
969                 {
970                         unsigned int i, j;
971                         const GLfloat *p;
972                         qglBegin(GL_TRIANGLES);
973                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
974                         {
975                                 for (j = 0;j < backendarrayunits;j++)
976                                 {
977                                         if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled)
978                                         {
979                                                 if (backendarrayunits > 1)
980                                                 {
981                                                         if (gl_state.units[j].arraycomponents == 4)
982                                                         {
983                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
984                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
985                                                         }
986                                                         else if (gl_state.units[j].arraycomponents == 3)
987                                                         {
988                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
989                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
990                                                         }
991                                                         else if (gl_state.units[j].arraycomponents == 2)
992                                                         {
993                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
994                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
995                                                         }
996                                                         else
997                                                         {
998                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
999                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
1000                                                         }
1001                                                 }
1002                                                 else
1003                                                 {
1004                                                         if (gl_state.units[j].arraycomponents == 4)
1005                                                         {
1006                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
1007                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
1008                                                         }
1009                                                         else if (gl_state.units[j].arraycomponents == 3)
1010                                                         {
1011                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
1012                                                                 qglTexCoord3f(p[0], p[1], p[2]);
1013                                                         }
1014                                                         else if (gl_state.units[j].arraycomponents == 2)
1015                                                         {
1016                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
1017                                                                 qglTexCoord2f(p[0], p[1]);
1018                                                         }
1019                                                         else
1020                                                         {
1021                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
1022                                                                 qglTexCoord1f(p[0]);
1023                                                         }
1024                                                 }
1025                                         }
1026                                 }
1027                                 if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1028                                 {
1029                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
1030                                         qglColor4f(p[0], p[1], p[2], p[3]);
1031                                 }
1032                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
1033                                 qglVertex3f(p[0], p[1], p[2]);
1034                         }
1035                         qglEnd();
1036                         CHECKGLERROR
1037                 }
1038                 else if (gl_mesh_testarrayelement.integer)
1039                 {
1040                         int i;
1041                         qglBegin(GL_TRIANGLES);
1042                         for (i = 0;i < numtriangles * 3;i++)
1043                         {
1044                                 qglArrayElement(elements[i]);
1045                         }
1046                         qglEnd();
1047                         CHECKGLERROR
1048                 }
1049                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1050                 {
1051                         GL_BindEBO(bufferobject);
1052                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, bufferobject ? (void *)bufferoffset : elements);
1053                         CHECKGLERROR
1054                 }
1055                 else
1056                 {
1057                         GL_BindEBO(bufferobject);
1058                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, bufferobject ? (void *)bufferoffset : elements);
1059                         CHECKGLERROR
1060                 }
1061         }
1062 }
1063
1064 // restores backend state, used when done with 3D rendering
1065 void R_Mesh_Finish(void)
1066 {
1067         unsigned int i;
1068         BACKENDACTIVECHECK
1069         CHECKGLERROR
1070         GL_LockArrays(0, 0);
1071         CHECKGLERROR
1072
1073         for (i = 0;i < backendimageunits;i++)
1074         {
1075                 GL_ActiveTexture(i);
1076                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
1077                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1078                 if (gl_texture3d)
1079                 {
1080                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1081                 }
1082                 if (gl_texturecubemap)
1083                 {
1084                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1085                 }
1086         }
1087         for (i = 0;i < backendarrayunits;i++)
1088         {
1089                 GL_ActiveTexture(backendarrayunits - 1 - i);
1090                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1091         }
1092         for (i = 0;i < backendunits;i++)
1093         {
1094                 GL_ActiveTexture(backendunits - 1 - i);
1095                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1096                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1097                 if (gl_texture3d)
1098                 {
1099                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1100                 }
1101                 if (gl_texturecubemap)
1102                 {
1103                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1104                 }
1105                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1106                 if (gl_combine.integer)
1107                 {
1108                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1109                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1110                 }
1111         }
1112         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1113         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1114
1115         qglDisable(GL_BLEND);CHECKGLERROR
1116         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1117         qglDepthMask(GL_TRUE);CHECKGLERROR
1118         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1119 }
1120
1121 int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name)
1122 {
1123         gl_bufferobjectinfo_t *info;
1124         GLuint bufferobject;
1125
1126         if (!gl_vbo.integer)
1127                 return 0;
1128
1129         qglGenBuffersARB(1, &bufferobject);
1130         switch(target)
1131         {
1132         case GL_ELEMENT_ARRAY_BUFFER_ARB: GL_BindEBO(bufferobject);break;
1133         case GL_ARRAY_BUFFER_ARB: GL_BindVBO(bufferobject);break;
1134         default: Sys_Error("R_Mesh_CreateStaticBufferObject: unknown target type %i\n", target);return 0;
1135         }
1136         qglBufferDataARB(target, size, data, GL_STATIC_DRAW_ARB);
1137
1138         info = Mem_ExpandableArray_AllocRecord(&gl_bufferobjectinfoarray);
1139         memset(info, 0, sizeof(*info));
1140         info->target = target;
1141         info->object = bufferobject;
1142         info->size = size;
1143         strlcpy(info->name, name, sizeof(info->name));
1144
1145         return (int)bufferobject;
1146 }
1147
1148 void R_Mesh_DestroyBufferObject(int bufferobject)
1149 {
1150         int i, endindex;
1151         gl_bufferobjectinfo_t *info;
1152
1153         qglDeleteBuffersARB(1, (GLuint *)&bufferobject);
1154
1155         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1156         for (i = 0;i < endindex;i++)
1157         {
1158                 info = Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1159                 if (!info)
1160                         continue;
1161                 if (info->object == bufferobject)
1162                 {
1163                         Mem_ExpandableArray_FreeRecord(&gl_bufferobjectinfoarray, (void *)info);
1164                         break;
1165                 }
1166         }
1167 }
1168
1169 void GL_Mesh_ListVBOs(qboolean printeach)
1170 {
1171         int i, endindex;
1172         size_t ebocount = 0, ebomemory = 0;
1173         size_t vbocount = 0, vbomemory = 0;
1174         gl_bufferobjectinfo_t *info;
1175         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1176         for (i = 0;i < endindex;i++)
1177         {
1178                 info = Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1179                 if (!info)
1180                         continue;
1181                 switch(info->target)
1182                 {
1183                 case GL_ELEMENT_ARRAY_BUFFER_ARB: ebocount++;ebomemory += info->size;if (printeach) Con_Printf("EBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break;
1184                 case GL_ARRAY_BUFFER_ARB: vbocount++;vbomemory += info->size;if (printeach) Con_Printf("VBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break;
1185                 default: Con_Printf("gl_vbostats: unknown target type %i\n", info->target);break;
1186                 }
1187         }
1188         Con_Printf("vertex buffers: %i element buffers totalling %i bytes (%.3f MB), %i vertex buffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0);
1189 }
1190
1191 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1192 {
1193         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1194         {
1195                 double glmatrix[16];
1196                 backend_modelmatrix = *matrix;
1197                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
1198                 Matrix4x4_ToArrayDoubleGL(&backend_modelviewmatrix, glmatrix);
1199                 CHECKGLERROR
1200                 qglLoadMatrixd(glmatrix);CHECKGLERROR
1201         }
1202 }
1203
1204 void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset)
1205 {
1206         if (!gl_vbo.integer)
1207                 bufferobject = 0;
1208         if (gl_state.pointer_vertex != vertex3f || gl_state.pointer_vertex_buffer != bufferobject || gl_state.pointer_vertex_offset != bufferoffset)
1209         {
1210                 gl_state.pointer_vertex = vertex3f;
1211                 gl_state.pointer_vertex_buffer = bufferobject;
1212                 gl_state.pointer_vertex_offset = bufferoffset;
1213                 CHECKGLERROR
1214                 GL_BindVBO(bufferobject);
1215                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), bufferobject ? (void *)bufferoffset : vertex3f);CHECKGLERROR
1216         }
1217 }
1218
1219 void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset)
1220 {
1221         // note: this can not rely on bufferobject to decide whether a color array
1222         // is supplied, because surfmesh_t shares one vbo for all arrays, which
1223         // means that a valid vbo may be supplied even if there is no color array.
1224         if (color4f)
1225         {
1226                 if (!gl_vbo.integer)
1227                         bufferobject = 0;
1228                 // caller wants color array enabled
1229                 if (!gl_state.pointer_color_enabled)
1230                 {
1231                         gl_state.pointer_color_enabled = true;
1232                         CHECKGLERROR
1233                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1234                 }
1235                 if (gl_state.pointer_color != color4f || gl_state.pointer_color_buffer != bufferobject || gl_state.pointer_color_offset != bufferoffset)
1236                 {
1237                         gl_state.pointer_color = color4f;
1238                         gl_state.pointer_color_buffer = bufferobject;
1239                         gl_state.pointer_color_offset = bufferoffset;
1240                         CHECKGLERROR
1241                         GL_BindVBO(bufferobject);
1242                         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), bufferobject ? (void *)bufferoffset : color4f);CHECKGLERROR
1243                 }
1244         }
1245         else
1246         {
1247                 // caller wants color array disabled
1248                 if (gl_state.pointer_color_enabled)
1249                 {
1250                         gl_state.pointer_color_enabled = false;
1251                         CHECKGLERROR
1252                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1253                         // when color array is on the glColor gets trashed, set it again
1254                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1255                 }
1256         }
1257 }
1258
1259 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset)
1260 {
1261         gltextureunit_t *unit = gl_state.units + unitnum;
1262         // update array settings
1263         CHECKGLERROR
1264         // note: there is no need to check bufferobject here because all cases
1265         // that involve a valid bufferobject also supply a texcoord array
1266         if (texcoord)
1267         {
1268                 if (!gl_vbo.integer)
1269                         bufferobject = 0;
1270                 // texture array unit is enabled, enable the array
1271                 if (!unit->arrayenabled)
1272                 {
1273                         unit->arrayenabled = true;
1274                         GL_ClientActiveTexture(unitnum);
1275                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1276                 }
1277                 // texcoord array
1278                 if (unit->pointer_texcoord != texcoord || unit->pointer_texcoord_buffer != bufferobject || unit->pointer_texcoord_offset != bufferoffset || unit->arraycomponents != numcomponents)
1279                 {
1280                         unit->pointer_texcoord = texcoord;
1281                         unit->pointer_texcoord_buffer = bufferobject;
1282                         unit->pointer_texcoord_offset = bufferoffset;
1283                         unit->arraycomponents = numcomponents;
1284                         GL_ClientActiveTexture(unitnum);
1285                         GL_BindVBO(bufferobject);
1286                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, bufferobject ? (void *)bufferoffset : texcoord);CHECKGLERROR
1287                 }
1288         }
1289         else
1290         {
1291                 // texture array unit is disabled, disable the array
1292                 if (unit->arrayenabled)
1293                 {
1294                         unit->arrayenabled = false;
1295                         GL_ClientActiveTexture(unitnum);
1296                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1297                 }
1298         }
1299 }
1300
1301 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
1302 {
1303         gltextureunit_t *unit = gl_state.units + unitnum;
1304         if (unitnum >= backendimageunits)
1305                 return;
1306         // update 1d texture binding
1307         if (unit->t1d != tex1d)
1308         {
1309                 GL_ActiveTexture(unitnum);
1310                 if (unitnum < backendunits)
1311                 {
1312                         if (tex1d)
1313                         {
1314                                 if (unit->t1d == 0)
1315                                 {
1316                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1317                                 }
1318                         }
1319                         else
1320                         {
1321                                 if (unit->t1d)
1322                                 {
1323                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1324                                 }
1325                         }
1326                 }
1327                 unit->t1d = tex1d;
1328                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1329         }
1330         // update 2d texture binding
1331         if (unit->t2d != tex2d)
1332         {
1333                 GL_ActiveTexture(unitnum);
1334                 if (unitnum < backendunits)
1335                 {
1336                         if (tex2d)
1337                         {
1338                                 if (unit->t2d == 0)
1339                                 {
1340                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1341                                 }
1342                         }
1343                         else
1344                         {
1345                                 if (unit->t2d)
1346                                 {
1347                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1348                                 }
1349                         }
1350                 }
1351                 unit->t2d = tex2d;
1352                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1353         }
1354         // update 3d texture binding
1355         if (unit->t3d != tex3d)
1356         {
1357                 GL_ActiveTexture(unitnum);
1358                 if (unitnum < backendunits)
1359                 {
1360                         if (tex3d)
1361                         {
1362                                 if (unit->t3d == 0)
1363                                 {
1364                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1365                                 }
1366                         }
1367                         else
1368                         {
1369                                 if (unit->t3d)
1370                                 {
1371                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1372                                 }
1373                         }
1374                 }
1375                 unit->t3d = tex3d;
1376                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1377         }
1378         // update cubemap texture binding
1379         if (unit->tcubemap != texcubemap)
1380         {
1381                 GL_ActiveTexture(unitnum);
1382                 if (unitnum < backendunits)
1383                 {
1384                         if (texcubemap)
1385                         {
1386                                 if (unit->tcubemap == 0)
1387                                 {
1388                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1389                                 }
1390                         }
1391                         else
1392                         {
1393                                 if (unit->tcubemap)
1394                                 {
1395                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1396                                 }
1397                         }
1398                 }
1399                 unit->tcubemap = texcubemap;
1400                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1401         }
1402 }
1403
1404 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1405 {
1406         gltextureunit_t *unit = gl_state.units + unitnum;
1407         if (unitnum >= backendimageunits)
1408                 return;
1409         // update 1d texture binding
1410         if (unit->t1d != texnum)
1411         {
1412                 GL_ActiveTexture(unitnum);
1413                 if (unitnum < backendunits)
1414                 {
1415                         if (texnum)
1416                         {
1417                                 if (unit->t1d == 0)
1418                                 {
1419                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1420                                 }
1421                         }
1422                         else
1423                         {
1424                                 if (unit->t1d)
1425                                 {
1426                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1427                                 }
1428                         }
1429                 }
1430                 unit->t1d = texnum;
1431                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1432         }
1433         // update 2d texture binding
1434         if (unit->t2d)
1435         {
1436                 GL_ActiveTexture(unitnum);
1437                 if (unitnum < backendunits)
1438                 {
1439                         if (unit->t2d)
1440                         {
1441                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1442                         }
1443                 }
1444                 unit->t2d = 0;
1445                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1446         }
1447         // update 3d texture binding
1448         if (unit->t3d)
1449         {
1450                 GL_ActiveTexture(unitnum);
1451                 if (unitnum < backendunits)
1452                 {
1453                         if (unit->t3d)
1454                         {
1455                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1456                         }
1457                 }
1458                 unit->t3d = 0;
1459                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1460         }
1461         // update cubemap texture binding
1462         if (unit->tcubemap)
1463         {
1464                 GL_ActiveTexture(unitnum);
1465                 if (unitnum < backendunits)
1466                 {
1467                         if (unit->tcubemap)
1468                         {
1469                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1470                         }
1471                 }
1472                 unit->tcubemap = 0;
1473                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1474         }
1475 }
1476
1477 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1478 {
1479         gltextureunit_t *unit = gl_state.units + unitnum;
1480         if (unitnum >= backendimageunits)
1481                 return;
1482         // update 1d texture binding
1483         if (unit->t1d)
1484         {
1485                 GL_ActiveTexture(unitnum);
1486                 if (unitnum < backendunits)
1487                 {
1488                         if (unit->t1d)
1489                         {
1490                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1491                         }
1492                 }
1493                 unit->t1d = 0;
1494                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1495         }
1496         // update 2d texture binding
1497         if (unit->t2d != texnum)
1498         {
1499                 GL_ActiveTexture(unitnum);
1500                 if (unitnum < backendunits)
1501                 {
1502                         if (texnum)
1503                         {
1504                                 if (unit->t2d == 0)
1505                                 {
1506                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1507                                 }
1508                         }
1509                         else
1510                         {
1511                                 if (unit->t2d)
1512                                 {
1513                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1514                                 }
1515                         }
1516                 }
1517                 unit->t2d = texnum;
1518                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1519         }
1520         // update 3d texture binding
1521         if (unit->t3d)
1522         {
1523                 GL_ActiveTexture(unitnum);
1524                 if (unitnum < backendunits)
1525                 {
1526                         if (unit->t3d)
1527                         {
1528                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1529                         }
1530                 }
1531                 unit->t3d = 0;
1532                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1533         }
1534         // update cubemap texture binding
1535         if (unit->tcubemap != 0)
1536         {
1537                 GL_ActiveTexture(unitnum);
1538                 if (unitnum < backendunits)
1539                 {
1540                         if (unit->tcubemap)
1541                         {
1542                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1543                         }
1544                 }
1545                 unit->tcubemap = 0;
1546                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1547         }
1548 }
1549
1550 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1551 {
1552         gltextureunit_t *unit = gl_state.units + unitnum;
1553         if (unitnum >= backendimageunits)
1554                 return;
1555         // update 1d texture binding
1556         if (unit->t1d)
1557         {
1558                 GL_ActiveTexture(unitnum);
1559                 if (unitnum < backendunits)
1560                 {
1561                         if (unit->t1d)
1562                         {
1563                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1564                         }
1565                 }
1566                 unit->t1d = 0;
1567                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1568         }
1569         // update 2d texture binding
1570         if (unit->t2d)
1571         {
1572                 GL_ActiveTexture(unitnum);
1573                 if (unitnum < backendunits)
1574                 {
1575                         if (unit->t2d)
1576                         {
1577                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1578                         }
1579                 }
1580                 unit->t2d = 0;
1581                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1582         }
1583         // update 3d texture binding
1584         if (unit->t3d != texnum)
1585         {
1586                 GL_ActiveTexture(unitnum);
1587                 if (unitnum < backendunits)
1588                 {
1589                         if (texnum)
1590                         {
1591                                 if (unit->t3d == 0)
1592                                 {
1593                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1594                                 }
1595                         }
1596                         else
1597                         {
1598                                 if (unit->t3d)
1599                                 {
1600                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1601                                 }
1602                         }
1603                 }
1604                 unit->t3d = texnum;
1605                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1606         }
1607         // update cubemap texture binding
1608         if (unit->tcubemap != 0)
1609         {
1610                 GL_ActiveTexture(unitnum);
1611                 if (unitnum < backendunits)
1612                 {
1613                         if (unit->tcubemap)
1614                         {
1615                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1616                         }
1617                 }
1618                 unit->tcubemap = 0;
1619                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1620         }
1621 }
1622
1623 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1624 {
1625         gltextureunit_t *unit = gl_state.units + unitnum;
1626         if (unitnum >= backendimageunits)
1627                 return;
1628         // update 1d texture binding
1629         if (unit->t1d)
1630         {
1631                 GL_ActiveTexture(unitnum);
1632                 if (unitnum < backendunits)
1633                 {
1634                         if (unit->t1d)
1635                         {
1636                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1637                         }
1638                 }
1639                 unit->t1d = 0;
1640                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1641         }
1642         // update 2d texture binding
1643         if (unit->t2d)
1644         {
1645                 GL_ActiveTexture(unitnum);
1646                 if (unitnum < backendunits)
1647                 {
1648                         if (unit->t2d)
1649                         {
1650                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1651                         }
1652                 }
1653                 unit->t2d = 0;
1654                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1655         }
1656         // update 3d texture binding
1657         if (unit->t3d)
1658         {
1659                 GL_ActiveTexture(unitnum);
1660                 if (unitnum < backendunits)
1661                 {
1662                         if (unit->t3d)
1663                         {
1664                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1665                         }
1666                 }
1667                 unit->t3d = 0;
1668                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1669         }
1670         // update cubemap texture binding
1671         if (unit->tcubemap != texnum)
1672         {
1673                 GL_ActiveTexture(unitnum);
1674                 if (unitnum < backendunits)
1675                 {
1676                         if (texnum)
1677                         {
1678                                 if (unit->tcubemap == 0)
1679                                 {
1680                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1681                                 }
1682                         }
1683                         else
1684                         {
1685                                 if (unit->tcubemap)
1686                                 {
1687                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1688                                 }
1689                         }
1690                 }
1691                 unit->tcubemap = texnum;
1692                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1693         }
1694 }
1695
1696 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1697 {
1698         gltextureunit_t *unit = gl_state.units + unitnum;
1699         if (matrix->m[3][3])
1700         {
1701                 // texmatrix specified, check if it is different
1702                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1703                 {
1704                         double glmatrix[16];
1705                         unit->texmatrixenabled = true;
1706                         unit->matrix = *matrix;
1707                         CHECKGLERROR
1708                         Matrix4x4_ToArrayDoubleGL(&unit->matrix, glmatrix);
1709                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1710                         GL_ActiveTexture(unitnum);
1711                         qglLoadMatrixd(glmatrix);CHECKGLERROR
1712                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1713                 }
1714         }
1715         else
1716         {
1717                 // no texmatrix specified, revert to identity
1718                 if (unit->texmatrixenabled)
1719                 {
1720                         unit->texmatrixenabled = false;
1721                         CHECKGLERROR
1722                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1723                         GL_ActiveTexture(unitnum);
1724                         qglLoadIdentity();CHECKGLERROR
1725                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1726                 }
1727         }
1728 }
1729
1730 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1731 {
1732         gltextureunit_t *unit = gl_state.units + unitnum;
1733         CHECKGLERROR
1734         if (gl_combine.integer)
1735         {
1736                 // GL_ARB_texture_env_combine
1737                 if (!combinergb)
1738                         combinergb = GL_MODULATE;
1739                 if (!combinealpha)
1740                         combinealpha = GL_MODULATE;
1741                 if (!rgbscale)
1742                         rgbscale = 1;
1743                 if (!alphascale)
1744                         alphascale = 1;
1745                 if (unit->combinergb != combinergb)
1746                 {
1747                         unit->combinergb = combinergb;
1748                         GL_ActiveTexture(unitnum);
1749                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1750                 }
1751                 if (unit->combinealpha != combinealpha)
1752                 {
1753                         unit->combinealpha = combinealpha;
1754                         GL_ActiveTexture(unitnum);
1755                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1756                 }
1757                 if (unit->rgbscale != rgbscale)
1758                 {
1759                         GL_ActiveTexture(unitnum);
1760                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
1761                 }
1762                 if (unit->alphascale != alphascale)
1763                 {
1764                         GL_ActiveTexture(unitnum);
1765                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
1766                 }
1767         }
1768         else
1769         {
1770                 // normal GL texenv
1771                 if (!combinergb)
1772                         combinergb = GL_MODULATE;
1773                 if (unit->combinergb != combinergb)
1774                 {
1775                         unit->combinergb = combinergb;
1776                         GL_ActiveTexture(unitnum);
1777                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1778                 }
1779         }
1780 }
1781
1782 void R_Mesh_TextureState(const rmeshstate_t *m)
1783 {
1784         unsigned int i;
1785
1786         BACKENDACTIVECHECK
1787
1788         CHECKGLERROR
1789         if (gl_backend_rebindtextures)
1790         {
1791                 gl_backend_rebindtextures = false;
1792                 GL_SetupTextureState();
1793                 CHECKGLERROR
1794         }
1795
1796         for (i = 0;i < backendimageunits;i++)
1797                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
1798         for (i = 0;i < backendarrayunits;i++)
1799         {
1800                 if (m->pointer_texcoord3f[i])
1801                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
1802                 else
1803                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
1804         }
1805         for (i = 0;i < backendunits;i++)
1806         {
1807                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
1808                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
1809         }
1810         CHECKGLERROR
1811 }
1812
1813 void R_Mesh_ResetTextureState(void)
1814 {
1815         unsigned int unitnum;
1816
1817         BACKENDACTIVECHECK
1818
1819         CHECKGLERROR
1820         if (gl_backend_rebindtextures)
1821         {
1822                 gl_backend_rebindtextures = false;
1823                 GL_SetupTextureState();
1824                 CHECKGLERROR
1825         }
1826
1827         for (unitnum = 0;unitnum < backendimageunits;unitnum++)
1828         {
1829                 gltextureunit_t *unit = gl_state.units + unitnum;
1830                 // update 1d texture binding
1831                 if (unit->t1d)
1832                 {
1833                         GL_ActiveTexture(unitnum);
1834                         if (unitnum < backendunits)
1835                         {
1836                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1837                         }
1838                         unit->t1d = 0;
1839                         qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1840                 }
1841                 // update 2d texture binding
1842                 if (unit->t2d)
1843                 {
1844                         GL_ActiveTexture(unitnum);
1845                         if (unitnum < backendunits)
1846                         {
1847                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1848                         }
1849                         unit->t2d = 0;
1850                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1851                 }
1852                 // update 3d texture binding
1853                 if (unit->t3d)
1854                 {
1855                         GL_ActiveTexture(unitnum);
1856                         if (unitnum < backendunits)
1857                         {
1858                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1859                         }
1860                         unit->t3d = 0;
1861                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1862                 }
1863                 // update cubemap texture binding
1864                 if (unit->tcubemap)
1865                 {
1866                         GL_ActiveTexture(unitnum);
1867                         if (unitnum < backendunits)
1868                         {
1869                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1870                         }
1871                         unit->tcubemap = 0;
1872                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1873                 }
1874         }
1875         for (unitnum = 0;unitnum < backendarrayunits;unitnum++)
1876         {
1877                 gltextureunit_t *unit = gl_state.units + unitnum;
1878                 // texture array unit is disabled, disable the array
1879                 if (unit->arrayenabled)
1880                 {
1881                         unit->arrayenabled = false;
1882                         GL_ClientActiveTexture(unitnum);
1883                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1884                 }
1885         }
1886         for (unitnum = 0;unitnum < backendunits;unitnum++)
1887         {
1888                 gltextureunit_t *unit = gl_state.units + unitnum;
1889                 // no texmatrix specified, revert to identity
1890                 if (unit->texmatrixenabled)
1891                 {
1892                         unit->texmatrixenabled = false;
1893                         CHECKGLERROR
1894                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1895                         GL_ActiveTexture(unitnum);
1896                         qglLoadIdentity();CHECKGLERROR
1897                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1898                 }
1899                 if (gl_combine.integer)
1900                 {
1901                         // GL_ARB_texture_env_combine
1902                         if (unit->combinergb != GL_MODULATE)
1903                         {
1904                                 unit->combinergb = GL_MODULATE;
1905                                 GL_ActiveTexture(unitnum);
1906                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1907                         }
1908                         if (unit->combinealpha != GL_MODULATE)
1909                         {
1910                                 unit->combinealpha = GL_MODULATE;
1911                                 GL_ActiveTexture(unitnum);
1912                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1913                         }
1914                         if (unit->rgbscale != 1)
1915                         {
1916                                 GL_ActiveTexture(unitnum);
1917                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = 1));CHECKGLERROR
1918                         }
1919                         if (unit->alphascale != 1)
1920                         {
1921                                 GL_ActiveTexture(unitnum);
1922                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = 1));CHECKGLERROR
1923                         }
1924                 }
1925                 else
1926                 {
1927                         // normal GL texenv
1928                         if (unit->combinergb != GL_MODULATE)
1929                         {
1930                                 unit->combinergb = GL_MODULATE;
1931                                 GL_ActiveTexture(unitnum);
1932                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1933                         }
1934                 }
1935         }
1936 }
1937
1938 void R_Mesh_Draw_ShowTris(int firstvertex, int numvertices, int numtriangles, const int *elements)
1939 {
1940         CHECKGLERROR
1941         qglBegin(GL_LINES);
1942         for (;numtriangles;numtriangles--, elements += 3)
1943         {
1944                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1945                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1946                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1947         }
1948         qglEnd();
1949         CHECKGLERROR
1950 }