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