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