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