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