]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
added DP_QC_STRFTIME extension
[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", "1", "enables use of glLockArraysEXT, may cause glitches with some broken drivers"};
16
17 int gl_maxdrawrangeelementsvertices;
18 int gl_maxdrawrangeelementsindices;
19
20 #ifdef DEBUGGL
21 int errornumber = 0;
22
23 void GL_PrintError(int errornumber, char *filename, int linenumber)
24 {
25         switch(errornumber)
26         {
27 #ifdef GL_INVALID_ENUM
28         case GL_INVALID_ENUM:
29                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
30                 break;
31 #endif
32 #ifdef GL_INVALID_VALUE
33         case GL_INVALID_VALUE:
34                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
35                 break;
36 #endif
37 #ifdef GL_INVALID_OPERATION
38         case GL_INVALID_OPERATION:
39                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
40                 break;
41 #endif
42 #ifdef GL_STACK_OVERFLOW
43         case GL_STACK_OVERFLOW:
44                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
45                 break;
46 #endif
47 #ifdef GL_STACK_UNDERFLOW
48         case GL_STACK_UNDERFLOW:
49                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
50                 break;
51 #endif
52 #ifdef GL_OUT_OF_MEMORY
53         case GL_OUT_OF_MEMORY:
54                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
55                 break;
56 #endif
57 #ifdef GL_TABLE_TOO_LARGE
58         case GL_TABLE_TOO_LARGE:
59                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
60                 break;
61 #endif
62         default:
63                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
64                 break;
65         }
66 }
67 #endif
68
69 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active");
70
71 void SCR_ScreenShot_f (void);
72
73 static matrix4x4_t backend_viewmatrix;
74 static matrix4x4_t backend_modelmatrix;
75 static matrix4x4_t backend_modelviewmatrix;
76 static matrix4x4_t backend_projectmatrix;
77
78 static unsigned int backendunits, backendimageunits, backendarrayunits, backendactive;
79
80 /*
81 note: here's strip order for a terrain row:
82 0--1--2--3--4
83 |\ |\ |\ |\ |
84 | \| \| \| \|
85 A--B--C--D--E
86 clockwise
87
88 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
89
90 *elements++ = i + row;
91 *elements++ = i;
92 *elements++ = i + row + 1;
93 *elements++ = i;
94 *elements++ = i + 1;
95 *elements++ = i + row + 1;
96
97
98 for (y = 0;y < rows - 1;y++)
99 {
100         for (x = 0;x < columns - 1;x++)
101         {
102                 i = y * rows + x;
103                 *elements++ = i + columns;
104                 *elements++ = i;
105                 *elements++ = i + columns + 1;
106                 *elements++ = i;
107                 *elements++ = i + 1;
108                 *elements++ = i + columns + 1;
109         }
110 }
111
112 alternative:
113 0--1--2--3--4
114 | /| /|\ | /|
115 |/ |/ | \|/ |
116 A--B--C--D--E
117 counterclockwise
118
119 for (y = 0;y < rows - 1;y++)
120 {
121         for (x = 0;x < columns - 1;x++)
122         {
123                 i = y * rows + x;
124                 *elements++ = i;
125                 *elements++ = i + columns;
126                 *elements++ = i + columns + 1;
127                 *elements++ = i + columns;
128                 *elements++ = i + columns + 1;
129                 *elements++ = i + 1;
130         }
131 }
132 */
133
134 int polygonelements[(POLYGONELEMENTS_MAXPOINTS-2)*3];
135 int quadelements[QUADELEMENTS_MAXQUADS*6];
136
137 void GL_Backend_AllocArrays(void)
138 {
139 }
140
141 void GL_Backend_FreeArrays(void)
142 {
143 }
144
145 static void gl_backend_start(void)
146 {
147         Con_Print("OpenGL Backend starting...\n");
148         CHECKGLERROR
149
150         if (qglDrawRangeElements != NULL)
151         {
152                 CHECKGLERROR
153                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
154                 CHECKGLERROR
155                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
156                 CHECKGLERROR
157                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
158         }
159
160         backendunits = bound(1, gl_textureunits, MAX_TEXTUREUNITS);
161         backendimageunits = backendunits;
162         backendarrayunits = backendunits;
163         if (gl_support_fragment_shader)
164         {
165                 CHECKGLERROR
166                 qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, (int *)&backendimageunits);
167                 CHECKGLERROR
168                 qglGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, (int *)&backendarrayunits);
169                 CHECKGLERROR
170                 Con_Printf("GLSL shader support detected: texture units = %i texenv, %i image, %i array\n", backendunits, backendimageunits, backendarrayunits);
171                 backendimageunits = bound(1, backendimageunits, MAX_TEXTUREUNITS);
172                 backendarrayunits = bound(1, backendarrayunits, MAX_TEXTUREUNITS);
173         }
174         else if (backendunits > 1)
175                 Con_Printf("multitexture detected: texture units = %i\n", backendunits);
176         else
177                 Con_Printf("singletexture\n");
178
179         GL_Backend_AllocArrays();
180
181         Con_Printf("OpenGL backend started.\n");
182
183         CHECKGLERROR
184
185         backendactive = true;
186 }
187
188 static void gl_backend_shutdown(void)
189 {
190         backendunits = 0;
191         backendimageunits = 0;
192         backendarrayunits = 0;
193         backendactive = false;
194
195         Con_Print("OpenGL Backend shutting down\n");
196
197         GL_Backend_FreeArrays();
198 }
199
200 static void gl_backend_newmap(void)
201 {
202 }
203
204 void gl_backend_init(void)
205 {
206         int i;
207
208         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
209         {
210                 polygonelements[i * 3 + 0] = 0;
211                 polygonelements[i * 3 + 1] = i + 1;
212                 polygonelements[i * 3 + 2] = i + 2;
213         }
214         // elements for rendering a series of quads as triangles
215         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
216         {
217                 quadelements[i * 6 + 0] = i * 4;
218                 quadelements[i * 6 + 1] = i * 4 + 1;
219                 quadelements[i * 6 + 2] = i * 4 + 2;
220                 quadelements[i * 6 + 3] = i * 4;
221                 quadelements[i * 6 + 4] = i * 4 + 2;
222                 quadelements[i * 6 + 5] = i * 4 + 3;
223         }
224
225         Cvar_RegisterVariable(&r_render);
226         Cvar_RegisterVariable(&r_waterwarp);
227         Cvar_RegisterVariable(&gl_polyblend);
228         Cvar_RegisterVariable(&gl_dither);
229         Cvar_RegisterVariable(&gl_lockarrays);
230         Cvar_RegisterVariable(&gl_paranoid);
231         Cvar_RegisterVariable(&gl_printcheckerror);
232 #ifdef NORENDER
233         Cvar_SetValue("r_render", 0);
234 #endif
235
236         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
237         Cvar_RegisterVariable(&gl_mesh_testarrayelement);
238         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
239
240         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
241 }
242
243 void GL_SetupView_Orientation_Identity (void)
244 {
245         backend_viewmatrix = identitymatrix;
246         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
247 }
248
249 void GL_SetupView_Orientation_FromEntity(const matrix4x4_t *matrix)
250 {
251         matrix4x4_t tempmatrix, basematrix;
252         Matrix4x4_Invert_Simple(&tempmatrix, matrix);
253         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
254         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
255         Matrix4x4_Concat(&backend_viewmatrix, &basematrix, &tempmatrix);
256         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
257         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
258         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
259         //Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
260         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
261 }
262
263 void GL_SetupView_Mode_Perspective (double frustumx, double frustumy, double zNear, double zFar)
264 {
265         double m[16];
266
267         // set up viewpoint
268         CHECKGLERROR
269         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
270         qglLoadIdentity();CHECKGLERROR
271         // set view pyramid
272         qglFrustum(-frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);CHECKGLERROR
273         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
274         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
275         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
276         GL_SetupView_Orientation_Identity();
277         CHECKGLERROR
278 }
279
280 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double frustumx, double frustumy, double zNear)
281 {
282         double nudge, m[16];
283
284         // set up viewpoint
285         CHECKGLERROR
286         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
287         qglLoadIdentity();CHECKGLERROR
288         // set view pyramid
289         nudge = 1.0 - 1.0 / (1<<23);
290         m[ 0] = 1.0 / frustumx;
291         m[ 1] = 0;
292         m[ 2] = 0;
293         m[ 3] = 0;
294         m[ 4] = 0;
295         m[ 5] = 1.0 / frustumy;
296         m[ 6] = 0;
297         m[ 7] = 0;
298         m[ 8] = 0;
299         m[ 9] = 0;
300         m[10] = -nudge;
301         m[11] = -1;
302         m[12] = 0;
303         m[13] = 0;
304         m[14] = -2 * zNear * nudge;
305         m[15] = 0;
306         qglLoadMatrixd(m);CHECKGLERROR
307         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
308         GL_SetupView_Orientation_Identity();
309         CHECKGLERROR
310         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
311 }
312
313 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
314 {
315         double m[16];
316
317         // set up viewpoint
318         CHECKGLERROR
319         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
320         qglLoadIdentity();CHECKGLERROR
321         qglOrtho(x1, x2, y2, y1, zNear, zFar);CHECKGLERROR
322         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
323         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
324         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
325         GL_SetupView_Orientation_Identity();
326         CHECKGLERROR
327 }
328
329 typedef struct gltextureunit_s
330 {
331         int t1d, t2d, t3d, tcubemap;
332         int arrayenabled;
333         unsigned int arraycomponents;
334         const void *pointer_texcoord;
335         int rgbscale, alphascale;
336         int combinergb, combinealpha;
337         // FIXME: add more combine stuff
338         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
339         int texmatrixenabled;
340         matrix4x4_t matrix;
341 }
342 gltextureunit_t;
343
344 static struct gl_state_s
345 {
346         int cullface;
347         int cullfaceenable;
348         int blendfunc1;
349         int blendfunc2;
350         int blend;
351         GLboolean depthmask;
352         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
353         int depthtest;
354         int alphatest;
355         int scissortest;
356         unsigned int unit;
357         unsigned int clientunit;
358         gltextureunit_t units[MAX_TEXTUREUNITS];
359         float color4f[4];
360         int lockrange_first;
361         int lockrange_count;
362         const void *pointer_vertex;
363         const void *pointer_color;
364 }
365 gl_state;
366
367 void GL_SetupTextureState(void)
368 {
369         unsigned int i;
370         gltextureunit_t *unit;
371         CHECKGLERROR
372         gl_state.unit = MAX_TEXTUREUNITS;
373         gl_state.clientunit = MAX_TEXTUREUNITS;
374         for (i = 0;i < MAX_TEXTUREUNITS;i++)
375         {
376                 unit = gl_state.units + i;
377                 unit->t1d = 0;
378                 unit->t2d = 0;
379                 unit->t3d = 0;
380                 unit->tcubemap = 0;
381                 unit->arrayenabled = false;
382                 unit->arraycomponents = 0;
383                 unit->pointer_texcoord = NULL;
384                 unit->rgbscale = 1;
385                 unit->alphascale = 1;
386                 unit->combinergb = GL_MODULATE;
387                 unit->combinealpha = GL_MODULATE;
388                 unit->texmatrixenabled = false;
389                 unit->matrix = identitymatrix;
390         }
391
392         for (i = 0;i < backendimageunits;i++)
393         {
394                 GL_ActiveTexture(i);
395                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
396                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
397                 if (gl_texture3d)
398                 {
399                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
400                 }
401                 if (gl_texturecubemap)
402                 {
403                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
404                 }
405         }
406
407         for (i = 0;i < backendarrayunits;i++)
408         {
409                 GL_ClientActiveTexture(i);
410                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
411                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
412         }
413
414         for (i = 0;i < backendunits;i++)
415         {
416                 GL_ActiveTexture(i);
417                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
418                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
419                 if (gl_texture3d)
420                 {
421                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
422                 }
423                 if (gl_texturecubemap)
424                 {
425                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
426                 }
427                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
428                 qglLoadIdentity();CHECKGLERROR
429                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
430                 if (gl_combine.integer)
431                 {
432                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
433                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
434                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
435                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
436                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
437                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
438                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
439                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
440                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
441                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
442                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
443                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
444                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
445                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
446                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
447                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
448                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
449                 }
450                 else
451                 {
452                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
453                 }
454                 CHECKGLERROR
455         }
456         CHECKGLERROR
457 }
458
459 void GL_Backend_ResetState(void)
460 {
461         memset(&gl_state, 0, sizeof(gl_state));
462         gl_state.depthtest = true;
463         gl_state.alphatest = false;
464         gl_state.blendfunc1 = GL_ONE;
465         gl_state.blendfunc2 = GL_ZERO;
466         gl_state.blend = false;
467         gl_state.depthmask = GL_TRUE;
468         gl_state.colormask = 15;
469         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
470         gl_state.lockrange_first = 0;
471         gl_state.lockrange_count = 0;
472         gl_state.pointer_vertex = NULL;
473         gl_state.pointer_color = NULL;
474         gl_state.cullface = GL_FRONT; // quake is backwards, this culls back faces
475         gl_state.cullfaceenable = true;
476
477         CHECKGLERROR
478
479         qglColorMask(1, 1, 1, 1);
480         qglAlphaFunc(GL_GEQUAL, 0.5);CHECKGLERROR
481         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
482         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
483         qglDisable(GL_BLEND);CHECKGLERROR
484         qglCullFace(gl_state.cullface);CHECKGLERROR
485         qglEnable(GL_CULL_FACE);CHECKGLERROR
486         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
487         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
488         qglDepthMask(gl_state.depthmask);CHECKGLERROR
489
490         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
491         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
492
493         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
494         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
495
496         GL_Color(0, 0, 0, 0);
497         GL_Color(1, 1, 1, 1);
498
499         GL_SetupTextureState();
500 }
501
502 void GL_ActiveTexture(unsigned int num)
503 {
504         if (gl_state.unit != num)
505         {
506                 gl_state.unit = num;
507                 if (qglActiveTexture)
508                 {
509                         CHECKGLERROR
510                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
511                         CHECKGLERROR
512                 }
513         }
514 }
515
516 void GL_ClientActiveTexture(unsigned int num)
517 {
518         if (gl_state.clientunit != num)
519         {
520                 gl_state.clientunit = num;
521                 if (qglActiveTexture)
522                 {
523                         CHECKGLERROR
524                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
525                         CHECKGLERROR
526                 }
527         }
528 }
529
530 void GL_BlendFunc(int blendfunc1, int blendfunc2)
531 {
532         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
533         {
534                 CHECKGLERROR
535                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
536                 if (gl_state.blendfunc2 == GL_ZERO)
537                 {
538                         if (gl_state.blendfunc1 == GL_ONE)
539                         {
540                                 if (gl_state.blend)
541                                 {
542                                         gl_state.blend = 0;
543                                         qglDisable(GL_BLEND);CHECKGLERROR
544                                 }
545                         }
546                         else
547                         {
548                                 if (!gl_state.blend)
549                                 {
550                                         gl_state.blend = 1;
551                                         qglEnable(GL_BLEND);CHECKGLERROR
552                                 }
553                         }
554                 }
555                 else
556                 {
557                         if (!gl_state.blend)
558                         {
559                                 gl_state.blend = 1;
560                                 qglEnable(GL_BLEND);CHECKGLERROR
561                         }
562                 }
563         }
564 }
565
566 void GL_DepthMask(int state)
567 {
568         if (gl_state.depthmask != state)
569         {
570                 CHECKGLERROR
571                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
572         }
573 }
574
575 void GL_DepthTest(int state)
576 {
577         if (gl_state.depthtest != state)
578         {
579                 gl_state.depthtest = state;
580                 CHECKGLERROR
581                 if (gl_state.depthtest)
582                 {
583                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
584                 }
585                 else
586                 {
587                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
588                 }
589         }
590 }
591
592 void GL_CullFace(int state)
593 {
594         CHECKGLERROR
595         if (state != GL_NONE)
596         {
597                 if (!gl_state.cullfaceenable)
598                 {
599                         gl_state.cullfaceenable = true;
600                         qglEnable(GL_CULL_FACE);CHECKGLERROR
601                 }
602                 if (gl_state.cullface != state)
603                 {
604                         gl_state.cullface = state;
605                         qglCullFace(gl_state.cullface);CHECKGLERROR
606                 }
607         }
608         else
609         {
610                 if (gl_state.cullfaceenable)
611                 {
612                         gl_state.cullfaceenable = false;
613                         qglDisable(GL_CULL_FACE);CHECKGLERROR
614                 }
615         }
616 }
617
618 void GL_AlphaTest(int state)
619 {
620         if (gl_state.alphatest != state)
621         {
622                 gl_state.alphatest = state;
623                 CHECKGLERROR
624                 if (gl_state.alphatest)
625                 {
626                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
627                 }
628                 else
629                 {
630                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
631                 }
632         }
633 }
634
635 void GL_ColorMask(int r, int g, int b, int a)
636 {
637         int state = r*8 + g*4 + b*2 + a*1;
638         if (gl_state.colormask != state)
639         {
640                 gl_state.colormask = state;
641                 CHECKGLERROR
642                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
643         }
644 }
645
646 void GL_Color(float cr, float cg, float cb, float ca)
647 {
648         if (gl_state.pointer_color || gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
649         {
650                 gl_state.color4f[0] = cr;
651                 gl_state.color4f[1] = cg;
652                 gl_state.color4f[2] = cb;
653                 gl_state.color4f[3] = ca;
654                 CHECKGLERROR
655                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
656                 CHECKGLERROR
657         }
658 }
659
660 void GL_LockArrays(int first, int count)
661 {
662         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
663         {
664                 if (gl_state.lockrange_count)
665                 {
666                         gl_state.lockrange_count = 0;
667                         CHECKGLERROR
668                         qglUnlockArraysEXT();
669                         CHECKGLERROR
670                 }
671                 if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
672                 {
673                         gl_state.lockrange_first = first;
674                         gl_state.lockrange_count = count;
675                         CHECKGLERROR
676                         qglLockArraysEXT(first, count);
677                         CHECKGLERROR
678                 }
679         }
680 }
681
682 void GL_Scissor (int x, int y, int width, int height)
683 {
684         CHECKGLERROR
685         qglScissor(x, vid.height - (y + height),width,height);
686         CHECKGLERROR
687 }
688
689 void GL_ScissorTest(int state)
690 {
691         if(gl_state.scissortest == state)
692                 return;
693
694         CHECKGLERROR
695         if((gl_state.scissortest = state))
696                 qglEnable(GL_SCISSOR_TEST);
697         else
698                 qglDisable(GL_SCISSOR_TEST);
699         CHECKGLERROR
700 }
701
702 void GL_Clear(int mask)
703 {
704         CHECKGLERROR
705         qglClear(mask);CHECKGLERROR
706 }
707
708 void GL_TransformToScreen(const vec4_t in, vec4_t out)
709 {
710         vec4_t temp;
711         float iw;
712         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
713         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
714         iw = 1.0f / out[3];
715         out[0] = r_view.x + (out[0] * iw + 1.0f) * r_view.width * 0.5f;
716         out[1] = r_view.y + r_view.height - (out[1] * iw + 1.0f) * r_view.height * 0.5f;
717         out[2] = r_view.z + (out[2] * iw + 1.0f) * r_view.depth * 0.5f;
718 }
719
720 // called at beginning of frame
721 void R_Mesh_Start(void)
722 {
723         BACKENDACTIVECHECK
724         CHECKGLERROR
725         if (gl_printcheckerror.integer && !gl_paranoid.integer)
726         {
727                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
728                 Cvar_SetValueQuick(&gl_paranoid, 1);
729         }
730         GL_Backend_ResetState();
731 }
732
733 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
734 {
735         int shaderobject;
736         int shadercompiled;
737         char compilelog[MAX_INPUTLINE];
738         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
739         if (!shaderobject)
740                 return false;
741         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
742         qglCompileShaderARB(shaderobject);CHECKGLERROR
743         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
744         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
745         if (compilelog[0])
746                 Con_DPrintf("%s shader compile log:\n%s\n", shadertype, compilelog);
747         if (!shadercompiled)
748         {
749                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
750                 return false;
751         }
752         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
753         qglDeleteObjectARB(shaderobject);CHECKGLERROR
754         return true;
755 }
756
757 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)
758 {
759         GLint programlinked;
760         GLuint programobject = 0;
761         char linklog[MAX_INPUTLINE];
762         CHECKGLERROR
763
764         programobject = qglCreateProgramObjectARB();CHECKGLERROR
765         if (!programobject)
766                 return 0;
767
768         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
769                 goto cleanup;
770
771 #ifdef GL_GEOMETRY_SHADER_ARB
772         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
773                 goto cleanup;
774 #endif
775
776         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
777                 goto cleanup;
778
779         qglLinkProgramARB(programobject);CHECKGLERROR
780         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
781         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
782         if (linklog[0])
783         {
784                 Con_DPrintf("program link log:\n%s\n", linklog);
785                 // software vertex shader is ok but software fragment shader is WAY
786                 // too slow, fail program if so.
787                 // NOTE: this string might be ATI specific, but that's ok because the
788                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
789                 // software fragment shader due to low instruction and dependent
790                 // texture limits.
791                 if (strstr(linklog, "fragment shader will run in software"))
792                         programlinked = false;
793         }
794         if (!programlinked)
795                 goto cleanup;
796         return programobject;
797 cleanup:
798         qglDeleteObjectARB(programobject);CHECKGLERROR
799         return 0;
800 }
801
802 void GL_Backend_FreeProgram(unsigned int prog)
803 {
804         CHECKGLERROR
805         qglDeleteObjectARB(prog);
806         CHECKGLERROR
807 }
808
809 int gl_backend_rebindtextures;
810
811 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
812 {
813         int i;
814         if (offset)
815         {
816                 for (i = 0;i < count;i++)
817                         *out++ = *in++ + offset;
818         }
819         else
820                 memcpy(out, in, sizeof(*out) * count);
821 }
822
823 // renders triangles using vertices from the active arrays
824 int paranoidblah = 0;
825 void R_Mesh_Draw(int firstvertex, int numvertices, int numtriangles, const int *elements)
826 {
827         unsigned int numelements = numtriangles * 3;
828         if (numvertices < 3 || numtriangles < 1)
829         {
830                 Con_Printf("R_Mesh_Draw(%d, %d, %d, %8p);\n", firstvertex, numvertices, numtriangles, elements);
831                 return;
832         }
833         CHECKGLERROR
834         r_refdef.stats.meshes++;
835         r_refdef.stats.meshes_elements += numelements;
836         if (gl_paranoid.integer)
837         {
838                 unsigned int i, j, size;
839                 const int *p;
840                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
841                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
842                 CHECKGLERROR
843                 for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
844                         paranoidblah += *p;
845                 if (gl_state.pointer_color)
846                 {
847                         if (!qglIsEnabled(GL_COLOR_ARRAY))
848                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
849                         CHECKGLERROR
850                         for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
851                                 paranoidblah += *p;
852                 }
853                 for (i = 0;i < backendarrayunits;i++)
854                 {
855                         if (gl_state.units[i].arrayenabled)
856                         {
857                                 GL_ClientActiveTexture(i);
858                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
859                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
860                                 CHECKGLERROR
861                                 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++)
862                                         paranoidblah += *p;
863                         }
864                 }
865                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
866                 {
867                         if (elements[i] < firstvertex || elements[i] >= firstvertex + numvertices)
868                         {
869                                 Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in elements list\n", elements[i], firstvertex, firstvertex + numvertices);
870                                 return;
871                         }
872                 }
873                 CHECKGLERROR
874         }
875         if (r_render.integer)
876         {
877                 CHECKGLERROR
878                 if (gl_mesh_testmanualfeeding.integer)
879                 {
880                         unsigned int i, j;
881                         const GLfloat *p;
882                         qglBegin(GL_TRIANGLES);
883                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
884                         {
885                                 for (j = 0;j < backendarrayunits;j++)
886                                 {
887                                         if (gl_state.units[j].pointer_texcoord)
888                                         {
889                                                 if (backendarrayunits > 1)
890                                                 {
891                                                         if (gl_state.units[j].arraycomponents == 4)
892                                                         {
893                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
894                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
895                                                         }
896                                                         else if (gl_state.units[j].arraycomponents == 3)
897                                                         {
898                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
899                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
900                                                         }
901                                                         else if (gl_state.units[j].arraycomponents == 2)
902                                                         {
903                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
904                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
905                                                         }
906                                                         else
907                                                         {
908                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
909                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
910                                                         }
911                                                 }
912                                                 else
913                                                 {
914                                                         if (gl_state.units[j].arraycomponents == 4)
915                                                         {
916                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
917                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
918                                                         }
919                                                         else if (gl_state.units[j].arraycomponents == 3)
920                                                         {
921                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
922                                                                 qglTexCoord3f(p[0], p[1], p[2]);
923                                                         }
924                                                         else if (gl_state.units[j].arraycomponents == 2)
925                                                         {
926                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
927                                                                 qglTexCoord2f(p[0], p[1]);
928                                                         }
929                                                         else
930                                                         {
931                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
932                                                                 qglTexCoord1f(p[0]);
933                                                         }
934                                                 }
935                                         }
936                                 }
937                                 if (gl_state.pointer_color)
938                                 {
939                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
940                                         qglColor4f(p[0], p[1], p[2], p[3]);
941                                 }
942                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
943                                 qglVertex3f(p[0], p[1], p[2]);
944                         }
945                         qglEnd();
946                         CHECKGLERROR
947                 }
948                 else if (gl_mesh_testarrayelement.integer)
949                 {
950                         int i;
951                         qglBegin(GL_TRIANGLES);
952                         for (i = 0;i < numtriangles * 3;i++)
953                         {
954                                 qglArrayElement(elements[i]);
955                         }
956                         qglEnd();
957                         CHECKGLERROR
958                 }
959                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
960                 {
961                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, elements);
962                         CHECKGLERROR
963                 }
964                 else
965                 {
966                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);
967                         CHECKGLERROR
968                 }
969         }
970 }
971
972 // restores backend state, used when done with 3D rendering
973 void R_Mesh_Finish(void)
974 {
975         unsigned int i;
976         BACKENDACTIVECHECK
977         CHECKGLERROR
978         GL_LockArrays(0, 0);
979         CHECKGLERROR
980
981         for (i = 0;i < backendimageunits;i++)
982         {
983                 GL_ActiveTexture(i);
984                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
985                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
986                 if (gl_texture3d)
987                 {
988                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
989                 }
990                 if (gl_texturecubemap)
991                 {
992                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
993                 }
994         }
995         for (i = 0;i < backendarrayunits;i++)
996         {
997                 GL_ActiveTexture(backendarrayunits - 1 - i);
998                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
999         }
1000         for (i = 0;i < backendunits;i++)
1001         {
1002                 GL_ActiveTexture(backendunits - 1 - i);
1003                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1004                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1005                 if (gl_texture3d)
1006                 {
1007                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1008                 }
1009                 if (gl_texturecubemap)
1010                 {
1011                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1012                 }
1013                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1014                 if (gl_combine.integer)
1015                 {
1016                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1017                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1018                 }
1019         }
1020         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1021         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1022
1023         qglDisable(GL_BLEND);CHECKGLERROR
1024         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1025         qglDepthMask(GL_TRUE);CHECKGLERROR
1026         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1027 }
1028
1029 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1030 {
1031         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1032         {
1033                 double glmatrix[16];
1034                 backend_modelmatrix = *matrix;
1035                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
1036                 Matrix4x4_ToArrayDoubleGL(&backend_modelviewmatrix, glmatrix);
1037                 CHECKGLERROR
1038                 qglLoadMatrixd(glmatrix);CHECKGLERROR
1039         }
1040 }
1041
1042 void R_Mesh_VertexPointer(const float *vertex3f)
1043 {
1044         if (gl_state.pointer_vertex != vertex3f)
1045         {
1046                 gl_state.pointer_vertex = vertex3f;
1047                 CHECKGLERROR
1048                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), gl_state.pointer_vertex);
1049                 CHECKGLERROR
1050         }
1051 }
1052
1053 void R_Mesh_ColorPointer(const float *color4f)
1054 {
1055         if (gl_state.pointer_color != color4f)
1056         {
1057                 CHECKGLERROR
1058                 if (!gl_state.pointer_color)
1059                 {
1060                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1061                 }
1062                 else if (!color4f)
1063                 {
1064                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1065                         // when color array is on the glColor gets trashed, set it again
1066                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1067                 }
1068                 gl_state.pointer_color = color4f;
1069                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), gl_state.pointer_color);CHECKGLERROR
1070         }
1071 }
1072
1073 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord)
1074 {
1075         gltextureunit_t *unit = gl_state.units + unitnum;
1076         // update array settings
1077         CHECKGLERROR
1078         if (texcoord)
1079         {
1080                 // texcoord array
1081                 if (unit->pointer_texcoord != texcoord || unit->arraycomponents != numcomponents)
1082                 {
1083                         unit->pointer_texcoord = texcoord;
1084                         unit->arraycomponents = numcomponents;
1085                         GL_ClientActiveTexture(unitnum);
1086                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, unit->pointer_texcoord);CHECKGLERROR
1087                 }
1088                 // texture array unit is enabled, enable the array
1089                 if (!unit->arrayenabled)
1090                 {
1091                         unit->arrayenabled = true;
1092                         GL_ClientActiveTexture(unitnum);
1093                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1094                 }
1095         }
1096         else
1097         {
1098                 // texture array unit is disabled, disable the array
1099                 if (unit->arrayenabled)
1100                 {
1101                         unit->arrayenabled = false;
1102                         GL_ClientActiveTexture(unitnum);
1103                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1104                 }
1105         }
1106 }
1107
1108 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
1109 {
1110         gltextureunit_t *unit = gl_state.units + unitnum;
1111         if (unitnum >= backendimageunits)
1112                 return;
1113         // update 1d texture binding
1114         if (unit->t1d != tex1d)
1115         {
1116                 GL_ActiveTexture(unitnum);
1117                 if (unitnum < backendunits)
1118                 {
1119                         if (tex1d)
1120                         {
1121                                 if (unit->t1d == 0)
1122                                 {
1123                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1124                                 }
1125                         }
1126                         else
1127                         {
1128                                 if (unit->t1d)
1129                                 {
1130                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1131                                 }
1132                         }
1133                 }
1134                 unit->t1d = tex1d;
1135                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1136         }
1137         // update 2d texture binding
1138         if (unit->t2d != tex2d)
1139         {
1140                 GL_ActiveTexture(unitnum);
1141                 if (unitnum < backendunits)
1142                 {
1143                         if (tex2d)
1144                         {
1145                                 if (unit->t2d == 0)
1146                                 {
1147                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1148                                 }
1149                         }
1150                         else
1151                         {
1152                                 if (unit->t2d)
1153                                 {
1154                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1155                                 }
1156                         }
1157                 }
1158                 unit->t2d = tex2d;
1159                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1160         }
1161         // update 3d texture binding
1162         if (unit->t3d != tex3d)
1163         {
1164                 GL_ActiveTexture(unitnum);
1165                 if (unitnum < backendunits)
1166                 {
1167                         if (tex3d)
1168                         {
1169                                 if (unit->t3d == 0)
1170                                 {
1171                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1172                                 }
1173                         }
1174                         else
1175                         {
1176                                 if (unit->t3d)
1177                                 {
1178                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1179                                 }
1180                         }
1181                 }
1182                 unit->t3d = tex3d;
1183                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1184         }
1185         // update cubemap texture binding
1186         if (unit->tcubemap != texcubemap)
1187         {
1188                 GL_ActiveTexture(unitnum);
1189                 if (unitnum < backendunits)
1190                 {
1191                         if (texcubemap)
1192                         {
1193                                 if (unit->tcubemap == 0)
1194                                 {
1195                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1196                                 }
1197                         }
1198                         else
1199                         {
1200                                 if (unit->tcubemap)
1201                                 {
1202                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1203                                 }
1204                         }
1205                 }
1206                 unit->tcubemap = texcubemap;
1207                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1208         }
1209 }
1210
1211 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1212 {
1213         gltextureunit_t *unit = gl_state.units + unitnum;
1214         if (unitnum >= backendimageunits)
1215                 return;
1216         // update 1d texture binding
1217         if (unit->t1d != texnum)
1218         {
1219                 GL_ActiveTexture(unitnum);
1220                 if (unitnum < backendunits)
1221                 {
1222                         if (texnum)
1223                         {
1224                                 if (unit->t1d == 0)
1225                                 {
1226                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1227                                 }
1228                         }
1229                         else
1230                         {
1231                                 if (unit->t1d)
1232                                 {
1233                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1234                                 }
1235                         }
1236                 }
1237                 unit->t1d = texnum;
1238                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1239         }
1240         // update 2d texture binding
1241         if (unit->t2d)
1242         {
1243                 GL_ActiveTexture(unitnum);
1244                 if (unitnum < backendunits)
1245                 {
1246                         if (unit->t2d)
1247                         {
1248                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1249                         }
1250                 }
1251                 unit->t2d = 0;
1252                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1253         }
1254         // update 3d texture binding
1255         if (unit->t3d)
1256         {
1257                 GL_ActiveTexture(unitnum);
1258                 if (unitnum < backendunits)
1259                 {
1260                         if (unit->t3d)
1261                         {
1262                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1263                         }
1264                 }
1265                 unit->t3d = 0;
1266                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1267         }
1268         // update cubemap texture binding
1269         if (unit->tcubemap)
1270         {
1271                 GL_ActiveTexture(unitnum);
1272                 if (unitnum < backendunits)
1273                 {
1274                         if (unit->tcubemap)
1275                         {
1276                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1277                         }
1278                 }
1279                 unit->tcubemap = 0;
1280                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1281         }
1282 }
1283
1284 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1285 {
1286         gltextureunit_t *unit = gl_state.units + unitnum;
1287         if (unitnum >= backendimageunits)
1288                 return;
1289         // update 1d texture binding
1290         if (unit->t1d)
1291         {
1292                 GL_ActiveTexture(unitnum);
1293                 if (unitnum < backendunits)
1294                 {
1295                         if (unit->t1d)
1296                         {
1297                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1298                         }
1299                 }
1300                 unit->t1d = 0;
1301                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1302         }
1303         // update 2d texture binding
1304         if (unit->t2d != texnum)
1305         {
1306                 GL_ActiveTexture(unitnum);
1307                 if (unitnum < backendunits)
1308                 {
1309                         if (texnum)
1310                         {
1311                                 if (unit->t2d == 0)
1312                                 {
1313                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1314                                 }
1315                         }
1316                         else
1317                         {
1318                                 if (unit->t2d)
1319                                 {
1320                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1321                                 }
1322                         }
1323                 }
1324                 unit->t2d = texnum;
1325                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1326         }
1327         // update 3d texture binding
1328         if (unit->t3d)
1329         {
1330                 GL_ActiveTexture(unitnum);
1331                 if (unitnum < backendunits)
1332                 {
1333                         if (unit->t3d)
1334                         {
1335                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1336                         }
1337                 }
1338                 unit->t3d = 0;
1339                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1340         }
1341         // update cubemap texture binding
1342         if (unit->tcubemap != 0)
1343         {
1344                 GL_ActiveTexture(unitnum);
1345                 if (unitnum < backendunits)
1346                 {
1347                         if (unit->tcubemap)
1348                         {
1349                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1350                         }
1351                 }
1352                 unit->tcubemap = 0;
1353                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1354         }
1355 }
1356
1357 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1358 {
1359         gltextureunit_t *unit = gl_state.units + unitnum;
1360         if (unitnum >= backendimageunits)
1361                 return;
1362         // update 1d texture binding
1363         if (unit->t1d)
1364         {
1365                 GL_ActiveTexture(unitnum);
1366                 if (unitnum < backendunits)
1367                 {
1368                         if (unit->t1d)
1369                         {
1370                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1371                         }
1372                 }
1373                 unit->t1d = 0;
1374                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1375         }
1376         // update 2d texture binding
1377         if (unit->t2d)
1378         {
1379                 GL_ActiveTexture(unitnum);
1380                 if (unitnum < backendunits)
1381                 {
1382                         if (unit->t2d)
1383                         {
1384                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1385                         }
1386                 }
1387                 unit->t2d = 0;
1388                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1389         }
1390         // update 3d texture binding
1391         if (unit->t3d != texnum)
1392         {
1393                 GL_ActiveTexture(unitnum);
1394                 if (unitnum < backendunits)
1395                 {
1396                         if (texnum)
1397                         {
1398                                 if (unit->t3d == 0)
1399                                 {
1400                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1401                                 }
1402                         }
1403                         else
1404                         {
1405                                 if (unit->t3d)
1406                                 {
1407                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1408                                 }
1409                         }
1410                 }
1411                 unit->t3d = texnum;
1412                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1413         }
1414         // update cubemap texture binding
1415         if (unit->tcubemap != 0)
1416         {
1417                 GL_ActiveTexture(unitnum);
1418                 if (unitnum < backendunits)
1419                 {
1420                         if (unit->tcubemap)
1421                         {
1422                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1423                         }
1424                 }
1425                 unit->tcubemap = 0;
1426                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1427         }
1428 }
1429
1430 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1431 {
1432         gltextureunit_t *unit = gl_state.units + unitnum;
1433         if (unitnum >= backendimageunits)
1434                 return;
1435         // update 1d texture binding
1436         if (unit->t1d)
1437         {
1438                 GL_ActiveTexture(unitnum);
1439                 if (unitnum < backendunits)
1440                 {
1441                         if (unit->t1d)
1442                         {
1443                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1444                         }
1445                 }
1446                 unit->t1d = 0;
1447                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1448         }
1449         // update 2d texture binding
1450         if (unit->t2d)
1451         {
1452                 GL_ActiveTexture(unitnum);
1453                 if (unitnum < backendunits)
1454                 {
1455                         if (unit->t2d)
1456                         {
1457                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1458                         }
1459                 }
1460                 unit->t2d = 0;
1461                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1462         }
1463         // update 3d texture binding
1464         if (unit->t3d)
1465         {
1466                 GL_ActiveTexture(unitnum);
1467                 if (unitnum < backendunits)
1468                 {
1469                         if (unit->t3d)
1470                         {
1471                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1472                         }
1473                 }
1474                 unit->t3d = 0;
1475                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1476         }
1477         // update cubemap texture binding
1478         if (unit->tcubemap != texnum)
1479         {
1480                 GL_ActiveTexture(unitnum);
1481                 if (unitnum < backendunits)
1482                 {
1483                         if (texnum)
1484                         {
1485                                 if (unit->tcubemap == 0)
1486                                 {
1487                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1488                                 }
1489                         }
1490                         else
1491                         {
1492                                 if (unit->tcubemap)
1493                                 {
1494                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1495                                 }
1496                         }
1497                 }
1498                 unit->tcubemap = texnum;
1499                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1500         }
1501 }
1502
1503 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1504 {
1505         gltextureunit_t *unit = gl_state.units + unitnum;
1506         if (matrix->m[3][3])
1507         {
1508                 // texmatrix specified, check if it is different
1509                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1510                 {
1511                         double glmatrix[16];
1512                         unit->texmatrixenabled = true;
1513                         unit->matrix = *matrix;
1514                         CHECKGLERROR
1515                         Matrix4x4_ToArrayDoubleGL(&unit->matrix, glmatrix);
1516                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1517                         GL_ActiveTexture(unitnum);
1518                         qglLoadMatrixd(glmatrix);CHECKGLERROR
1519                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1520                 }
1521         }
1522         else
1523         {
1524                 // no texmatrix specified, revert to identity
1525                 if (unit->texmatrixenabled)
1526                 {
1527                         unit->texmatrixenabled = false;
1528                         CHECKGLERROR
1529                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1530                         GL_ActiveTexture(unitnum);
1531                         qglLoadIdentity();CHECKGLERROR
1532                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1533                 }
1534         }
1535 }
1536
1537 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1538 {
1539         gltextureunit_t *unit = gl_state.units + unitnum;
1540         CHECKGLERROR
1541         if (gl_combine.integer)
1542         {
1543                 // GL_ARB_texture_env_combine
1544                 if (!combinergb)
1545                         combinergb = GL_MODULATE;
1546                 if (!combinealpha)
1547                         combinealpha = GL_MODULATE;
1548                 if (!rgbscale)
1549                         rgbscale = 1;
1550                 if (!alphascale)
1551                         alphascale = 1;
1552                 if (unit->combinergb != combinergb)
1553                 {
1554                         unit->combinergb = combinergb;
1555                         GL_ActiveTexture(unitnum);
1556                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1557                 }
1558                 if (unit->combinealpha != combinealpha)
1559                 {
1560                         unit->combinealpha = combinealpha;
1561                         GL_ActiveTexture(unitnum);
1562                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1563                 }
1564                 if (unit->rgbscale != rgbscale)
1565                 {
1566                         GL_ActiveTexture(unitnum);
1567                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
1568                 }
1569                 if (unit->alphascale != alphascale)
1570                 {
1571                         GL_ActiveTexture(unitnum);
1572                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
1573                 }
1574         }
1575         else
1576         {
1577                 // normal GL texenv
1578                 if (!combinergb)
1579                         combinergb = GL_MODULATE;
1580                 if (unit->combinergb != combinergb)
1581                 {
1582                         unit->combinergb = combinergb;
1583                         GL_ActiveTexture(unitnum);
1584                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1585                 }
1586         }
1587 }
1588
1589 void R_Mesh_TextureState(const rmeshstate_t *m)
1590 {
1591         unsigned int i;
1592
1593         BACKENDACTIVECHECK
1594
1595         CHECKGLERROR
1596         if (gl_backend_rebindtextures)
1597         {
1598                 gl_backend_rebindtextures = false;
1599                 GL_SetupTextureState();
1600                 CHECKGLERROR
1601         }
1602
1603         for (i = 0;i < backendimageunits;i++)
1604                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
1605         for (i = 0;i < backendarrayunits;i++)
1606         {
1607                 if (m->pointer_texcoord3f[i])
1608                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i]);
1609                 else
1610                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i]);
1611         }
1612         for (i = 0;i < backendunits;i++)
1613         {
1614                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
1615                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
1616         }
1617         CHECKGLERROR
1618 }
1619
1620 void R_Mesh_ResetTextureState(void)
1621 {
1622         unsigned int unitnum;
1623
1624         BACKENDACTIVECHECK
1625
1626         CHECKGLERROR
1627         if (gl_backend_rebindtextures)
1628         {
1629                 gl_backend_rebindtextures = false;
1630                 GL_SetupTextureState();
1631                 CHECKGLERROR
1632         }
1633
1634         for (unitnum = 0;unitnum < backendimageunits;unitnum++)
1635         {
1636                 gltextureunit_t *unit = gl_state.units + unitnum;
1637                 // update 1d texture binding
1638                 if (unit->t1d)
1639                 {
1640                         GL_ActiveTexture(unitnum);
1641                         if (unitnum < backendunits)
1642                         {
1643                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1644                         }
1645                         unit->t1d = 0;
1646                         qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1647                 }
1648                 // update 2d texture binding
1649                 if (unit->t2d)
1650                 {
1651                         GL_ActiveTexture(unitnum);
1652                         if (unitnum < backendunits)
1653                         {
1654                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1655                         }
1656                         unit->t2d = 0;
1657                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1658                 }
1659                 // update 3d texture binding
1660                 if (unit->t3d)
1661                 {
1662                         GL_ActiveTexture(unitnum);
1663                         if (unitnum < backendunits)
1664                         {
1665                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1666                         }
1667                         unit->t3d = 0;
1668                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1669                 }
1670                 // update cubemap texture binding
1671                 if (unit->tcubemap)
1672                 {
1673                         GL_ActiveTexture(unitnum);
1674                         if (unitnum < backendunits)
1675                         {
1676                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1677                         }
1678                         unit->tcubemap = 0;
1679                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1680                 }
1681         }
1682         for (unitnum = 0;unitnum < backendarrayunits;unitnum++)
1683         {
1684                 gltextureunit_t *unit = gl_state.units + unitnum;
1685                 // texture array unit is disabled, disable the array
1686                 if (unit->arrayenabled)
1687                 {
1688                         unit->arrayenabled = false;
1689                         GL_ClientActiveTexture(unitnum);
1690                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1691                 }
1692         }
1693         for (unitnum = 0;unitnum < backendunits;unitnum++)
1694         {
1695                 gltextureunit_t *unit = gl_state.units + unitnum;
1696                 // no texmatrix specified, revert to identity
1697                 if (unit->texmatrixenabled)
1698                 {
1699                         unit->texmatrixenabled = false;
1700                         CHECKGLERROR
1701                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1702                         GL_ActiveTexture(unitnum);
1703                         qglLoadIdentity();CHECKGLERROR
1704                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1705                 }
1706                 if (gl_combine.integer)
1707                 {
1708                         // GL_ARB_texture_env_combine
1709                         if (unit->combinergb != GL_MODULATE)
1710                         {
1711                                 unit->combinergb = GL_MODULATE;
1712                                 GL_ActiveTexture(unitnum);
1713                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1714                         }
1715                         if (unit->combinealpha != GL_MODULATE)
1716                         {
1717                                 unit->combinealpha = GL_MODULATE;
1718                                 GL_ActiveTexture(unitnum);
1719                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1720                         }
1721                         if (unit->rgbscale != 1)
1722                         {
1723                                 GL_ActiveTexture(unitnum);
1724                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = 1));CHECKGLERROR
1725                         }
1726                         if (unit->alphascale != 1)
1727                         {
1728                                 GL_ActiveTexture(unitnum);
1729                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = 1));CHECKGLERROR
1730                         }
1731                 }
1732                 else
1733                 {
1734                         // normal GL texenv
1735                         if (unit->combinergb != GL_MODULATE)
1736                         {
1737                                 unit->combinergb = GL_MODULATE;
1738                                 GL_ActiveTexture(unitnum);
1739                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1740                         }
1741                 }
1742         }
1743 }
1744
1745 void R_Mesh_Draw_ShowTris(int firstvertex, int numvertices, int numtriangles, const int *elements)
1746 {
1747         CHECKGLERROR
1748         qglBegin(GL_LINES);
1749         for (;numtriangles;numtriangles--, elements += 3)
1750         {
1751                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1752                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1753                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1754         }
1755         qglEnd();
1756         CHECKGLERROR
1757 }