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