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