50d37a71186281a54e31e86d51d8d27cbeb21a55
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4
5 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
6 cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0", "use glBegin(GL_TRIANGLES);glArrayElement();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
7 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
8 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
9 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
10
11 cvar_t r_render = {0, "r_render", "1", "enables rendering calls (you want this on!)"};
12 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
13 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
14 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
15 cvar_t gl_lockarrays = {0, "gl_lockarrays", "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         if (gl_state.cullface != state)
595         {
596                 CHECKGLERROR
597                 if (state != GL_NONE)
598                 {
599                         if (!gl_state.cullfaceenable)
600                         {
601                                 gl_state.cullfaceenable = true;
602                                 qglEnable(GL_CULL_FACE);CHECKGLERROR
603                         }
604                         if (gl_state.cullface != state)
605                         {
606                                 gl_state.cullface = state;
607                                 qglCullFace(state);CHECKGLERROR
608                         }
609                 }
610                 else
611                 {
612                         if (gl_state.cullfaceenable)
613                         {
614                                 gl_state.cullfaceenable = false;
615                                 qglDisable(GL_CULL_FACE);CHECKGLERROR
616                         }
617                 }
618         }
619 }
620
621 void GL_AlphaTest(int state)
622 {
623         if (gl_state.alphatest != state)
624         {
625                 gl_state.alphatest = state;
626                 CHECKGLERROR
627                 if (gl_state.alphatest)
628                 {
629                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
630                 }
631                 else
632                 {
633                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
634                 }
635         }
636 }
637
638 void GL_ColorMask(int r, int g, int b, int a)
639 {
640         int state = r*8 + g*4 + b*2 + a*1;
641         if (gl_state.colormask != state)
642         {
643                 gl_state.colormask = state;
644                 CHECKGLERROR
645                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
646         }
647 }
648
649 void GL_Color(float cr, float cg, float cb, float ca)
650 {
651         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)
652         {
653                 gl_state.color4f[0] = cr;
654                 gl_state.color4f[1] = cg;
655                 gl_state.color4f[2] = cb;
656                 gl_state.color4f[3] = ca;
657                 CHECKGLERROR
658                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
659                 CHECKGLERROR
660         }
661 }
662
663 void GL_LockArrays(int first, int count)
664 {
665         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
666         {
667                 if (gl_state.lockrange_count)
668                 {
669                         gl_state.lockrange_count = 0;
670                         CHECKGLERROR
671                         qglUnlockArraysEXT();
672                         CHECKGLERROR
673                 }
674                 if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
675                 {
676                         gl_state.lockrange_first = first;
677                         gl_state.lockrange_count = count;
678                         CHECKGLERROR
679                         qglLockArraysEXT(first, count);
680                         CHECKGLERROR
681                 }
682         }
683 }
684
685 void GL_Scissor (int x, int y, int width, int height)
686 {
687         CHECKGLERROR
688         qglScissor(x, vid.height - (y + height),width,height);
689         CHECKGLERROR
690 }
691
692 void GL_ScissorTest(int state)
693 {
694         if(gl_state.scissortest == state)
695                 return;
696
697         CHECKGLERROR
698         if((gl_state.scissortest = state))
699                 qglEnable(GL_SCISSOR_TEST);
700         else
701                 qglDisable(GL_SCISSOR_TEST);
702         CHECKGLERROR
703 }
704
705 void GL_Clear(int mask)
706 {
707         CHECKGLERROR
708         qglClear(mask);CHECKGLERROR
709 }
710
711 void GL_TransformToScreen(const vec4_t in, vec4_t out)
712 {
713         vec4_t temp;
714         float iw;
715         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
716         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
717         iw = 1.0f / out[3];
718         out[0] = r_view.x + (out[0] * iw + 1.0f) * r_view.width * 0.5f;
719         out[1] = r_view.y + r_view.height - (out[1] * iw + 1.0f) * r_view.height * 0.5f;
720         out[2] = r_view.z + (out[2] * iw + 1.0f) * r_view.depth * 0.5f;
721 }
722
723 // called at beginning of frame
724 void R_Mesh_Start(void)
725 {
726         BACKENDACTIVECHECK
727         CHECKGLERROR
728         if (gl_printcheckerror.integer && !gl_paranoid.integer)
729         {
730                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
731                 Cvar_SetValueQuick(&gl_paranoid, 1);
732         }
733         GL_Backend_ResetState();
734 }
735
736 unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int fragmentstrings_count, const char **fragmentstrings_list)
737 {
738         GLint vertexshadercompiled, fragmentshadercompiled, programlinked;
739         GLuint vertexshaderobject, fragmentshaderobject, programobject = 0;
740         char compilelog[MAX_INPUTLINE];
741         CHECKGLERROR
742
743         programobject = qglCreateProgramObjectARB();CHECKGLERROR
744         if (!programobject)
745                 return 0;
746
747         if (developer.integer >= 100)
748         {
749                 int i;
750                 Con_Printf("Compiling shader:\n");
751                 if (vertexstrings_count)
752                 {
753                         Con_Printf("------ VERTEX SHADER ------\n");
754                         for (i = 0;i < vertexstrings_count;i++)
755                                 Con_Print(vertexstrings_list[i]);
756                         Con_Print("\n");
757                 }
758                 if (fragmentstrings_count)
759                 {
760                         Con_Printf("------ FRAGMENT SHADER ------\n");
761                         for (i = 0;i < fragmentstrings_count;i++)
762                                 Con_Print(fragmentstrings_list[i]);
763                         Con_Print("\n");
764                 }
765         }
766
767         if (vertexstrings_count)
768         {
769                 vertexshaderobject = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);CHECKGLERROR
770                 if (!vertexshaderobject)
771                 {
772                         qglDeleteObjectARB(programobject);
773                         CHECKGLERROR
774                         return 0;
775                 }
776                 qglShaderSourceARB(vertexshaderobject, vertexstrings_count, vertexstrings_list, NULL);CHECKGLERROR
777                 qglCompileShaderARB(vertexshaderobject);CHECKGLERROR
778                 qglGetObjectParameterivARB(vertexshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &vertexshadercompiled);CHECKGLERROR
779                 qglGetInfoLogARB(vertexshaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
780                 if (compilelog[0])
781                         Con_DPrintf("vertex shader compile log:\n%s\n", compilelog);
782                 if (!vertexshadercompiled)
783                 {
784                         qglDeleteObjectARB(programobject);CHECKGLERROR
785                         qglDeleteObjectARB(vertexshaderobject);CHECKGLERROR
786                         return 0;
787                 }
788                 qglAttachObjectARB(programobject, vertexshaderobject);CHECKGLERROR
789                 qglDeleteObjectARB(vertexshaderobject);CHECKGLERROR
790         }
791
792         if (fragmentstrings_count)
793         {
794                 fragmentshaderobject = qglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);CHECKGLERROR
795                 if (!fragmentshaderobject)
796                 {
797                         qglDeleteObjectARB(programobject);CHECKGLERROR
798                         return 0;
799                 }
800                 qglShaderSourceARB(fragmentshaderobject, fragmentstrings_count, fragmentstrings_list, NULL);CHECKGLERROR
801                 qglCompileShaderARB(fragmentshaderobject);CHECKGLERROR
802                 qglGetObjectParameterivARB(fragmentshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &fragmentshadercompiled);CHECKGLERROR
803                 qglGetInfoLogARB(fragmentshaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
804                 if (compilelog[0])
805                         Con_DPrintf("fragment shader compile log:\n%s\n", compilelog);
806                 if (!fragmentshadercompiled)
807                 {
808                         qglDeleteObjectARB(programobject);CHECKGLERROR
809                         qglDeleteObjectARB(fragmentshaderobject);CHECKGLERROR
810                         return 0;
811                 }
812                 qglAttachObjectARB(programobject, fragmentshaderobject);CHECKGLERROR
813                 qglDeleteObjectARB(fragmentshaderobject);CHECKGLERROR
814         }
815
816         qglLinkProgramARB(programobject);CHECKGLERROR
817         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
818         qglGetInfoLogARB(programobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
819         if (compilelog[0])
820         {
821                 Con_DPrintf("program link log:\n%s\n", compilelog);
822                 // software vertex shader is ok but software fragment shader is WAY
823                 // too slow, fail program if so.
824                 // NOTE: this string might be ATI specific, but that's ok because the
825                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
826                 // software fragment shader due to low instruction and dependent
827                 // texture limits.
828                 if (strstr(compilelog, "fragment shader will run in software"))
829                         programlinked = false;
830         }
831         if (!programlinked)
832         {
833                 qglDeleteObjectARB(programobject);CHECKGLERROR
834                 return 0;
835         }
836         CHECKGLERROR
837         return programobject;
838 }
839
840 void GL_Backend_FreeProgram(unsigned int prog)
841 {
842         CHECKGLERROR
843         qglDeleteObjectARB(prog);
844         CHECKGLERROR
845 }
846
847 int gl_backend_rebindtextures;
848
849 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
850 {
851         int i;
852         if (offset)
853         {
854                 for (i = 0;i < count;i++)
855                         *out++ = *in++ + offset;
856         }
857         else
858                 memcpy(out, in, sizeof(*out) * count);
859 }
860
861 // renders triangles using vertices from the active arrays
862 int paranoidblah = 0;
863 void R_Mesh_Draw(int firstvertex, int numvertices, int numtriangles, const int *elements)
864 {
865         unsigned int numelements = numtriangles * 3;
866         if (numvertices < 3 || numtriangles < 1)
867         {
868                 Con_Printf("R_Mesh_Draw(%d, %d, %d, %08p);\n", firstvertex, numvertices, numtriangles, elements);
869                 return;
870         }
871         CHECKGLERROR
872         r_refdef.stats.meshes++;
873         r_refdef.stats.meshes_elements += numelements;
874         if (gl_paranoid.integer)
875         {
876                 unsigned int i, j, size;
877                 const int *p;
878                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
879                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
880                 CHECKGLERROR
881                 for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
882                         paranoidblah += *p;
883                 if (gl_state.pointer_color)
884                 {
885                         if (!qglIsEnabled(GL_COLOR_ARRAY))
886                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
887                         CHECKGLERROR
888                         for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
889                                 paranoidblah += *p;
890                 }
891                 for (i = 0;i < backendarrayunits;i++)
892                 {
893                         if (gl_state.units[i].arrayenabled)
894                         {
895                                 GL_ClientActiveTexture(i);
896                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
897                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
898                                 CHECKGLERROR
899                                 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++)
900                                         paranoidblah += *p;
901                         }
902                 }
903                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
904                 {
905                         if (elements[i] < firstvertex || elements[i] >= firstvertex + numvertices)
906                         {
907                                 Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in elements list\n", elements[i], firstvertex, firstvertex + numvertices);
908                                 return;
909                         }
910                 }
911                 CHECKGLERROR
912         }
913         if (r_render.integer)
914         {
915                 CHECKGLERROR
916                 if (gl_mesh_testmanualfeeding.integer)
917                 {
918                         unsigned int i, j;
919                         const GLfloat *p;
920                         qglBegin(GL_TRIANGLES);
921                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
922                         {
923                                 for (j = 0;j < backendarrayunits;j++)
924                                 {
925                                         if (gl_state.units[j].pointer_texcoord)
926                                         {
927                                                 if (backendarrayunits > 1)
928                                                 {
929                                                         if (gl_state.units[j].arraycomponents == 4)
930                                                         {
931                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
932                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
933                                                         }
934                                                         else if (gl_state.units[j].arraycomponents == 3)
935                                                         {
936                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
937                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
938                                                         }
939                                                         else if (gl_state.units[j].arraycomponents == 2)
940                                                         {
941                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
942                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
943                                                         }
944                                                         else
945                                                         {
946                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
947                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
948                                                         }
949                                                 }
950                                                 else
951                                                 {
952                                                         if (gl_state.units[j].arraycomponents == 4)
953                                                         {
954                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
955                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
956                                                         }
957                                                         else if (gl_state.units[j].arraycomponents == 3)
958                                                         {
959                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
960                                                                 qglTexCoord3f(p[0], p[1], p[2]);
961                                                         }
962                                                         else if (gl_state.units[j].arraycomponents == 2)
963                                                         {
964                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
965                                                                 qglTexCoord2f(p[0], p[1]);
966                                                         }
967                                                         else
968                                                         {
969                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
970                                                                 qglTexCoord1f(p[0]);
971                                                         }
972                                                 }
973                                         }
974                                 }
975                                 if (gl_state.pointer_color)
976                                 {
977                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
978                                         qglColor4f(p[0], p[1], p[2], p[3]);
979                                 }
980                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
981                                 qglVertex3f(p[0], p[1], p[2]);
982                         }
983                         qglEnd();
984                         CHECKGLERROR
985                 }
986                 else if (gl_mesh_testarrayelement.integer)
987                 {
988                         int i;
989                         qglBegin(GL_TRIANGLES);
990                         for (i = 0;i < numtriangles * 3;i++)
991                         {
992                                 qglArrayElement(elements[i]);
993                         }
994                         qglEnd();
995                         CHECKGLERROR
996                 }
997                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
998                 {
999                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, elements);
1000                         CHECKGLERROR
1001                 }
1002                 else
1003                 {
1004                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);
1005                         CHECKGLERROR
1006                 }
1007         }
1008 }
1009
1010 // restores backend state, used when done with 3D rendering
1011 void R_Mesh_Finish(void)
1012 {
1013         unsigned int i;
1014         BACKENDACTIVECHECK
1015         CHECKGLERROR
1016         GL_LockArrays(0, 0);
1017         CHECKGLERROR
1018
1019         for (i = 0;i < backendimageunits;i++)
1020         {
1021                 GL_ActiveTexture(i);
1022                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
1023                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1024                 if (gl_texture3d)
1025                 {
1026                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1027                 }
1028                 if (gl_texturecubemap)
1029                 {
1030                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1031                 }
1032         }
1033         for (i = 0;i < backendarrayunits;i++)
1034         {
1035                 GL_ActiveTexture(backendarrayunits - 1 - i);
1036                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1037         }
1038         for (i = 0;i < backendunits;i++)
1039         {
1040                 GL_ActiveTexture(backendunits - 1 - i);
1041                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1042                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1043                 if (gl_texture3d)
1044                 {
1045                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1046                 }
1047                 if (gl_texturecubemap)
1048                 {
1049                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1050                 }
1051                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1052                 if (gl_combine.integer)
1053                 {
1054                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1055                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1056                 }
1057         }
1058         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1059         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1060
1061         qglDisable(GL_BLEND);CHECKGLERROR
1062         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1063         qglDepthMask(GL_TRUE);CHECKGLERROR
1064         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1065 }
1066
1067 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1068 {
1069         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1070         {
1071                 double glmatrix[16];
1072                 backend_modelmatrix = *matrix;
1073                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
1074                 Matrix4x4_ToArrayDoubleGL(&backend_modelviewmatrix, glmatrix);
1075                 CHECKGLERROR
1076                 qglLoadMatrixd(glmatrix);CHECKGLERROR
1077         }
1078 }
1079
1080 void R_Mesh_VertexPointer(const float *vertex3f)
1081 {
1082         if (gl_state.pointer_vertex != vertex3f)
1083         {
1084                 gl_state.pointer_vertex = vertex3f;
1085                 CHECKGLERROR
1086                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), gl_state.pointer_vertex);
1087                 CHECKGLERROR
1088         }
1089 }
1090
1091 void R_Mesh_ColorPointer(const float *color4f)
1092 {
1093         if (gl_state.pointer_color != color4f)
1094         {
1095                 CHECKGLERROR
1096                 if (!gl_state.pointer_color)
1097                 {
1098                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1099                 }
1100                 else if (!color4f)
1101                 {
1102                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1103                         // when color array is on the glColor gets trashed, set it again
1104                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1105                 }
1106                 gl_state.pointer_color = color4f;
1107                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), gl_state.pointer_color);CHECKGLERROR
1108         }
1109 }
1110
1111 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord)
1112 {
1113         gltextureunit_t *unit = gl_state.units + unitnum;
1114         // update array settings
1115         CHECKGLERROR
1116         if (texcoord)
1117         {
1118                 // texcoord array
1119                 if (unit->pointer_texcoord != texcoord || unit->arraycomponents != numcomponents)
1120                 {
1121                         unit->pointer_texcoord = texcoord;
1122                         unit->arraycomponents = numcomponents;
1123                         GL_ClientActiveTexture(unitnum);
1124                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, unit->pointer_texcoord);CHECKGLERROR
1125                 }
1126                 // texture array unit is enabled, enable the array
1127                 if (!unit->arrayenabled)
1128                 {
1129                         unit->arrayenabled = true;
1130                         GL_ClientActiveTexture(unitnum);
1131                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1132                 }
1133         }
1134         else
1135         {
1136                 // texture array unit is disabled, disable the array
1137                 if (unit->arrayenabled)
1138                 {
1139                         unit->arrayenabled = false;
1140                         GL_ClientActiveTexture(unitnum);
1141                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1142                 }
1143         }
1144 }
1145
1146 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
1147 {
1148         gltextureunit_t *unit = gl_state.units + unitnum;
1149         if (unitnum >= backendimageunits)
1150                 return;
1151         // update 1d texture binding
1152         if (unit->t1d != tex1d)
1153         {
1154                 GL_ActiveTexture(unitnum);
1155                 if (unitnum < backendunits)
1156                 {
1157                         if (tex1d)
1158                         {
1159                                 if (unit->t1d == 0)
1160                                 {
1161                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1162                                 }
1163                         }
1164                         else
1165                         {
1166                                 if (unit->t1d)
1167                                 {
1168                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1169                                 }
1170                         }
1171                 }
1172                 unit->t1d = tex1d;
1173                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1174         }
1175         // update 2d texture binding
1176         if (unit->t2d != tex2d)
1177         {
1178                 GL_ActiveTexture(unitnum);
1179                 if (unitnum < backendunits)
1180                 {
1181                         if (tex2d)
1182                         {
1183                                 if (unit->t2d == 0)
1184                                 {
1185                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1186                                 }
1187                         }
1188                         else
1189                         {
1190                                 if (unit->t2d)
1191                                 {
1192                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1193                                 }
1194                         }
1195                 }
1196                 unit->t2d = tex2d;
1197                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1198         }
1199         // update 3d texture binding
1200         if (unit->t3d != tex3d)
1201         {
1202                 GL_ActiveTexture(unitnum);
1203                 if (unitnum < backendunits)
1204                 {
1205                         if (tex3d)
1206                         {
1207                                 if (unit->t3d == 0)
1208                                 {
1209                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1210                                 }
1211                         }
1212                         else
1213                         {
1214                                 if (unit->t3d)
1215                                 {
1216                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1217                                 }
1218                         }
1219                 }
1220                 unit->t3d = tex3d;
1221                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1222         }
1223         // update cubemap texture binding
1224         if (unit->tcubemap != texcubemap)
1225         {
1226                 GL_ActiveTexture(unitnum);
1227                 if (unitnum < backendunits)
1228                 {
1229                         if (texcubemap)
1230                         {
1231                                 if (unit->tcubemap == 0)
1232                                 {
1233                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1234                                 }
1235                         }
1236                         else
1237                         {
1238                                 if (unit->tcubemap)
1239                                 {
1240                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1241                                 }
1242                         }
1243                 }
1244                 unit->tcubemap = texcubemap;
1245                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1246         }
1247 }
1248
1249 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1250 {
1251         gltextureunit_t *unit = gl_state.units + unitnum;
1252         if (unitnum >= backendimageunits)
1253                 return;
1254         // update 1d texture binding
1255         if (unit->t1d != texnum)
1256         {
1257                 GL_ActiveTexture(unitnum);
1258                 if (unitnum < backendunits)
1259                 {
1260                         if (texnum)
1261                         {
1262                                 if (unit->t1d == 0)
1263                                 {
1264                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1265                                 }
1266                         }
1267                         else
1268                         {
1269                                 if (unit->t1d)
1270                                 {
1271                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1272                                 }
1273                         }
1274                 }
1275                 unit->t1d = texnum;
1276                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1277         }
1278         // update 2d texture binding
1279         if (unit->t2d)
1280         {
1281                 GL_ActiveTexture(unitnum);
1282                 if (unitnum < backendunits)
1283                 {
1284                         if (unit->t2d)
1285                         {
1286                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1287                         }
1288                 }
1289                 unit->t2d = 0;
1290                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1291         }
1292         // update 3d texture binding
1293         if (unit->t3d)
1294         {
1295                 GL_ActiveTexture(unitnum);
1296                 if (unitnum < backendunits)
1297                 {
1298                         if (unit->t3d)
1299                         {
1300                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1301                         }
1302                 }
1303                 unit->t3d = 0;
1304                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1305         }
1306         // update cubemap texture binding
1307         if (unit->tcubemap)
1308         {
1309                 GL_ActiveTexture(unitnum);
1310                 if (unitnum < backendunits)
1311                 {
1312                         if (unit->tcubemap)
1313                         {
1314                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1315                         }
1316                 }
1317                 unit->tcubemap = 0;
1318                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1319         }
1320 }
1321
1322 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1323 {
1324         gltextureunit_t *unit = gl_state.units + unitnum;
1325         if (unitnum >= backendimageunits)
1326                 return;
1327         // update 1d texture binding
1328         if (unit->t1d)
1329         {
1330                 GL_ActiveTexture(unitnum);
1331                 if (unitnum < backendunits)
1332                 {
1333                         if (unit->t1d)
1334                         {
1335                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1336                         }
1337                 }
1338                 unit->t1d = 0;
1339                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1340         }
1341         // update 2d texture binding
1342         if (unit->t2d != texnum)
1343         {
1344                 GL_ActiveTexture(unitnum);
1345                 if (unitnum < backendunits)
1346                 {
1347                         if (texnum)
1348                         {
1349                                 if (unit->t2d == 0)
1350                                 {
1351                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1352                                 }
1353                         }
1354                         else
1355                         {
1356                                 if (unit->t2d)
1357                                 {
1358                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1359                                 }
1360                         }
1361                 }
1362                 unit->t2d = texnum;
1363                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1364         }
1365         // update 3d texture binding
1366         if (unit->t3d)
1367         {
1368                 GL_ActiveTexture(unitnum);
1369                 if (unitnum < backendunits)
1370                 {
1371                         if (unit->t3d)
1372                         {
1373                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1374                         }
1375                 }
1376                 unit->t3d = 0;
1377                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1378         }
1379         // update cubemap texture binding
1380         if (unit->tcubemap != 0)
1381         {
1382                 GL_ActiveTexture(unitnum);
1383                 if (unitnum < backendunits)
1384                 {
1385                         if (unit->tcubemap)
1386                         {
1387                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1388                         }
1389                 }
1390                 unit->tcubemap = 0;
1391                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1392         }
1393 }
1394
1395 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1396 {
1397         gltextureunit_t *unit = gl_state.units + unitnum;
1398         if (unitnum >= backendimageunits)
1399                 return;
1400         // update 1d texture binding
1401         if (unit->t1d)
1402         {
1403                 GL_ActiveTexture(unitnum);
1404                 if (unitnum < backendunits)
1405                 {
1406                         if (unit->t1d)
1407                         {
1408                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1409                         }
1410                 }
1411                 unit->t1d = 0;
1412                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1413         }
1414         // update 2d texture binding
1415         if (unit->t2d)
1416         {
1417                 GL_ActiveTexture(unitnum);
1418                 if (unitnum < backendunits)
1419                 {
1420                         if (unit->t2d)
1421                         {
1422                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1423                         }
1424                 }
1425                 unit->t2d = 0;
1426                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1427         }
1428         // update 3d texture binding
1429         if (unit->t3d != texnum)
1430         {
1431                 GL_ActiveTexture(unitnum);
1432                 if (unitnum < backendunits)
1433                 {
1434                         if (texnum)
1435                         {
1436                                 if (unit->t3d == 0)
1437                                 {
1438                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1439                                 }
1440                         }
1441                         else
1442                         {
1443                                 if (unit->t3d)
1444                                 {
1445                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1446                                 }
1447                         }
1448                 }
1449                 unit->t3d = texnum;
1450                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1451         }
1452         // update cubemap texture binding
1453         if (unit->tcubemap != 0)
1454         {
1455                 GL_ActiveTexture(unitnum);
1456                 if (unitnum < backendunits)
1457                 {
1458                         if (unit->tcubemap)
1459                         {
1460                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1461                         }
1462                 }
1463                 unit->tcubemap = 0;
1464                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1465         }
1466 }
1467
1468 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1469 {
1470         gltextureunit_t *unit = gl_state.units + unitnum;
1471         if (unitnum >= backendimageunits)
1472                 return;
1473         // update 1d texture binding
1474         if (unit->t1d)
1475         {
1476                 GL_ActiveTexture(unitnum);
1477                 if (unitnum < backendunits)
1478                 {
1479                         if (unit->t1d)
1480                         {
1481                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1482                         }
1483                 }
1484                 unit->t1d = 0;
1485                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1486         }
1487         // update 2d texture binding
1488         if (unit->t2d)
1489         {
1490                 GL_ActiveTexture(unitnum);
1491                 if (unitnum < backendunits)
1492                 {
1493                         if (unit->t2d)
1494                         {
1495                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1496                         }
1497                 }
1498                 unit->t2d = 0;
1499                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1500         }
1501         // update 3d texture binding
1502         if (unit->t3d)
1503         {
1504                 GL_ActiveTexture(unitnum);
1505                 if (unitnum < backendunits)
1506                 {
1507                         if (unit->t3d)
1508                         {
1509                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1510                         }
1511                 }
1512                 unit->t3d = 0;
1513                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1514         }
1515         // update cubemap texture binding
1516         if (unit->tcubemap != texnum)
1517         {
1518                 GL_ActiveTexture(unitnum);
1519                 if (unitnum < backendunits)
1520                 {
1521                         if (texnum)
1522                         {
1523                                 if (unit->tcubemap == 0)
1524                                 {
1525                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1526                                 }
1527                         }
1528                         else
1529                         {
1530                                 if (unit->tcubemap)
1531                                 {
1532                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1533                                 }
1534                         }
1535                 }
1536                 unit->tcubemap = texnum;
1537                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1538         }
1539 }
1540
1541 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1542 {
1543         gltextureunit_t *unit = gl_state.units + unitnum;
1544         if (matrix->m[3][3])
1545         {
1546                 // texmatrix specified, check if it is different
1547                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1548                 {
1549                         double glmatrix[16];
1550                         unit->texmatrixenabled = true;
1551                         unit->matrix = *matrix;
1552                         CHECKGLERROR
1553                         Matrix4x4_ToArrayDoubleGL(&unit->matrix, glmatrix);
1554                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1555                         GL_ActiveTexture(unitnum);
1556                         qglLoadMatrixd(glmatrix);CHECKGLERROR
1557                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1558                 }
1559         }
1560         else
1561         {
1562                 // no texmatrix specified, revert to identity
1563                 if (unit->texmatrixenabled)
1564                 {
1565                         unit->texmatrixenabled = false;
1566                         CHECKGLERROR
1567                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1568                         GL_ActiveTexture(unitnum);
1569                         qglLoadIdentity();CHECKGLERROR
1570                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1571                 }
1572         }
1573 }
1574
1575 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1576 {
1577         gltextureunit_t *unit = gl_state.units + unitnum;
1578         CHECKGLERROR
1579         if (gl_combine.integer)
1580         {
1581                 // GL_ARB_texture_env_combine
1582                 if (!combinergb)
1583                         combinergb = GL_MODULATE;
1584                 if (!combinealpha)
1585                         combinealpha = GL_MODULATE;
1586                 if (!rgbscale)
1587                         rgbscale = 1;
1588                 if (!alphascale)
1589                         alphascale = 1;
1590                 if (unit->combinergb != combinergb)
1591                 {
1592                         unit->combinergb = combinergb;
1593                         GL_ActiveTexture(unitnum);
1594                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1595                 }
1596                 if (unit->combinealpha != combinealpha)
1597                 {
1598                         unit->combinealpha = combinealpha;
1599                         GL_ActiveTexture(unitnum);
1600                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1601                 }
1602                 if (unit->rgbscale != rgbscale)
1603                 {
1604                         GL_ActiveTexture(unitnum);
1605                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
1606                 }
1607                 if (unit->alphascale != alphascale)
1608                 {
1609                         GL_ActiveTexture(unitnum);
1610                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
1611                 }
1612         }
1613         else
1614         {
1615                 // normal GL texenv
1616                 if (!combinergb)
1617                         combinergb = GL_MODULATE;
1618                 if (unit->combinergb != combinergb)
1619                 {
1620                         unit->combinergb = combinergb;
1621                         GL_ActiveTexture(unitnum);
1622                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1623                 }
1624         }
1625 }
1626
1627 void R_Mesh_TextureState(const rmeshstate_t *m)
1628 {
1629         unsigned int i;
1630
1631         BACKENDACTIVECHECK
1632
1633         CHECKGLERROR
1634         if (gl_backend_rebindtextures)
1635         {
1636                 gl_backend_rebindtextures = false;
1637                 GL_SetupTextureState();
1638                 CHECKGLERROR
1639         }
1640
1641         for (i = 0;i < backendimageunits;i++)
1642                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
1643         for (i = 0;i < backendarrayunits;i++)
1644         {
1645                 if (m->pointer_texcoord3f[i])
1646                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i]);
1647                 else
1648                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i]);
1649         }
1650         for (i = 0;i < backendunits;i++)
1651         {
1652                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
1653                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
1654         }
1655         CHECKGLERROR
1656 }
1657
1658 void R_Mesh_ResetTextureState(void)
1659 {
1660         unsigned int unitnum;
1661
1662         BACKENDACTIVECHECK
1663
1664         CHECKGLERROR
1665         if (gl_backend_rebindtextures)
1666         {
1667                 gl_backend_rebindtextures = false;
1668                 GL_SetupTextureState();
1669                 CHECKGLERROR
1670         }
1671
1672         for (unitnum = 0;unitnum < backendimageunits;unitnum++)
1673         {
1674                 gltextureunit_t *unit = gl_state.units + unitnum;
1675                 // update 1d texture binding
1676                 if (unit->t1d)
1677                 {
1678                         GL_ActiveTexture(unitnum);
1679                         if (unitnum < backendunits)
1680                         {
1681                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1682                         }
1683                         unit->t1d = 0;
1684                         qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1685                 }
1686                 // update 2d texture binding
1687                 if (unit->t2d)
1688                 {
1689                         GL_ActiveTexture(unitnum);
1690                         if (unitnum < backendunits)
1691                         {
1692                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1693                         }
1694                         unit->t2d = 0;
1695                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1696                 }
1697                 // update 3d texture binding
1698                 if (unit->t3d)
1699                 {
1700                         GL_ActiveTexture(unitnum);
1701                         if (unitnum < backendunits)
1702                         {
1703                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1704                         }
1705                         unit->t3d = 0;
1706                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1707                 }
1708                 // update cubemap texture binding
1709                 if (unit->tcubemap)
1710                 {
1711                         GL_ActiveTexture(unitnum);
1712                         if (unitnum < backendunits)
1713                         {
1714                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1715                         }
1716                         unit->tcubemap = 0;
1717                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1718                 }
1719         }
1720         for (unitnum = 0;unitnum < backendarrayunits;unitnum++)
1721         {
1722                 gltextureunit_t *unit = gl_state.units + unitnum;
1723                 // texture array unit is disabled, disable the array
1724                 if (unit->arrayenabled)
1725                 {
1726                         unit->arrayenabled = false;
1727                         GL_ClientActiveTexture(unitnum);
1728                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1729                 }
1730         }
1731         for (unitnum = 0;unitnum < backendunits;unitnum++)
1732         {
1733                 gltextureunit_t *unit = gl_state.units + unitnum;
1734                 // no texmatrix specified, revert to identity
1735                 if (unit->texmatrixenabled)
1736                 {
1737                         unit->texmatrixenabled = false;
1738                         CHECKGLERROR
1739                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1740                         GL_ActiveTexture(unitnum);
1741                         qglLoadIdentity();CHECKGLERROR
1742                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1743                 }
1744                 if (gl_combine.integer)
1745                 {
1746                         // GL_ARB_texture_env_combine
1747                         if (unit->combinergb != GL_MODULATE)
1748                         {
1749                                 unit->combinergb = GL_MODULATE;
1750                                 GL_ActiveTexture(unitnum);
1751                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1752                         }
1753                         if (unit->combinealpha != GL_MODULATE)
1754                         {
1755                                 unit->combinealpha = GL_MODULATE;
1756                                 GL_ActiveTexture(unitnum);
1757                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1758                         }
1759                         if (unit->rgbscale != 1)
1760                         {
1761                                 GL_ActiveTexture(unitnum);
1762                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = 1));CHECKGLERROR
1763                         }
1764                         if (unit->alphascale != 1)
1765                         {
1766                                 GL_ActiveTexture(unitnum);
1767                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = 1));CHECKGLERROR
1768                         }
1769                 }
1770                 else
1771                 {
1772                         // normal GL texenv
1773                         if (unit->combinergb != GL_MODULATE)
1774                         {
1775                                 unit->combinergb = GL_MODULATE;
1776                                 GL_ActiveTexture(unitnum);
1777                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1778                         }
1779                 }
1780         }
1781 }
1782
1783 void R_Mesh_Draw_ShowTris(int firstvertex, int numvertices, int numtriangles, const int *elements)
1784 {
1785         CHECKGLERROR
1786         qglBegin(GL_LINES);
1787         for (;numtriangles;numtriangles--, elements += 3)
1788         {
1789                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1790                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1791                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1792         }
1793         qglEnd();
1794         CHECKGLERROR
1795 }