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