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