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