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