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