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