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