added polygonoffset as a texture property, used on submodels (such as
[xonotic/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4
5 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
6 cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0", "use glBegin(GL_TRIANGLES);glArrayElement();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
7 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
8 cvar_t gl_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 = {0, "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\n");
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_Simple(&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         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
303 }
304
305 void GL_SetupView_Mode_Perspective (double frustumx, double frustumy, double zNear, double zFar)
306 {
307         double m[16];
308
309         // set up viewpoint
310         CHECKGLERROR
311         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
312         qglLoadIdentity();CHECKGLERROR
313         // set view pyramid
314         qglFrustum(-frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);CHECKGLERROR
315         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
316         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
317         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
318         GL_SetupView_Orientation_Identity();
319         CHECKGLERROR
320 }
321
322 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double frustumx, double frustumy, double zNear)
323 {
324         double nudge, m[16];
325
326         // set up viewpoint
327         CHECKGLERROR
328         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
329         qglLoadIdentity();CHECKGLERROR
330         // set view pyramid
331         nudge = 1.0 - 1.0 / (1<<23);
332         m[ 0] = 1.0 / frustumx;
333         m[ 1] = 0;
334         m[ 2] = 0;
335         m[ 3] = 0;
336         m[ 4] = 0;
337         m[ 5] = 1.0 / frustumy;
338         m[ 6] = 0;
339         m[ 7] = 0;
340         m[ 8] = 0;
341         m[ 9] = 0;
342         m[10] = -nudge;
343         m[11] = -1;
344         m[12] = 0;
345         m[13] = 0;
346         m[14] = -2 * zNear * nudge;
347         m[15] = 0;
348         qglLoadMatrixd(m);CHECKGLERROR
349         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
350         GL_SetupView_Orientation_Identity();
351         CHECKGLERROR
352         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
353 }
354
355 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
356 {
357         double m[16];
358
359         // set up viewpoint
360         CHECKGLERROR
361         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
362         qglLoadIdentity();CHECKGLERROR
363         qglOrtho(x1, x2, y2, y1, zNear, zFar);CHECKGLERROR
364         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
365         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
366         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
367         GL_SetupView_Orientation_Identity();
368         CHECKGLERROR
369 }
370
371 typedef struct gltextureunit_s
372 {
373         const void *pointer_texcoord;
374         size_t pointer_texcoord_offset;
375         int pointer_texcoord_buffer;
376         int t1d, t2d, t3d, tcubemap;
377         int arrayenabled;
378         unsigned int arraycomponents;
379         int rgbscale, alphascale;
380         int combinergb, combinealpha;
381         // FIXME: add more combine stuff
382         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
383         int texmatrixenabled;
384         matrix4x4_t matrix;
385 }
386 gltextureunit_t;
387
388 static struct gl_state_s
389 {
390         int cullface;
391         int cullfaceenable;
392         int blendfunc1;
393         int blendfunc2;
394         int blend;
395         GLboolean depthmask;
396         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
397         int depthtest;
398         float depthrange[2];
399         float polygonoffset[2];
400         int alphatest;
401         int scissortest;
402         unsigned int unit;
403         unsigned int clientunit;
404         gltextureunit_t units[MAX_TEXTUREUNITS];
405         float color4f[4];
406         int lockrange_first;
407         int lockrange_count;
408         int vertexbufferobject;
409         int elementbufferobject;
410         qboolean pointer_color_enabled;
411         const void *pointer_vertex;
412         const void *pointer_color;
413         size_t pointer_vertex_offset;
414         size_t pointer_color_offset;
415         int pointer_vertex_buffer;
416         int pointer_color_buffer;
417 }
418 gl_state;
419
420 static void GL_BindVBO(int bufferobject)
421 {
422         if (gl_state.vertexbufferobject != bufferobject)
423         {
424                 gl_state.vertexbufferobject = bufferobject;
425                 CHECKGLERROR
426                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);
427                 CHECKGLERROR
428         }
429 }
430
431 static void GL_BindEBO(int bufferobject)
432 {
433         if (gl_state.elementbufferobject != bufferobject)
434         {
435                 gl_state.elementbufferobject = bufferobject;
436                 CHECKGLERROR
437                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);
438                 CHECKGLERROR
439         }
440 }
441
442 void GL_SetupTextureState(void)
443 {
444         unsigned int i;
445         gltextureunit_t *unit;
446         CHECKGLERROR
447         gl_state.unit = MAX_TEXTUREUNITS;
448         gl_state.clientunit = MAX_TEXTUREUNITS;
449         for (i = 0;i < MAX_TEXTUREUNITS;i++)
450         {
451                 unit = gl_state.units + i;
452                 unit->t1d = 0;
453                 unit->t2d = 0;
454                 unit->t3d = 0;
455                 unit->tcubemap = 0;
456                 unit->arrayenabled = false;
457                 unit->arraycomponents = 0;
458                 unit->pointer_texcoord = NULL;
459                 unit->pointer_texcoord_buffer = 0;
460                 unit->pointer_texcoord_offset = 0;
461                 unit->rgbscale = 1;
462                 unit->alphascale = 1;
463                 unit->combinergb = GL_MODULATE;
464                 unit->combinealpha = GL_MODULATE;
465                 unit->texmatrixenabled = false;
466                 unit->matrix = identitymatrix;
467         }
468
469         for (i = 0;i < backendimageunits;i++)
470         {
471                 GL_ActiveTexture(i);
472                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
473                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
474                 if (gl_texture3d)
475                 {
476                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
477                 }
478                 if (gl_texturecubemap)
479                 {
480                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
481                 }
482         }
483
484         for (i = 0;i < backendarrayunits;i++)
485         {
486                 GL_ClientActiveTexture(i);
487                 GL_BindVBO(0);
488                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
489                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
490         }
491
492         for (i = 0;i < backendunits;i++)
493         {
494                 GL_ActiveTexture(i);
495                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
496                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
497                 if (gl_texture3d)
498                 {
499                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
500                 }
501                 if (gl_texturecubemap)
502                 {
503                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
504                 }
505                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
506                 qglLoadIdentity();CHECKGLERROR
507                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
508                 if (gl_combine.integer)
509                 {
510                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
511                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
512                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
513                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
514                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
515                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
516                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
517                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
518                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
519                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
520                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
521                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
522                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
523                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
524                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
525                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
526                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
527                 }
528                 else
529                 {
530                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
531                 }
532                 CHECKGLERROR
533         }
534         CHECKGLERROR
535 }
536
537 void GL_Backend_ResetState(void)
538 {
539         memset(&gl_state, 0, sizeof(gl_state));
540         gl_state.depthtest = true;
541         gl_state.alphatest = false;
542         gl_state.blendfunc1 = GL_ONE;
543         gl_state.blendfunc2 = GL_ZERO;
544         gl_state.blend = false;
545         gl_state.depthmask = GL_TRUE;
546         gl_state.colormask = 15;
547         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
548         gl_state.lockrange_first = 0;
549         gl_state.lockrange_count = 0;
550         gl_state.cullface = v_flipped_state ? GL_BACK : GL_FRONT; // quake is backwards, this culls back faces
551         gl_state.cullfaceenable = true;
552         gl_state.polygonoffset[0] = 0;
553         gl_state.polygonoffset[1] = 0;
554
555         CHECKGLERROR
556
557         qglColorMask(1, 1, 1, 1);
558         qglAlphaFunc(GL_GEQUAL, 0.5);CHECKGLERROR
559         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
560         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
561         qglDisable(GL_BLEND);CHECKGLERROR
562         qglCullFace(gl_state.cullface);CHECKGLERROR
563         qglEnable(GL_CULL_FACE);CHECKGLERROR
564         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
565         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
566         qglDepthMask(gl_state.depthmask);CHECKGLERROR
567         qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
568
569         if (gl_support_arb_vertex_buffer_object)
570         {
571                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
572                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
573         }
574
575         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
576         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
577
578         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
579         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
580
581         GL_Color(0, 0, 0, 0);
582         GL_Color(1, 1, 1, 1);
583
584         GL_SetupTextureState();
585 }
586
587 void GL_ActiveTexture(unsigned int num)
588 {
589         if (gl_state.unit != num)
590         {
591                 gl_state.unit = num;
592                 if (qglActiveTexture)
593                 {
594                         CHECKGLERROR
595                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
596                         CHECKGLERROR
597                 }
598         }
599 }
600
601 void GL_ClientActiveTexture(unsigned int num)
602 {
603         if (gl_state.clientunit != num)
604         {
605                 gl_state.clientunit = num;
606                 if (qglActiveTexture)
607                 {
608                         CHECKGLERROR
609                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
610                         CHECKGLERROR
611                 }
612         }
613 }
614
615 void GL_BlendFunc(int blendfunc1, int blendfunc2)
616 {
617         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
618         {
619                 CHECKGLERROR
620                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
621                 if (gl_state.blendfunc2 == GL_ZERO)
622                 {
623                         if (gl_state.blendfunc1 == GL_ONE)
624                         {
625                                 if (gl_state.blend)
626                                 {
627                                         gl_state.blend = 0;
628                                         qglDisable(GL_BLEND);CHECKGLERROR
629                                 }
630                         }
631                         else
632                         {
633                                 if (!gl_state.blend)
634                                 {
635                                         gl_state.blend = 1;
636                                         qglEnable(GL_BLEND);CHECKGLERROR
637                                 }
638                         }
639                 }
640                 else
641                 {
642                         if (!gl_state.blend)
643                         {
644                                 gl_state.blend = 1;
645                                 qglEnable(GL_BLEND);CHECKGLERROR
646                         }
647                 }
648         }
649 }
650
651 void GL_DepthMask(int state)
652 {
653         if (gl_state.depthmask != state)
654         {
655                 CHECKGLERROR
656                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
657         }
658 }
659
660 void GL_DepthTest(int state)
661 {
662         if (gl_state.depthtest != state)
663         {
664                 gl_state.depthtest = state;
665                 CHECKGLERROR
666                 if (gl_state.depthtest)
667                 {
668                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
669                 }
670                 else
671                 {
672                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
673                 }
674         }
675 }
676
677 void GL_DepthRange(float nearfrac, float farfrac)
678 {
679         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
680         {
681                 gl_state.depthrange[0] = nearfrac;
682                 gl_state.depthrange[1] = farfrac;
683                 qglDepthRange(nearfrac, farfrac);
684         }
685 }
686
687 void GL_PolygonOffset(float planeoffset, float depthoffset)
688 {
689         if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset)
690         {
691                 gl_state.polygonoffset[0] = planeoffset;
692                 gl_state.polygonoffset[1] = depthoffset;
693                 qglPolygonOffset(planeoffset, depthoffset);
694         }
695 }
696
697 void GL_SetMirrorState(qboolean state)
698 {
699         if(!state != !v_flipped_state)
700         {
701                 // change cull face mode!
702                 if(gl_state.cullface == GL_BACK)
703                         qglCullFace((gl_state.cullface = GL_FRONT));
704                 else if(gl_state.cullface == GL_FRONT)
705                         qglCullFace((gl_state.cullface = GL_BACK));
706         }
707         v_flipped_state = state;
708 }
709
710 void GL_CullFace(int state)
711 {
712         CHECKGLERROR
713
714         if(v_flipped_state)
715         {
716                 if(state == GL_FRONT)
717                         state = GL_BACK;
718                 else if(state == GL_BACK)
719                         state = GL_FRONT;
720         }
721
722         if (state != GL_NONE)
723         {
724                 if (!gl_state.cullfaceenable)
725                 {
726                         gl_state.cullfaceenable = true;
727                         qglEnable(GL_CULL_FACE);CHECKGLERROR
728                 }
729                 if (gl_state.cullface != state)
730                 {
731                         gl_state.cullface = state;
732                         qglCullFace(gl_state.cullface);CHECKGLERROR
733                 }
734         }
735         else
736         {
737                 if (gl_state.cullfaceenable)
738                 {
739                         gl_state.cullfaceenable = false;
740                         qglDisable(GL_CULL_FACE);CHECKGLERROR
741                 }
742         }
743 }
744
745 void GL_AlphaTest(int state)
746 {
747         if (gl_state.alphatest != state)
748         {
749                 gl_state.alphatest = state;
750                 CHECKGLERROR
751                 if (gl_state.alphatest)
752                 {
753                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
754                 }
755                 else
756                 {
757                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
758                 }
759         }
760 }
761
762 void GL_ColorMask(int r, int g, int b, int a)
763 {
764         int state = r*8 + g*4 + b*2 + a*1;
765         if (gl_state.colormask != state)
766         {
767                 gl_state.colormask = state;
768                 CHECKGLERROR
769                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
770         }
771 }
772
773 void GL_Color(float cr, float cg, float cb, float ca)
774 {
775         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)
776         {
777                 gl_state.color4f[0] = cr;
778                 gl_state.color4f[1] = cg;
779                 gl_state.color4f[2] = cb;
780                 gl_state.color4f[3] = ca;
781                 CHECKGLERROR
782                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
783                 CHECKGLERROR
784         }
785 }
786
787 void GL_LockArrays(int first, int count)
788 {
789         if (count < gl_lockarrays_minimumvertices.integer)
790         {
791                 first = 0;
792                 count = 0;
793         }
794         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
795         {
796                 if (gl_state.lockrange_count)
797                 {
798                         gl_state.lockrange_count = 0;
799                         CHECKGLERROR
800                         qglUnlockArraysEXT();
801                         CHECKGLERROR
802                 }
803                 if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
804                 {
805                         gl_state.lockrange_first = first;
806                         gl_state.lockrange_count = count;
807                         CHECKGLERROR
808                         qglLockArraysEXT(first, count);
809                         CHECKGLERROR
810                 }
811         }
812 }
813
814 void GL_Scissor (int x, int y, int width, int height)
815 {
816         CHECKGLERROR
817         qglScissor(x, vid.height - (y + height),width,height);
818         CHECKGLERROR
819 }
820
821 void GL_ScissorTest(int state)
822 {
823         if(gl_state.scissortest == state)
824                 return;
825
826         CHECKGLERROR
827         if((gl_state.scissortest = state))
828                 qglEnable(GL_SCISSOR_TEST);
829         else
830                 qglDisable(GL_SCISSOR_TEST);
831         CHECKGLERROR
832 }
833
834 void GL_Clear(int mask)
835 {
836         CHECKGLERROR
837         qglClear(mask);CHECKGLERROR
838 }
839
840 void GL_TransformToScreen(const vec4_t in, vec4_t out)
841 {
842         vec4_t temp;
843         float iw;
844         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
845         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
846         iw = 1.0f / out[3];
847         out[0] = r_view.x + (out[0] * iw + 1.0f) * r_view.width * 0.5f;
848         out[1] = r_view.y + r_view.height - (out[1] * iw + 1.0f) * r_view.height * 0.5f;
849         out[2] = r_view.z + (out[2] * iw + 1.0f) * r_view.depth * 0.5f;
850 }
851
852 // called at beginning of frame
853 void R_Mesh_Start(void)
854 {
855         BACKENDACTIVECHECK
856         CHECKGLERROR
857         if (gl_printcheckerror.integer && !gl_paranoid.integer)
858         {
859                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
860                 Cvar_SetValueQuick(&gl_paranoid, 1);
861         }
862         GL_Backend_ResetState();
863 }
864
865 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
866 {
867         int shaderobject;
868         int shadercompiled;
869         char compilelog[MAX_INPUTLINE];
870         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
871         if (!shaderobject)
872                 return false;
873         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
874         qglCompileShaderARB(shaderobject);CHECKGLERROR
875         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
876         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
877         if (compilelog[0])
878                 Con_DPrintf("%s shader compile log:\n%s\n", shadertype, compilelog);
879         if (!shadercompiled)
880         {
881                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
882                 return false;
883         }
884         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
885         qglDeleteObjectARB(shaderobject);CHECKGLERROR
886         return true;
887 }
888
889 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)
890 {
891         GLint programlinked;
892         GLuint programobject = 0;
893         char linklog[MAX_INPUTLINE];
894         CHECKGLERROR
895
896         programobject = qglCreateProgramObjectARB();CHECKGLERROR
897         if (!programobject)
898                 return 0;
899
900         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
901                 goto cleanup;
902
903 #ifdef GL_GEOMETRY_SHADER_ARB
904         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
905                 goto cleanup;
906 #endif
907
908         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
909                 goto cleanup;
910
911         qglLinkProgramARB(programobject);CHECKGLERROR
912         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
913         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
914         if (linklog[0])
915         {
916                 Con_DPrintf("program link log:\n%s\n", linklog);
917                 // software vertex shader is ok but software fragment shader is WAY
918                 // too slow, fail program if so.
919                 // NOTE: this string might be ATI specific, but that's ok because the
920                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
921                 // software fragment shader due to low instruction and dependent
922                 // texture limits.
923                 if (strstr(linklog, "fragment shader will run in software"))
924                         programlinked = false;
925         }
926         if (!programlinked)
927                 goto cleanup;
928         return programobject;
929 cleanup:
930         qglDeleteObjectARB(programobject);CHECKGLERROR
931         return 0;
932 }
933
934 void GL_Backend_FreeProgram(unsigned int prog)
935 {
936         CHECKGLERROR
937         qglDeleteObjectARB(prog);
938         CHECKGLERROR
939 }
940
941 int gl_backend_rebindtextures;
942
943 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
944 {
945         int i;
946         if (offset)
947         {
948                 for (i = 0;i < count;i++)
949                         *out++ = *in++ + offset;
950         }
951         else
952                 memcpy(out, in, sizeof(*out) * count);
953 }
954
955 // renders triangles using vertices from the active arrays
956 int paranoidblah = 0;
957 void R_Mesh_Draw(int firstvertex, int numvertices, int numtriangles, const int *elements, int bufferobject, size_t bufferoffset)
958 {
959         unsigned int numelements = numtriangles * 3;
960         if (numvertices < 3 || numtriangles < 1)
961         {
962                 Con_Printf("R_Mesh_Draw(%d, %d, %d, %8p, %i, %p);\n", firstvertex, numvertices, numtriangles, elements, bufferobject, (void *)bufferoffset);
963                 return;
964         }
965         if (!gl_vbo.integer)
966                 bufferobject = 0;
967         CHECKGLERROR
968         r_refdef.stats.meshes++;
969         r_refdef.stats.meshes_elements += numelements;
970         if (gl_paranoid.integer)
971         {
972                 unsigned int i, j, size;
973                 const int *p;
974                 // note: there's no validation done here on buffer objects because it
975                 // is somewhat difficult to get at the data, and gl_paranoid can be
976                 // used without buffer objects if the need arises
977                 // (the data could be gotten using glMapBuffer but it would be very
978                 //  slow due to uncachable video memory reads)
979                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
980                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
981                 CHECKGLERROR
982                 if (gl_state.pointer_vertex)
983                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
984                                 paranoidblah += *p;
985                 if (gl_state.pointer_color_enabled)
986                 {
987                         if (!qglIsEnabled(GL_COLOR_ARRAY))
988                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
989                         CHECKGLERROR
990                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
991                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
992                                         paranoidblah += *p;
993                 }
994                 for (i = 0;i < backendarrayunits;i++)
995                 {
996                         if (gl_state.units[i].arrayenabled)
997                         {
998                                 GL_ClientActiveTexture(i);
999                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
1000                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
1001                                 CHECKGLERROR
1002                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
1003                                         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++)
1004                                                 paranoidblah += *p;
1005                         }
1006                 }
1007                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1008                 {
1009                         if (elements[i] < firstvertex || elements[i] >= firstvertex + numvertices)
1010                         {
1011                                 Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in elements list\n", elements[i], firstvertex, firstvertex + numvertices);
1012                                 return;
1013                         }
1014                 }
1015                 CHECKGLERROR
1016         }
1017         if (r_render.integer)
1018         {
1019                 CHECKGLERROR
1020                 if (gl_mesh_testmanualfeeding.integer)
1021                 {
1022                         unsigned int i, j;
1023                         const GLfloat *p;
1024                         qglBegin(GL_TRIANGLES);
1025                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1026                         {
1027                                 for (j = 0;j < backendarrayunits;j++)
1028                                 {
1029                                         if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled)
1030                                         {
1031                                                 if (backendarrayunits > 1)
1032                                                 {
1033                                                         if (gl_state.units[j].arraycomponents == 4)
1034                                                         {
1035                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
1036                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
1037                                                         }
1038                                                         else if (gl_state.units[j].arraycomponents == 3)
1039                                                         {
1040                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
1041                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
1042                                                         }
1043                                                         else if (gl_state.units[j].arraycomponents == 2)
1044                                                         {
1045                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
1046                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
1047                                                         }
1048                                                         else
1049                                                         {
1050                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
1051                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
1052                                                         }
1053                                                 }
1054                                                 else
1055                                                 {
1056                                                         if (gl_state.units[j].arraycomponents == 4)
1057                                                         {
1058                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
1059                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
1060                                                         }
1061                                                         else if (gl_state.units[j].arraycomponents == 3)
1062                                                         {
1063                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
1064                                                                 qglTexCoord3f(p[0], p[1], p[2]);
1065                                                         }
1066                                                         else if (gl_state.units[j].arraycomponents == 2)
1067                                                         {
1068                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
1069                                                                 qglTexCoord2f(p[0], p[1]);
1070                                                         }
1071                                                         else
1072                                                         {
1073                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
1074                                                                 qglTexCoord1f(p[0]);
1075                                                         }
1076                                                 }
1077                                         }
1078                                 }
1079                                 if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1080                                 {
1081                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
1082                                         qglColor4f(p[0], p[1], p[2], p[3]);
1083                                 }
1084                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
1085                                 qglVertex3f(p[0], p[1], p[2]);
1086                         }
1087                         qglEnd();
1088                         CHECKGLERROR
1089                 }
1090                 else if (gl_mesh_testarrayelement.integer)
1091                 {
1092                         int i;
1093                         qglBegin(GL_TRIANGLES);
1094                         for (i = 0;i < numtriangles * 3;i++)
1095                         {
1096                                 qglArrayElement(elements[i]);
1097                         }
1098                         qglEnd();
1099                         CHECKGLERROR
1100                 }
1101                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1102                 {
1103                         GL_BindEBO(bufferobject);
1104                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, bufferobject ? (void *)bufferoffset : elements);
1105                         CHECKGLERROR
1106                 }
1107                 else
1108                 {
1109                         GL_BindEBO(bufferobject);
1110                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, bufferobject ? (void *)bufferoffset : elements);
1111                         CHECKGLERROR
1112                 }
1113         }
1114 }
1115
1116 // restores backend state, used when done with 3D rendering
1117 void R_Mesh_Finish(void)
1118 {
1119         unsigned int i;
1120         BACKENDACTIVECHECK
1121         CHECKGLERROR
1122         GL_LockArrays(0, 0);
1123         CHECKGLERROR
1124
1125         for (i = 0;i < backendimageunits;i++)
1126         {
1127                 GL_ActiveTexture(i);
1128                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
1129                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1130                 if (gl_texture3d)
1131                 {
1132                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1133                 }
1134                 if (gl_texturecubemap)
1135                 {
1136                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1137                 }
1138         }
1139         for (i = 0;i < backendarrayunits;i++)
1140         {
1141                 GL_ActiveTexture(backendarrayunits - 1 - i);
1142                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1143         }
1144         for (i = 0;i < backendunits;i++)
1145         {
1146                 GL_ActiveTexture(backendunits - 1 - i);
1147                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1148                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1149                 if (gl_texture3d)
1150                 {
1151                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1152                 }
1153                 if (gl_texturecubemap)
1154                 {
1155                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1156                 }
1157                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1158                 if (gl_combine.integer)
1159                 {
1160                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1161                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1162                 }
1163         }
1164         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1165         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1166
1167         qglDisable(GL_BLEND);CHECKGLERROR
1168         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1169         qglDepthMask(GL_TRUE);CHECKGLERROR
1170         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1171 }
1172
1173 int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name)
1174 {
1175         gl_bufferobjectinfo_t *info;
1176         GLuint bufferobject;
1177
1178         if (!gl_vbo.integer)
1179                 return 0;
1180
1181         qglGenBuffersARB(1, &bufferobject);
1182         switch(target)
1183         {
1184         case GL_ELEMENT_ARRAY_BUFFER_ARB: GL_BindEBO(bufferobject);break;
1185         case GL_ARRAY_BUFFER_ARB: GL_BindVBO(bufferobject);break;
1186         default: Sys_Error("R_Mesh_CreateStaticBufferObject: unknown target type %i\n", target);return 0;
1187         }
1188         qglBufferDataARB(target, size, data, GL_STATIC_DRAW_ARB);
1189
1190         info = Mem_ExpandableArray_AllocRecord(&gl_bufferobjectinfoarray);
1191         memset(info, 0, sizeof(*info));
1192         info->target = target;
1193         info->object = bufferobject;
1194         info->size = size;
1195         strlcpy(info->name, name, sizeof(info->name));
1196
1197         return (int)bufferobject;
1198 }
1199
1200 void R_Mesh_DestroyBufferObject(int bufferobject)
1201 {
1202         int i, endindex;
1203         gl_bufferobjectinfo_t *info;
1204
1205         qglDeleteBuffersARB(1, (GLuint *)&bufferobject);
1206
1207         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1208         for (i = 0;i < endindex;i++)
1209         {
1210                 info = Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1211                 if (!info)
1212                         continue;
1213                 if (info->object == bufferobject)
1214                 {
1215                         Mem_ExpandableArray_FreeRecord(&gl_bufferobjectinfoarray, (void *)info);
1216                         break;
1217                 }
1218         }
1219 }
1220
1221 void GL_Mesh_ListVBOs(qboolean printeach)
1222 {
1223         int i, endindex;
1224         size_t ebocount = 0, ebomemory = 0;
1225         size_t vbocount = 0, vbomemory = 0;
1226         gl_bufferobjectinfo_t *info;
1227         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1228         for (i = 0;i < endindex;i++)
1229         {
1230                 info = Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1231                 if (!info)
1232                         continue;
1233                 switch(info->target)
1234                 {
1235                 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;
1236                 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;
1237                 default: Con_Printf("gl_vbostats: unknown target type %i\n", info->target);break;
1238                 }
1239         }
1240         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);
1241 }
1242
1243 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1244 {
1245         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1246         {
1247                 double glmatrix[16];
1248                 backend_modelmatrix = *matrix;
1249                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
1250                 Matrix4x4_ToArrayDoubleGL(&backend_modelviewmatrix, glmatrix);
1251                 CHECKGLERROR
1252                 qglLoadMatrixd(glmatrix);CHECKGLERROR
1253         }
1254 }
1255
1256 void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset)
1257 {
1258         if (!gl_vbo.integer)
1259                 bufferobject = 0;
1260         if (gl_state.pointer_vertex != vertex3f || gl_state.pointer_vertex_buffer != bufferobject || gl_state.pointer_vertex_offset != bufferoffset)
1261         {
1262                 gl_state.pointer_vertex = vertex3f;
1263                 gl_state.pointer_vertex_buffer = bufferobject;
1264                 gl_state.pointer_vertex_offset = bufferoffset;
1265                 CHECKGLERROR
1266                 GL_BindVBO(bufferobject);
1267                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), bufferobject ? (void *)bufferoffset : vertex3f);CHECKGLERROR
1268         }
1269 }
1270
1271 void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset)
1272 {
1273         // note: this can not rely on bufferobject to decide whether a color array
1274         // is supplied, because surfmesh_t shares one vbo for all arrays, which
1275         // means that a valid vbo may be supplied even if there is no color array.
1276         if (color4f)
1277         {
1278                 if (!gl_vbo.integer)
1279                         bufferobject = 0;
1280                 // caller wants color array enabled
1281                 if (!gl_state.pointer_color_enabled)
1282                 {
1283                         gl_state.pointer_color_enabled = true;
1284                         CHECKGLERROR
1285                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1286                 }
1287                 if (gl_state.pointer_color != color4f || gl_state.pointer_color_buffer != bufferobject || gl_state.pointer_color_offset != bufferoffset)
1288                 {
1289                         gl_state.pointer_color = color4f;
1290                         gl_state.pointer_color_buffer = bufferobject;
1291                         gl_state.pointer_color_offset = bufferoffset;
1292                         CHECKGLERROR
1293                         GL_BindVBO(bufferobject);
1294                         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), bufferobject ? (void *)bufferoffset : color4f);CHECKGLERROR
1295                 }
1296         }
1297         else
1298         {
1299                 // caller wants color array disabled
1300                 if (gl_state.pointer_color_enabled)
1301                 {
1302                         gl_state.pointer_color_enabled = false;
1303                         CHECKGLERROR
1304                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1305                         // when color array is on the glColor gets trashed, set it again
1306                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1307                 }
1308         }
1309 }
1310
1311 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset)
1312 {
1313         gltextureunit_t *unit = gl_state.units + unitnum;
1314         // update array settings
1315         CHECKGLERROR
1316         // note: there is no need to check bufferobject here because all cases
1317         // that involve a valid bufferobject also supply a texcoord array
1318         if (texcoord)
1319         {
1320                 if (!gl_vbo.integer)
1321                         bufferobject = 0;
1322                 // texture array unit is enabled, enable the array
1323                 if (!unit->arrayenabled)
1324                 {
1325                         unit->arrayenabled = true;
1326                         GL_ClientActiveTexture(unitnum);
1327                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1328                 }
1329                 // texcoord array
1330                 if (unit->pointer_texcoord != texcoord || unit->pointer_texcoord_buffer != bufferobject || unit->pointer_texcoord_offset != bufferoffset || unit->arraycomponents != numcomponents)
1331                 {
1332                         unit->pointer_texcoord = texcoord;
1333                         unit->pointer_texcoord_buffer = bufferobject;
1334                         unit->pointer_texcoord_offset = bufferoffset;
1335                         unit->arraycomponents = numcomponents;
1336                         GL_ClientActiveTexture(unitnum);
1337                         GL_BindVBO(bufferobject);
1338                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, bufferobject ? (void *)bufferoffset : texcoord);CHECKGLERROR
1339                 }
1340         }
1341         else
1342         {
1343                 // texture array unit is disabled, disable the array
1344                 if (unit->arrayenabled)
1345                 {
1346                         unit->arrayenabled = false;
1347                         GL_ClientActiveTexture(unitnum);
1348                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1349                 }
1350         }
1351 }
1352
1353 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
1354 {
1355         gltextureunit_t *unit = gl_state.units + unitnum;
1356         if (unitnum >= backendimageunits)
1357                 return;
1358         // update 1d texture binding
1359         if (unit->t1d != tex1d)
1360         {
1361                 GL_ActiveTexture(unitnum);
1362                 if (unitnum < backendunits)
1363                 {
1364                         if (tex1d)
1365                         {
1366                                 if (unit->t1d == 0)
1367                                 {
1368                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1369                                 }
1370                         }
1371                         else
1372                         {
1373                                 if (unit->t1d)
1374                                 {
1375                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1376                                 }
1377                         }
1378                 }
1379                 unit->t1d = tex1d;
1380                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1381         }
1382         // update 2d texture binding
1383         if (unit->t2d != tex2d)
1384         {
1385                 GL_ActiveTexture(unitnum);
1386                 if (unitnum < backendunits)
1387                 {
1388                         if (tex2d)
1389                         {
1390                                 if (unit->t2d == 0)
1391                                 {
1392                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1393                                 }
1394                         }
1395                         else
1396                         {
1397                                 if (unit->t2d)
1398                                 {
1399                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1400                                 }
1401                         }
1402                 }
1403                 unit->t2d = tex2d;
1404                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1405         }
1406         // update 3d texture binding
1407         if (unit->t3d != tex3d)
1408         {
1409                 GL_ActiveTexture(unitnum);
1410                 if (unitnum < backendunits)
1411                 {
1412                         if (tex3d)
1413                         {
1414                                 if (unit->t3d == 0)
1415                                 {
1416                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1417                                 }
1418                         }
1419                         else
1420                         {
1421                                 if (unit->t3d)
1422                                 {
1423                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1424                                 }
1425                         }
1426                 }
1427                 unit->t3d = tex3d;
1428                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1429         }
1430         // update cubemap texture binding
1431         if (unit->tcubemap != texcubemap)
1432         {
1433                 GL_ActiveTexture(unitnum);
1434                 if (unitnum < backendunits)
1435                 {
1436                         if (texcubemap)
1437                         {
1438                                 if (unit->tcubemap == 0)
1439                                 {
1440                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1441                                 }
1442                         }
1443                         else
1444                         {
1445                                 if (unit->tcubemap)
1446                                 {
1447                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1448                                 }
1449                         }
1450                 }
1451                 unit->tcubemap = texcubemap;
1452                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1453         }
1454 }
1455
1456 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1457 {
1458         gltextureunit_t *unit = gl_state.units + unitnum;
1459         if (unitnum >= backendimageunits)
1460                 return;
1461         // update 1d texture binding
1462         if (unit->t1d != texnum)
1463         {
1464                 GL_ActiveTexture(unitnum);
1465                 if (unitnum < backendunits)
1466                 {
1467                         if (texnum)
1468                         {
1469                                 if (unit->t1d == 0)
1470                                 {
1471                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1472                                 }
1473                         }
1474                         else
1475                         {
1476                                 if (unit->t1d)
1477                                 {
1478                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1479                                 }
1480                         }
1481                 }
1482                 unit->t1d = texnum;
1483                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1484         }
1485         // update 2d texture binding
1486         if (unit->t2d)
1487         {
1488                 GL_ActiveTexture(unitnum);
1489                 if (unitnum < backendunits)
1490                 {
1491                         if (unit->t2d)
1492                         {
1493                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1494                         }
1495                 }
1496                 unit->t2d = 0;
1497                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1498         }
1499         // update 3d texture binding
1500         if (unit->t3d)
1501         {
1502                 GL_ActiveTexture(unitnum);
1503                 if (unitnum < backendunits)
1504                 {
1505                         if (unit->t3d)
1506                         {
1507                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1508                         }
1509                 }
1510                 unit->t3d = 0;
1511                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1512         }
1513         // update cubemap texture binding
1514         if (unit->tcubemap)
1515         {
1516                 GL_ActiveTexture(unitnum);
1517                 if (unitnum < backendunits)
1518                 {
1519                         if (unit->tcubemap)
1520                         {
1521                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1522                         }
1523                 }
1524                 unit->tcubemap = 0;
1525                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1526         }
1527 }
1528
1529 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1530 {
1531         gltextureunit_t *unit = gl_state.units + unitnum;
1532         if (unitnum >= backendimageunits)
1533                 return;
1534         // update 1d texture binding
1535         if (unit->t1d)
1536         {
1537                 GL_ActiveTexture(unitnum);
1538                 if (unitnum < backendunits)
1539                 {
1540                         if (unit->t1d)
1541                         {
1542                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1543                         }
1544                 }
1545                 unit->t1d = 0;
1546                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1547         }
1548         // update 2d texture binding
1549         if (unit->t2d != texnum)
1550         {
1551                 GL_ActiveTexture(unitnum);
1552                 if (unitnum < backendunits)
1553                 {
1554                         if (texnum)
1555                         {
1556                                 if (unit->t2d == 0)
1557                                 {
1558                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1559                                 }
1560                         }
1561                         else
1562                         {
1563                                 if (unit->t2d)
1564                                 {
1565                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1566                                 }
1567                         }
1568                 }
1569                 unit->t2d = texnum;
1570                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1571         }
1572         // update 3d texture binding
1573         if (unit->t3d)
1574         {
1575                 GL_ActiveTexture(unitnum);
1576                 if (unitnum < backendunits)
1577                 {
1578                         if (unit->t3d)
1579                         {
1580                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1581                         }
1582                 }
1583                 unit->t3d = 0;
1584                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1585         }
1586         // update cubemap texture binding
1587         if (unit->tcubemap != 0)
1588         {
1589                 GL_ActiveTexture(unitnum);
1590                 if (unitnum < backendunits)
1591                 {
1592                         if (unit->tcubemap)
1593                         {
1594                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1595                         }
1596                 }
1597                 unit->tcubemap = 0;
1598                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1599         }
1600 }
1601
1602 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1603 {
1604         gltextureunit_t *unit = gl_state.units + unitnum;
1605         if (unitnum >= backendimageunits)
1606                 return;
1607         // update 1d texture binding
1608         if (unit->t1d)
1609         {
1610                 GL_ActiveTexture(unitnum);
1611                 if (unitnum < backendunits)
1612                 {
1613                         if (unit->t1d)
1614                         {
1615                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1616                         }
1617                 }
1618                 unit->t1d = 0;
1619                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1620         }
1621         // update 2d texture binding
1622         if (unit->t2d)
1623         {
1624                 GL_ActiveTexture(unitnum);
1625                 if (unitnum < backendunits)
1626                 {
1627                         if (unit->t2d)
1628                         {
1629                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1630                         }
1631                 }
1632                 unit->t2d = 0;
1633                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1634         }
1635         // update 3d texture binding
1636         if (unit->t3d != texnum)
1637         {
1638                 GL_ActiveTexture(unitnum);
1639                 if (unitnum < backendunits)
1640                 {
1641                         if (texnum)
1642                         {
1643                                 if (unit->t3d == 0)
1644                                 {
1645                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1646                                 }
1647                         }
1648                         else
1649                         {
1650                                 if (unit->t3d)
1651                                 {
1652                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1653                                 }
1654                         }
1655                 }
1656                 unit->t3d = texnum;
1657                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1658         }
1659         // update cubemap texture binding
1660         if (unit->tcubemap != 0)
1661         {
1662                 GL_ActiveTexture(unitnum);
1663                 if (unitnum < backendunits)
1664                 {
1665                         if (unit->tcubemap)
1666                         {
1667                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1668                         }
1669                 }
1670                 unit->tcubemap = 0;
1671                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1672         }
1673 }
1674
1675 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1676 {
1677         gltextureunit_t *unit = gl_state.units + unitnum;
1678         if (unitnum >= backendimageunits)
1679                 return;
1680         // update 1d texture binding
1681         if (unit->t1d)
1682         {
1683                 GL_ActiveTexture(unitnum);
1684                 if (unitnum < backendunits)
1685                 {
1686                         if (unit->t1d)
1687                         {
1688                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1689                         }
1690                 }
1691                 unit->t1d = 0;
1692                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1693         }
1694         // update 2d texture binding
1695         if (unit->t2d)
1696         {
1697                 GL_ActiveTexture(unitnum);
1698                 if (unitnum < backendunits)
1699                 {
1700                         if (unit->t2d)
1701                         {
1702                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1703                         }
1704                 }
1705                 unit->t2d = 0;
1706                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1707         }
1708         // update 3d texture binding
1709         if (unit->t3d)
1710         {
1711                 GL_ActiveTexture(unitnum);
1712                 if (unitnum < backendunits)
1713                 {
1714                         if (unit->t3d)
1715                         {
1716                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1717                         }
1718                 }
1719                 unit->t3d = 0;
1720                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1721         }
1722         // update cubemap texture binding
1723         if (unit->tcubemap != texnum)
1724         {
1725                 GL_ActiveTexture(unitnum);
1726                 if (unitnum < backendunits)
1727                 {
1728                         if (texnum)
1729                         {
1730                                 if (unit->tcubemap == 0)
1731                                 {
1732                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1733                                 }
1734                         }
1735                         else
1736                         {
1737                                 if (unit->tcubemap)
1738                                 {
1739                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1740                                 }
1741                         }
1742                 }
1743                 unit->tcubemap = texnum;
1744                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1745         }
1746 }
1747
1748 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1749 {
1750         gltextureunit_t *unit = gl_state.units + unitnum;
1751         if (matrix->m[3][3])
1752         {
1753                 // texmatrix specified, check if it is different
1754                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1755                 {
1756                         double glmatrix[16];
1757                         unit->texmatrixenabled = true;
1758                         unit->matrix = *matrix;
1759                         CHECKGLERROR
1760                         Matrix4x4_ToArrayDoubleGL(&unit->matrix, glmatrix);
1761                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1762                         GL_ActiveTexture(unitnum);
1763                         qglLoadMatrixd(glmatrix);CHECKGLERROR
1764                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1765                 }
1766         }
1767         else
1768         {
1769                 // no texmatrix specified, revert to identity
1770                 if (unit->texmatrixenabled)
1771                 {
1772                         unit->texmatrixenabled = false;
1773                         CHECKGLERROR
1774                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1775                         GL_ActiveTexture(unitnum);
1776                         qglLoadIdentity();CHECKGLERROR
1777                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1778                 }
1779         }
1780 }
1781
1782 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1783 {
1784         gltextureunit_t *unit = gl_state.units + unitnum;
1785         CHECKGLERROR
1786         if (gl_combine.integer)
1787         {
1788                 // GL_ARB_texture_env_combine
1789                 if (!combinergb)
1790                         combinergb = GL_MODULATE;
1791                 if (!combinealpha)
1792                         combinealpha = GL_MODULATE;
1793                 if (!rgbscale)
1794                         rgbscale = 1;
1795                 if (!alphascale)
1796                         alphascale = 1;
1797                 if (unit->combinergb != combinergb)
1798                 {
1799                         unit->combinergb = combinergb;
1800                         GL_ActiveTexture(unitnum);
1801                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1802                 }
1803                 if (unit->combinealpha != combinealpha)
1804                 {
1805                         unit->combinealpha = combinealpha;
1806                         GL_ActiveTexture(unitnum);
1807                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1808                 }
1809                 if (unit->rgbscale != rgbscale)
1810                 {
1811                         GL_ActiveTexture(unitnum);
1812                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
1813                 }
1814                 if (unit->alphascale != alphascale)
1815                 {
1816                         GL_ActiveTexture(unitnum);
1817                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
1818                 }
1819         }
1820         else
1821         {
1822                 // normal GL texenv
1823                 if (!combinergb)
1824                         combinergb = GL_MODULATE;
1825                 if (unit->combinergb != combinergb)
1826                 {
1827                         unit->combinergb = combinergb;
1828                         GL_ActiveTexture(unitnum);
1829                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1830                 }
1831         }
1832 }
1833
1834 void R_Mesh_TextureState(const rmeshstate_t *m)
1835 {
1836         unsigned int i;
1837
1838         BACKENDACTIVECHECK
1839
1840         CHECKGLERROR
1841         if (gl_backend_rebindtextures)
1842         {
1843                 gl_backend_rebindtextures = false;
1844                 GL_SetupTextureState();
1845                 CHECKGLERROR
1846         }
1847
1848         for (i = 0;i < backendimageunits;i++)
1849                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
1850         for (i = 0;i < backendarrayunits;i++)
1851         {
1852                 if (m->pointer_texcoord3f[i])
1853                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
1854                 else
1855                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
1856         }
1857         for (i = 0;i < backendunits;i++)
1858         {
1859                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
1860                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
1861         }
1862         CHECKGLERROR
1863 }
1864
1865 void R_Mesh_ResetTextureState(void)
1866 {
1867         unsigned int unitnum;
1868
1869         BACKENDACTIVECHECK
1870
1871         CHECKGLERROR
1872         if (gl_backend_rebindtextures)
1873         {
1874                 gl_backend_rebindtextures = false;
1875                 GL_SetupTextureState();
1876                 CHECKGLERROR
1877         }
1878
1879         for (unitnum = 0;unitnum < backendimageunits;unitnum++)
1880         {
1881                 gltextureunit_t *unit = gl_state.units + unitnum;
1882                 // update 1d texture binding
1883                 if (unit->t1d)
1884                 {
1885                         GL_ActiveTexture(unitnum);
1886                         if (unitnum < backendunits)
1887                         {
1888                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1889                         }
1890                         unit->t1d = 0;
1891                         qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1892                 }
1893                 // update 2d texture binding
1894                 if (unit->t2d)
1895                 {
1896                         GL_ActiveTexture(unitnum);
1897                         if (unitnum < backendunits)
1898                         {
1899                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1900                         }
1901                         unit->t2d = 0;
1902                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1903                 }
1904                 // update 3d texture binding
1905                 if (unit->t3d)
1906                 {
1907                         GL_ActiveTexture(unitnum);
1908                         if (unitnum < backendunits)
1909                         {
1910                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1911                         }
1912                         unit->t3d = 0;
1913                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1914                 }
1915                 // update cubemap texture binding
1916                 if (unit->tcubemap)
1917                 {
1918                         GL_ActiveTexture(unitnum);
1919                         if (unitnum < backendunits)
1920                         {
1921                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1922                         }
1923                         unit->tcubemap = 0;
1924                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1925                 }
1926         }
1927         for (unitnum = 0;unitnum < backendarrayunits;unitnum++)
1928         {
1929                 gltextureunit_t *unit = gl_state.units + unitnum;
1930                 // texture array unit is disabled, disable the array
1931                 if (unit->arrayenabled)
1932                 {
1933                         unit->arrayenabled = false;
1934                         GL_ClientActiveTexture(unitnum);
1935                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1936                 }
1937         }
1938         for (unitnum = 0;unitnum < backendunits;unitnum++)
1939         {
1940                 gltextureunit_t *unit = gl_state.units + unitnum;
1941                 // no texmatrix specified, revert to identity
1942                 if (unit->texmatrixenabled)
1943                 {
1944                         unit->texmatrixenabled = false;
1945                         CHECKGLERROR
1946                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1947                         GL_ActiveTexture(unitnum);
1948                         qglLoadIdentity();CHECKGLERROR
1949                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1950                 }
1951                 if (gl_combine.integer)
1952                 {
1953                         // GL_ARB_texture_env_combine
1954                         if (unit->combinergb != GL_MODULATE)
1955                         {
1956                                 unit->combinergb = GL_MODULATE;
1957                                 GL_ActiveTexture(unitnum);
1958                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1959                         }
1960                         if (unit->combinealpha != GL_MODULATE)
1961                         {
1962                                 unit->combinealpha = GL_MODULATE;
1963                                 GL_ActiveTexture(unitnum);
1964                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1965                         }
1966                         if (unit->rgbscale != 1)
1967                         {
1968                                 GL_ActiveTexture(unitnum);
1969                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = 1));CHECKGLERROR
1970                         }
1971                         if (unit->alphascale != 1)
1972                         {
1973                                 GL_ActiveTexture(unitnum);
1974                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = 1));CHECKGLERROR
1975                         }
1976                 }
1977                 else
1978                 {
1979                         // normal GL texenv
1980                         if (unit->combinergb != GL_MODULATE)
1981                         {
1982                                 unit->combinergb = GL_MODULATE;
1983                                 GL_ActiveTexture(unitnum);
1984                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1985                         }
1986                 }
1987         }
1988 }
1989
1990 void R_Mesh_Draw_ShowTris(int firstvertex, int numvertices, int numtriangles, const int *elements)
1991 {
1992         CHECKGLERROR
1993         qglBegin(GL_LINES);
1994         for (;numtriangles;numtriangles--, elements += 3)
1995         {
1996                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1997                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1998                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1999         }
2000         qglEnd();
2001         CHECKGLERROR
2002 }