]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
increase _snd_mixahead to 0.15 to fix crackling sound on Vista
[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_mesh_prefer_short_elements = {0, "gl_mesh_prefer_short_elements", "1", "use GL_UNSIGNED_SHORT element arrays instead of GL_UNSIGNED_INT"};
9 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
10 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
11
12 cvar_t r_render = {0, "r_render", "1", "enables rendering 3D views (you want this on!)"};
13 cvar_t r_renderview = {0, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
14 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
15 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
16 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
17 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"};
18 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"};
19 cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"};
20 cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"};
21
22 cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
23 qboolean v_flipped_state = false;
24
25 int gl_maxdrawrangeelementsvertices;
26 int gl_maxdrawrangeelementsindices;
27
28 #ifdef DEBUGGL
29 int errornumber = 0;
30
31 void GL_PrintError(int errornumber, char *filename, int linenumber)
32 {
33         switch(errornumber)
34         {
35 #ifdef GL_INVALID_ENUM
36         case GL_INVALID_ENUM:
37                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
38                 break;
39 #endif
40 #ifdef GL_INVALID_VALUE
41         case GL_INVALID_VALUE:
42                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
43                 break;
44 #endif
45 #ifdef GL_INVALID_OPERATION
46         case GL_INVALID_OPERATION:
47                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
48                 break;
49 #endif
50 #ifdef GL_STACK_OVERFLOW
51         case GL_STACK_OVERFLOW:
52                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
53                 break;
54 #endif
55 #ifdef GL_STACK_UNDERFLOW
56         case GL_STACK_UNDERFLOW:
57                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
58                 break;
59 #endif
60 #ifdef GL_OUT_OF_MEMORY
61         case GL_OUT_OF_MEMORY:
62                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
63                 break;
64 #endif
65 #ifdef GL_TABLE_TOO_LARGE
66         case GL_TABLE_TOO_LARGE:
67                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
68                 break;
69 #endif
70 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
71         case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
72                 Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber);
73                 break;
74 #endif
75         default:
76                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
77                 break;
78         }
79 }
80 #endif
81
82 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active");
83
84 void SCR_ScreenShot_f (void);
85
86 typedef struct gl_bufferobjectinfo_s
87 {
88         int target;
89         int object;
90         size_t size;
91         char name[MAX_QPATH];
92 }
93 gl_bufferobjectinfo_t;
94
95 typedef struct gltextureunit_s
96 {
97         const void *pointer_texcoord;
98         size_t pointer_texcoord_offset;
99         int pointer_texcoord_buffer;
100         int t2d, t3d, tcubemap, trectangle;
101         int arrayenabled;
102         unsigned int arraycomponents;
103         int rgbscale, alphascale;
104         int combinergb, combinealpha;
105         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
106         int texmatrixenabled;
107         matrix4x4_t matrix;
108 }
109 gltextureunit_t;
110
111 typedef struct gl_state_s
112 {
113         int cullface;
114         int cullfaceenable;
115         int blendfunc1;
116         int blendfunc2;
117         int blend;
118         GLboolean depthmask;
119         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
120         int depthtest;
121         float depthrange[2];
122         float polygonoffset[2];
123         int alphatest;
124         int scissortest;
125         unsigned int unit;
126         unsigned int clientunit;
127         gltextureunit_t units[MAX_TEXTUREUNITS];
128         float color4f[4];
129         int lockrange_first;
130         int lockrange_count;
131         int vertexbufferobject;
132         int elementbufferobject;
133         qboolean pointer_color_enabled;
134         const void *pointer_vertex;
135         const void *pointer_color;
136         size_t pointer_vertex_offset;
137         size_t pointer_color_offset;
138         int pointer_vertex_buffer;
139         int pointer_color_buffer;
140 }
141 gl_state_t;
142
143 static gl_state_t gl_state;
144
145 static memexpandablearray_t gl_bufferobjectinfoarray;
146
147 static r_viewport_t backend_viewport;
148 static matrix4x4_t backend_modelmatrix;
149 static matrix4x4_t backend_modelviewmatrix;
150
151 static unsigned int backendactive;
152
153 /*
154 note: here's strip order for a terrain row:
155 0--1--2--3--4
156 |\ |\ |\ |\ |
157 | \| \| \| \|
158 A--B--C--D--E
159 clockwise
160
161 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
162
163 *elements++ = i + row;
164 *elements++ = i;
165 *elements++ = i + row + 1;
166 *elements++ = i;
167 *elements++ = i + 1;
168 *elements++ = i + row + 1;
169
170
171 for (y = 0;y < rows - 1;y++)
172 {
173         for (x = 0;x < columns - 1;x++)
174         {
175                 i = y * rows + x;
176                 *elements++ = i + columns;
177                 *elements++ = i;
178                 *elements++ = i + columns + 1;
179                 *elements++ = i;
180                 *elements++ = i + 1;
181                 *elements++ = i + columns + 1;
182         }
183 }
184
185 alternative:
186 0--1--2--3--4
187 | /| /|\ | /|
188 |/ |/ | \|/ |
189 A--B--C--D--E
190 counterclockwise
191
192 for (y = 0;y < rows - 1;y++)
193 {
194         for (x = 0;x < columns - 1;x++)
195         {
196                 i = y * rows + x;
197                 *elements++ = i;
198                 *elements++ = i + columns;
199                 *elements++ = i + columns + 1;
200                 *elements++ = i + columns;
201                 *elements++ = i + columns + 1;
202                 *elements++ = i + 1;
203         }
204 }
205 */
206
207 int polygonelement3i[(POLYGONELEMENTS_MAXPOINTS-2)*3];
208 unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3];
209 int quadelement3i[QUADELEMENTS_MAXQUADS*6];
210 unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6];
211
212 void GL_VBOStats_f(void)
213 {
214         GL_Mesh_ListVBOs(true);
215 }
216
217 static void gl_backend_start(void)
218 {
219         CHECKGLERROR
220
221         if (qglDrawRangeElements != NULL)
222         {
223                 CHECKGLERROR
224                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
225                 CHECKGLERROR
226                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
227                 CHECKGLERROR
228                 Con_DPrintf("GL_MAX_ELEMENTS_VERTICES = %i\nGL_MAX_ELEMENTS_INDICES = %i\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
229         }
230
231         if (gl_support_fragment_shader)
232         {
233                 Con_DPrintf("GLSL shader support detected: texture units = %i texenv, %i image, %i array\n", vid.texunits, vid.teximageunits, vid.texarrayunits);
234                 vid.teximageunits = bound(1, vid.teximageunits, MAX_TEXTUREUNITS);
235                 vid.texarrayunits = bound(1, vid.texarrayunits, MAX_TEXTUREUNITS);
236         }
237         else
238                 Con_DPrintf("GL_MAX_TEXTUREUNITS = %i\n", vid.texunits);
239
240         Mem_ExpandableArray_NewArray(&gl_bufferobjectinfoarray, r_main_mempool, sizeof(gl_bufferobjectinfo_t), 128);
241
242         Con_DPrintf("OpenGL backend started.\n");
243
244         CHECKGLERROR
245
246         backendactive = true;
247 }
248
249 static void gl_backend_shutdown(void)
250 {
251         backendactive = false;
252
253         Con_DPrint("OpenGL Backend shutting down\n");
254
255         Mem_ExpandableArray_FreeArray(&gl_bufferobjectinfoarray);
256 }
257
258 static void gl_backend_newmap(void)
259 {
260 }
261
262 void gl_backend_init(void)
263 {
264         int i;
265
266         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
267         {
268                 polygonelement3s[i * 3 + 0] = 0;
269                 polygonelement3s[i * 3 + 1] = i + 1;
270                 polygonelement3s[i * 3 + 2] = i + 2;
271         }
272         // elements for rendering a series of quads as triangles
273         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
274         {
275                 quadelement3s[i * 6 + 0] = i * 4;
276                 quadelement3s[i * 6 + 1] = i * 4 + 1;
277                 quadelement3s[i * 6 + 2] = i * 4 + 2;
278                 quadelement3s[i * 6 + 3] = i * 4;
279                 quadelement3s[i * 6 + 4] = i * 4 + 2;
280                 quadelement3s[i * 6 + 5] = i * 4 + 3;
281         }
282
283         for (i = 0;i < (POLYGONELEMENTS_MAXPOINTS - 2)*3;i++)
284                 polygonelement3i[i] = polygonelement3s[i];
285         for (i = 0;i < QUADELEMENTS_MAXQUADS*3;i++)
286                 quadelement3i[i] = quadelement3s[i];
287
288         Cvar_RegisterVariable(&r_render);
289         Cvar_RegisterVariable(&r_renderview);
290         Cvar_RegisterVariable(&r_waterwarp);
291         Cvar_RegisterVariable(&gl_polyblend);
292         Cvar_RegisterVariable(&v_flipped);
293         Cvar_RegisterVariable(&gl_dither);
294         Cvar_RegisterVariable(&gl_lockarrays);
295         Cvar_RegisterVariable(&gl_lockarrays_minimumvertices);
296         Cvar_RegisterVariable(&gl_vbo);
297         Cvar_RegisterVariable(&gl_paranoid);
298         Cvar_RegisterVariable(&gl_printcheckerror);
299
300         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
301         Cvar_RegisterVariable(&gl_mesh_testarrayelement);
302         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
303         Cvar_RegisterVariable(&gl_mesh_prefer_short_elements);
304
305         Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them");
306
307         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
308 }
309
310 void GL_SetMirrorState(qboolean state);
311
312 void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out)
313 {
314         vec4_t temp;
315         float iw;
316         Matrix4x4_Transform4 (&v->viewmatrix, in, temp);
317         Matrix4x4_Transform4 (&v->projectmatrix, temp, out);
318         iw = 1.0f / out[3];
319         out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f;
320         out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f;
321         out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f;
322 }
323
324 static void R_Viewport_ApplyNearClipPlane(r_viewport_t *v, double normalx, double normaly, double normalz, double dist)
325 {
326         double q[4];
327         double d;
328         float clipPlane[4], v3[3], v4[3];
329         float normal[3];
330
331         // This is inspired by Oblique Depth Projection from http://www.terathon.com/code/oblique.php
332
333         VectorSet(normal, normalx, normaly, normalz);
334         Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane);
335         VectorScale(normal, dist, v3);
336         Matrix4x4_Transform(&v->viewmatrix, v3, v4);
337         // FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique
338         clipPlane[3] = -DotProduct(v4, clipPlane);
339
340 #if 0
341 {
342         // testing code for comparing results
343         float clipPlane2[4];
344         VectorCopy4(clipPlane, clipPlane2);
345         R_Mesh_Matrix(&identitymatrix);
346         VectorSet(q, normal[0], normal[1], normal[2], -dist);
347         qglClipPlane(GL_CLIP_PLANE0, q);
348         qglGetClipPlane(GL_CLIP_PLANE0, q);
349         VectorCopy4(q, clipPlane);
350 }
351 #endif
352
353         // Calculate the clip-space corner point opposite the clipping plane
354         // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
355         // transform it into camera space by multiplying it
356         // by the inverse of the projection matrix
357         q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + v->m[8]) / v->m[0];
358         q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + v->m[9]) / v->m[5];
359         q[2] = -1.0f;
360         q[3] = (1.0f + v->m[10]) / v->m[14];
361
362         // Calculate the scaled plane vector
363         d = 2.0f / DotProduct4(clipPlane, q);
364
365         // Replace the third row of the projection matrix
366         v->m[2] = clipPlane[0] * d;
367         v->m[6] = clipPlane[1] * d;
368         v->m[10] = clipPlane[2] * d + 1.0f;
369         v->m[14] = clipPlane[3] * d;
370 }
371
372 void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double x1, double y1, double x2, double y2, double nearclip, double farclip, const double *nearplane)
373 {
374         float left = x1, right = x2, bottom = y2, top = y1, zNear = nearclip, zFar = farclip;
375         memset(v, 0, sizeof(*v));
376         v->type = R_VIEWPORTTYPE_ORTHO;
377         v->cameramatrix = *cameramatrix;
378         v->x = x;
379         v->y = y;
380         v->z = 0;
381         v->width = width;
382         v->height = height;
383         v->depth = 1;
384         v->m[0]  = 2/(right - left);
385         v->m[5]  = 2/(top - bottom);
386         v->m[10] = -2/(zFar - zNear);
387         v->m[12] = - (right + left)/(right - left);
388         v->m[13] = - (top + bottom)/(top - bottom);
389         v->m[14] = - (zFar + zNear)/(zFar - zNear);
390         v->m[15] = 1;
391
392         Matrix4x4_Invert_Full(&v->viewmatrix, &v->cameramatrix);
393         Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
394
395         if (nearplane)
396                 R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
397
398 #if 0
399         {
400                 vec4_t test1;
401                 vec4_t test2;
402                 Vector4Set(test1, (x1+x2)*0.5f, (y1+y2)*0.5f, 0.0f, 1.0f);
403                 R_Viewport_TransformToScreen(v, test1, test2);
404                 Con_Printf("%f %f %f -> %f %f %f\n", test1[0], test1[1], test1[2], test2[0], test2[1], test2[2]);
405         }
406 #endif
407 }
408
409 void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double frustumx, double frustumy, double nearclip, double farclip, const double *nearplane)
410 {
411         matrix4x4_t tempmatrix, basematrix;
412         memset(v, 0, sizeof(*v));
413
414         if(v_flipped.integer)
415                 frustumx = -frustumx;
416
417         v->type = R_VIEWPORTTYPE_PERSPECTIVE;
418         v->cameramatrix = *cameramatrix;
419         v->x = x;
420         v->y = y;
421         v->z = 0;
422         v->width = width;
423         v->height = height;
424         v->depth = 1;
425         v->m[0]  = 1.0 / frustumx;
426         v->m[5]  = 1.0 / frustumy;
427         v->m[10] = -(farclip + nearclip) / (farclip - nearclip);
428         v->m[11] = -1;
429         v->m[14] = -2 * nearclip * farclip / (farclip - nearclip);
430
431         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
432         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
433         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
434         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
435
436         Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
437
438         if (nearplane)
439                 R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
440 }
441
442 void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double frustumx, double frustumy, double nearclip, const double *nearplane)
443 {
444         matrix4x4_t tempmatrix, basematrix;
445         const double nudge = 1.0 - 1.0 / (1<<23);
446         memset(v, 0, sizeof(*v));
447
448         if(v_flipped.integer)
449                 frustumx = -frustumx;
450
451         v->type = R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP;
452         v->cameramatrix = *cameramatrix;
453         v->x = x;
454         v->y = y;
455         v->z = 0;
456         v->width = width;
457         v->height = height;
458         v->depth = 1;
459         v->m[ 0] = 1.0 / frustumx;
460         v->m[ 5] = 1.0 / frustumy;
461         v->m[10] = -nudge;
462         v->m[11] = -1;
463         v->m[14] = -2 * nearclip * nudge;
464
465         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
466         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
467         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
468         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
469
470         Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
471
472         if (nearplane)
473                 R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
474 }
475
476 float cubeviewmatrix[6][16] =
477 {
478     // standard cubemap projections
479     { // +X
480          0, 0,-1, 0,
481          0,-1, 0, 0,
482         -1, 0, 0, 0,
483          0, 0, 0, 1,
484     },
485     { // -X
486          0, 0, 1, 0,
487          0,-1, 0, 0,
488          1, 0, 0, 0,
489          0, 0, 0, 1,
490     },
491     { // +Y
492          1, 0, 0, 0,
493          0, 0,-1, 0,
494          0, 1, 0, 0,
495          0, 0, 0, 1,
496     },
497     { // -Y
498          1, 0, 0, 0,
499          0, 0, 1, 0,
500          0,-1, 0, 0,
501          0, 0, 0, 1,
502     },
503     { // +Z
504          1, 0, 0, 0,
505          0,-1, 0, 0,
506          0, 0,-1, 0,
507          0, 0, 0, 1,
508     },
509     { // -Z
510         -1, 0, 0, 0,
511          0,-1, 0, 0,
512          0, 0, 1, 0,
513          0, 0, 0, 1,
514     },
515 };
516 float rectviewmatrix[6][16] =
517 {
518     // sign-preserving cubemap projections
519     { // +X
520          0, 0,-1, 0,
521          0, 1, 0, 0,
522          1, 0, 0, 0,
523          0, 0, 0, 1,
524     },
525     { // -X
526          0, 0, 1, 0,
527          0, 1, 0, 0,
528          1, 0, 0, 0,
529          0, 0, 0, 1,
530     },
531     { // +Y
532          1, 0, 0, 0,
533          0, 0,-1, 0,
534          0, 1, 0, 0,
535          0, 0, 0, 1,
536     },
537     { // -Y
538          1, 0, 0, 0,
539          0, 0, 1, 0,
540          0, 1, 0, 0,
541          0, 0, 0, 1,
542     },
543     { // +Z
544          1, 0, 0, 0,
545          0, 1, 0, 0,
546          0, 0,-1, 0,
547          0, 0, 0, 1,
548     },
549     { // -Z
550          1, 0, 0, 0,
551          0, 1, 0, 0,
552          0, 0, 1, 0,
553          0, 0, 0, 1,
554     },
555 };
556
557 void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane)
558 {
559         matrix4x4_t tempmatrix, basematrix;
560         memset(v, 0, sizeof(*v));
561         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
562         v->cameramatrix = *cameramatrix;
563         v->width = size;
564         v->height = size;
565         v->depth = 1;
566         v->m[0] = v->m[5] = 1.0f;
567         v->m[10] = -(farclip + nearclip) / (farclip - nearclip);
568         v->m[11] = -1;
569         v->m[14] = -2 * nearclip * farclip / (farclip - nearclip);
570
571         Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]);
572         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
573         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
574         Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
575
576         if (nearplane)
577                 R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
578 }
579
580 void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane)
581 {
582         matrix4x4_t tempmatrix, basematrix;
583         memset(v, 0, sizeof(*v));
584         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
585         v->cameramatrix = *cameramatrix;
586         v->x = (side & 1) * size;
587         v->y = (side >> 1) * size;
588         v->width = size;
589         v->height = size;
590         v->depth = 1;
591         v->m[0] = v->m[5] = 1.0f * ((float)size - border) / size;
592         v->m[10] = -(farclip + nearclip) / (farclip - nearclip);
593         v->m[11] = -1;
594         v->m[14] = -2 * nearclip * farclip / (farclip - nearclip);
595
596         Matrix4x4_FromArrayFloatGL(&basematrix, rectviewmatrix[side]);
597         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
598         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
599         Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
600
601         if (nearplane)
602                 R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
603 }
604
605 void R_SetViewport(const r_viewport_t *v)
606 {
607         float glmatrix[16];
608         backend_viewport = *v;
609
610         CHECKGLERROR
611         qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
612
613         // Load the projection matrix into OpenGL
614         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
615         qglLoadMatrixd(backend_viewport.m);CHECKGLERROR
616         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
617
618         // FIXME: v_flipped_state is evil, this probably breaks somewhere
619         GL_SetMirrorState(v_flipped.integer && (v->type == R_VIEWPORTTYPE_PERSPECTIVE || v->type == R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP));
620
621         // directly force an update of the modelview matrix
622         Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewport.viewmatrix, &backend_modelmatrix);
623         Matrix4x4_ToArrayFloatGL(&backend_modelviewmatrix, glmatrix);
624         qglLoadMatrixf(glmatrix);CHECKGLERROR
625 }
626
627 void R_GetViewport(r_viewport_t *v)
628 {
629         *v = backend_viewport;
630 }
631
632 static void GL_BindVBO(int bufferobject)
633 {
634         if (gl_state.vertexbufferobject != bufferobject)
635         {
636                 gl_state.vertexbufferobject = bufferobject;
637                 CHECKGLERROR
638                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);
639                 CHECKGLERROR
640         }
641 }
642
643 static void GL_BindEBO(int bufferobject)
644 {
645         if (gl_state.elementbufferobject != bufferobject)
646         {
647                 gl_state.elementbufferobject = bufferobject;
648                 CHECKGLERROR
649                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);
650                 CHECKGLERROR
651         }
652 }
653
654 void GL_SetupTextureState(void)
655 {
656         unsigned int i;
657         gltextureunit_t *unit;
658         CHECKGLERROR
659         gl_state.unit = MAX_TEXTUREUNITS;
660         gl_state.clientunit = MAX_TEXTUREUNITS;
661         for (i = 0;i < MAX_TEXTUREUNITS;i++)
662         {
663                 unit = gl_state.units + i;
664                 unit->t2d = 0;
665                 unit->t3d = 0;
666                 unit->tcubemap = 0;
667                 unit->arrayenabled = false;
668                 unit->arraycomponents = 0;
669                 unit->pointer_texcoord = NULL;
670                 unit->pointer_texcoord_buffer = 0;
671                 unit->pointer_texcoord_offset = 0;
672                 unit->rgbscale = 1;
673                 unit->alphascale = 1;
674                 unit->combinergb = GL_MODULATE;
675                 unit->combinealpha = GL_MODULATE;
676                 unit->texmatrixenabled = false;
677                 unit->matrix = identitymatrix;
678         }
679
680         for (i = 0;i < vid.teximageunits;i++)
681         {
682                 GL_ActiveTexture(i);
683                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
684                 if (gl_texture3d)
685                 {
686                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
687                 }
688                 if (gl_texturecubemap)
689                 {
690                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
691                 }
692                 if (gl_texturerectangle)
693                 {
694                         qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
695                 }
696         }
697
698         for (i = 0;i < vid.texarrayunits;i++)
699         {
700                 GL_ClientActiveTexture(i);
701                 GL_BindVBO(0);
702                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
703                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
704         }
705
706         for (i = 0;i < vid.texunits;i++)
707         {
708                 GL_ActiveTexture(i);
709                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
710                 if (gl_texture3d)
711                 {
712                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
713                 }
714                 if (gl_texturecubemap)
715                 {
716                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
717                 }
718                 if (gl_texturerectangle)
719                 {
720                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
721                 }
722                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
723                 qglLoadIdentity();CHECKGLERROR
724                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
725                 if (gl_combine.integer)
726                 {
727                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
728                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
729                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
730                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
731                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
732                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
733                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
734                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
735                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
736                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
737                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
738                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
739                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
740                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
741                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
742                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
743                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
744                 }
745                 else
746                 {
747                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
748                 }
749                 CHECKGLERROR
750         }
751         CHECKGLERROR
752 }
753
754 void GL_Backend_ResetState(void)
755 {
756         memset(&gl_state, 0, sizeof(gl_state));
757         gl_state.depthtest = true;
758         gl_state.alphatest = false;
759         gl_state.blendfunc1 = GL_ONE;
760         gl_state.blendfunc2 = GL_ZERO;
761         gl_state.blend = false;
762         gl_state.depthmask = GL_TRUE;
763         gl_state.colormask = 15;
764         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
765         gl_state.lockrange_first = 0;
766         gl_state.lockrange_count = 0;
767         gl_state.cullface = v_flipped_state ? GL_BACK : GL_FRONT; // quake is backwards, this culls back faces
768         gl_state.cullfaceenable = true;
769         gl_state.polygonoffset[0] = 0;
770         gl_state.polygonoffset[1] = 0;
771
772         CHECKGLERROR
773
774         qglColorMask(1, 1, 1, 1);
775         qglAlphaFunc(GL_GEQUAL, 0.5);CHECKGLERROR
776         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
777         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
778         qglDisable(GL_BLEND);CHECKGLERROR
779         qglCullFace(gl_state.cullface);CHECKGLERROR
780         qglEnable(GL_CULL_FACE);CHECKGLERROR
781         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
782         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
783         qglDepthMask(gl_state.depthmask);CHECKGLERROR
784         qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
785
786         if (gl_support_arb_vertex_buffer_object)
787         {
788                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
789                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
790         }
791
792         if (gl_support_ext_framebuffer_object)
793         {
794                 qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
795                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
796         }
797
798         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
799         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
800
801         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
802         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
803
804         GL_Color(0, 0, 0, 0);
805         GL_Color(1, 1, 1, 1);
806
807         GL_SetupTextureState();
808 }
809
810 void GL_ActiveTexture(unsigned int num)
811 {
812         if (gl_state.unit != num)
813         {
814                 gl_state.unit = num;
815                 if (qglActiveTexture)
816                 {
817                         CHECKGLERROR
818                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
819                         CHECKGLERROR
820                 }
821         }
822 }
823
824 void GL_ClientActiveTexture(unsigned int num)
825 {
826         if (gl_state.clientunit != num)
827         {
828                 gl_state.clientunit = num;
829                 if (qglActiveTexture)
830                 {
831                         CHECKGLERROR
832                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
833                         CHECKGLERROR
834                 }
835         }
836 }
837
838 void GL_BlendFunc(int blendfunc1, int blendfunc2)
839 {
840         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
841         {
842                 CHECKGLERROR
843                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
844                 if (gl_state.blendfunc2 == GL_ZERO)
845                 {
846                         if (gl_state.blendfunc1 == GL_ONE)
847                         {
848                                 if (gl_state.blend)
849                                 {
850                                         gl_state.blend = 0;
851                                         qglDisable(GL_BLEND);CHECKGLERROR
852                                 }
853                         }
854                         else
855                         {
856                                 if (!gl_state.blend)
857                                 {
858                                         gl_state.blend = 1;
859                                         qglEnable(GL_BLEND);CHECKGLERROR
860                                 }
861                         }
862                 }
863                 else
864                 {
865                         if (!gl_state.blend)
866                         {
867                                 gl_state.blend = 1;
868                                 qglEnable(GL_BLEND);CHECKGLERROR
869                         }
870                 }
871         }
872 }
873
874 void GL_DepthMask(int state)
875 {
876         if (gl_state.depthmask != state)
877         {
878                 CHECKGLERROR
879                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
880         }
881 }
882
883 void GL_DepthTest(int state)
884 {
885         if (gl_state.depthtest != state)
886         {
887                 gl_state.depthtest = state;
888                 CHECKGLERROR
889                 if (gl_state.depthtest)
890                 {
891                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
892                 }
893                 else
894                 {
895                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
896                 }
897         }
898 }
899
900 void GL_DepthRange(float nearfrac, float farfrac)
901 {
902         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
903         {
904                 gl_state.depthrange[0] = nearfrac;
905                 gl_state.depthrange[1] = farfrac;
906                 qglDepthRange(nearfrac, farfrac);
907         }
908 }
909
910 void GL_PolygonOffset(float planeoffset, float depthoffset)
911 {
912         if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset)
913         {
914                 gl_state.polygonoffset[0] = planeoffset;
915                 gl_state.polygonoffset[1] = depthoffset;
916                 qglPolygonOffset(planeoffset, depthoffset);
917         }
918 }
919
920 void GL_SetMirrorState(qboolean state)
921 {
922         if(!state != !v_flipped_state)
923         {
924                 // change cull face mode!
925                 if(gl_state.cullface == GL_BACK)
926                         qglCullFace((gl_state.cullface = GL_FRONT));
927                 else if(gl_state.cullface == GL_FRONT)
928                         qglCullFace((gl_state.cullface = GL_BACK));
929         }
930         v_flipped_state = state;
931 }
932
933 void GL_CullFace(int state)
934 {
935         CHECKGLERROR
936
937         if(v_flipped_state)
938         {
939                 if(state == GL_FRONT)
940                         state = GL_BACK;
941                 else if(state == GL_BACK)
942                         state = GL_FRONT;
943         }
944
945         if (state != GL_NONE)
946         {
947                 if (!gl_state.cullfaceenable)
948                 {
949                         gl_state.cullfaceenable = true;
950                         qglEnable(GL_CULL_FACE);CHECKGLERROR
951                 }
952                 if (gl_state.cullface != state)
953                 {
954                         gl_state.cullface = state;
955                         qglCullFace(gl_state.cullface);CHECKGLERROR
956                 }
957         }
958         else
959         {
960                 if (gl_state.cullfaceenable)
961                 {
962                         gl_state.cullfaceenable = false;
963                         qglDisable(GL_CULL_FACE);CHECKGLERROR
964                 }
965         }
966 }
967
968 void GL_AlphaTest(int state)
969 {
970         if (gl_state.alphatest != state)
971         {
972                 gl_state.alphatest = state;
973                 CHECKGLERROR
974                 if (gl_state.alphatest)
975                 {
976                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
977                 }
978                 else
979                 {
980                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
981                 }
982         }
983 }
984
985 void GL_ColorMask(int r, int g, int b, int a)
986 {
987         int state = r*8 + g*4 + b*2 + a*1;
988         if (gl_state.colormask != state)
989         {
990                 gl_state.colormask = state;
991                 CHECKGLERROR
992                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
993         }
994 }
995
996 void GL_Color(float cr, float cg, float cb, float ca)
997 {
998         if (gl_state.pointer_color_enabled || gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
999         {
1000                 gl_state.color4f[0] = cr;
1001                 gl_state.color4f[1] = cg;
1002                 gl_state.color4f[2] = cb;
1003                 gl_state.color4f[3] = ca;
1004                 CHECKGLERROR
1005                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
1006                 CHECKGLERROR
1007         }
1008 }
1009
1010 void GL_LockArrays(int first, int count)
1011 {
1012         if (count < gl_lockarrays_minimumvertices.integer)
1013         {
1014                 first = 0;
1015                 count = 0;
1016         }
1017         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
1018         {
1019                 if (gl_state.lockrange_count)
1020                 {
1021                         gl_state.lockrange_count = 0;
1022                         CHECKGLERROR
1023                         qglUnlockArraysEXT();
1024                         CHECKGLERROR
1025                 }
1026                 if (count && gl_supportslockarrays && gl_lockarrays.integer)
1027                 {
1028                         gl_state.lockrange_first = first;
1029                         gl_state.lockrange_count = count;
1030                         CHECKGLERROR
1031                         qglLockArraysEXT(first, count);
1032                         CHECKGLERROR
1033                 }
1034         }
1035 }
1036
1037 void GL_Scissor (int x, int y, int width, int height)
1038 {
1039         CHECKGLERROR
1040         qglScissor(x, y,width,height);
1041         CHECKGLERROR
1042 }
1043
1044 void GL_ScissorTest(int state)
1045 {
1046         if(gl_state.scissortest == state)
1047                 return;
1048
1049         CHECKGLERROR
1050         if((gl_state.scissortest = state))
1051                 qglEnable(GL_SCISSOR_TEST);
1052         else
1053                 qglDisable(GL_SCISSOR_TEST);
1054         CHECKGLERROR
1055 }
1056
1057 void GL_Clear(int mask)
1058 {
1059         CHECKGLERROR
1060         qglClear(mask);CHECKGLERROR
1061 }
1062
1063 // called at beginning of frame
1064 void R_Mesh_Start(void)
1065 {
1066         BACKENDACTIVECHECK
1067         CHECKGLERROR
1068         if (gl_printcheckerror.integer && !gl_paranoid.integer)
1069         {
1070                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
1071                 Cvar_SetValueQuick(&gl_paranoid, 1);
1072         }
1073         GL_Backend_ResetState();
1074 }
1075
1076 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
1077 {
1078         int shaderobject;
1079         int shadercompiled;
1080         char compilelog[MAX_INPUTLINE];
1081         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
1082         if (!shaderobject)
1083                 return false;
1084         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
1085         qglCompileShaderARB(shaderobject);CHECKGLERROR
1086         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
1087         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
1088         if (compilelog[0] && developer.integer > 0)
1089         {
1090                 int i, j, pretextlines = 0;
1091                 for (i = 0;i < numstrings - 1;i++)
1092                         for (j = 0;strings[i][j];j++)
1093                                 if (strings[i][j] == '\n')
1094                                         pretextlines++;
1095                 Con_DPrintf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
1096         }
1097         if (!shadercompiled)
1098         {
1099                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
1100                 return false;
1101         }
1102         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
1103         qglDeleteObjectARB(shaderobject);CHECKGLERROR
1104         return true;
1105 }
1106
1107 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)
1108 {
1109         GLint programlinked;
1110         GLuint programobject = 0;
1111         char linklog[MAX_INPUTLINE];
1112         CHECKGLERROR
1113
1114         programobject = qglCreateProgramObjectARB();CHECKGLERROR
1115         if (!programobject)
1116                 return 0;
1117
1118         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
1119                 goto cleanup;
1120
1121 #ifdef GL_GEOMETRY_SHADER_ARB
1122         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
1123                 goto cleanup;
1124 #endif
1125
1126         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
1127                 goto cleanup;
1128
1129         qglLinkProgramARB(programobject);CHECKGLERROR
1130         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
1131         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
1132         if (linklog[0])
1133         {
1134                 Con_DPrintf("program link log:\n%s\n", linklog);
1135                 // software vertex shader is ok but software fragment shader is WAY
1136                 // too slow, fail program if so.
1137                 // NOTE: this string might be ATI specific, but that's ok because the
1138                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
1139                 // software fragment shader due to low instruction and dependent
1140                 // texture limits.
1141                 if (strstr(linklog, "fragment shader will run in software"))
1142                         programlinked = false;
1143         }
1144         if (!programlinked)
1145                 goto cleanup;
1146         return programobject;
1147 cleanup:
1148         qglDeleteObjectARB(programobject);CHECKGLERROR
1149         return 0;
1150 }
1151
1152 void GL_Backend_FreeProgram(unsigned int prog)
1153 {
1154         CHECKGLERROR
1155         qglDeleteObjectARB(prog);
1156         CHECKGLERROR
1157 }
1158
1159 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
1160 {
1161         int i;
1162         if (offset)
1163         {
1164                 for (i = 0;i < count;i++)
1165                         *out++ = *in++ + offset;
1166         }
1167         else
1168                 memcpy(out, in, sizeof(*out) * count);
1169 }
1170
1171 // renders triangles using vertices from the active arrays
1172 int paranoidblah = 0;
1173 void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int bufferobject3i, int bufferobject3s)
1174 {
1175         unsigned int numelements = numtriangles * 3;
1176         if (numvertices < 3 || numtriangles < 1)
1177         {
1178                 if (numvertices < 0 || numtriangles < 0 || developer.integer >= 100)
1179                         Con_Printf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %i, %i);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3s, bufferobject3i, bufferobject3s);
1180                 return;
1181         }
1182         if (!gl_mesh_prefer_short_elements.integer)
1183         {
1184                 if (element3i)
1185                         element3s = NULL;
1186                 if (bufferobject3i)
1187                         bufferobject3s = 0;
1188         }
1189         if (element3i)
1190                 element3i += firsttriangle * 3;
1191         if (element3s)
1192                 element3s += firsttriangle * 3;
1193         switch (gl_vbo.integer)
1194         {
1195         default:
1196         case 0:
1197         case 2:
1198                 bufferobject3i = bufferobject3s = 0;
1199                 break;
1200         case 1:
1201                 break;
1202         case 3:
1203                 if (firsttriangle)
1204                         bufferobject3i = bufferobject3s = 0;
1205                 break;
1206         }
1207         CHECKGLERROR
1208         r_refdef.stats.meshes++;
1209         r_refdef.stats.meshes_elements += numelements;
1210         if (gl_paranoid.integer)
1211         {
1212                 unsigned int i, j, size;
1213                 const int *p;
1214                 // note: there's no validation done here on buffer objects because it
1215                 // is somewhat difficult to get at the data, and gl_paranoid can be
1216                 // used without buffer objects if the need arises
1217                 // (the data could be gotten using glMapBuffer but it would be very
1218                 //  slow due to uncachable video memory reads)
1219                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
1220                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
1221                 CHECKGLERROR
1222                 if (gl_state.pointer_vertex)
1223                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
1224                                 paranoidblah += *p;
1225                 if (gl_state.pointer_color_enabled)
1226                 {
1227                         if (!qglIsEnabled(GL_COLOR_ARRAY))
1228                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
1229                         CHECKGLERROR
1230                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1231                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
1232                                         paranoidblah += *p;
1233                 }
1234                 for (i = 0;i < vid.texarrayunits;i++)
1235                 {
1236                         if (gl_state.units[i].arrayenabled)
1237                         {
1238                                 GL_ClientActiveTexture(i);
1239                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
1240                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
1241                                 CHECKGLERROR
1242                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
1243                                         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++)
1244                                                 paranoidblah += *p;
1245                         }
1246                 }
1247                 if (element3i)
1248                 {
1249                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1250                         {
1251                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
1252                                 {
1253                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
1254                                         return;
1255                                 }
1256                         }
1257                 }
1258                 if (element3s)
1259                 {
1260                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1261                         {
1262                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
1263                                 {
1264                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
1265                                         return;
1266                                 }
1267                         }
1268                 }
1269                 CHECKGLERROR
1270         }
1271         if (r_render.integer || r_refdef.draw2dstage)
1272         {
1273                 CHECKGLERROR
1274                 if (gl_mesh_testmanualfeeding.integer)
1275                 {
1276                         unsigned int i, j, element;
1277                         const GLfloat *p;
1278                         qglBegin(GL_TRIANGLES);
1279                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1280                         {
1281                                 element = element3i ? element3i[i] : element3s[i];
1282                                 for (j = 0;j < vid.texarrayunits;j++)
1283                                 {
1284                                         if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled)
1285                                         {
1286                                                 if (vid.texarrayunits > 1)
1287                                                 {
1288                                                         if (gl_state.units[j].arraycomponents == 4)
1289                                                         {
1290                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4;
1291                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
1292                                                         }
1293                                                         else if (gl_state.units[j].arraycomponents == 3)
1294                                                         {
1295                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3;
1296                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
1297                                                         }
1298                                                         else if (gl_state.units[j].arraycomponents == 2)
1299                                                         {
1300                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2;
1301                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
1302                                                         }
1303                                                         else
1304                                                         {
1305                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
1306                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
1307                                                         }
1308                                                 }
1309                                                 else
1310                                                 {
1311                                                         if (gl_state.units[j].arraycomponents == 4)
1312                                                         {
1313                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4;
1314                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
1315                                                         }
1316                                                         else if (gl_state.units[j].arraycomponents == 3)
1317                                                         {
1318                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3;
1319                                                                 qglTexCoord3f(p[0], p[1], p[2]);
1320                                                         }
1321                                                         else if (gl_state.units[j].arraycomponents == 2)
1322                                                         {
1323                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2;
1324                                                                 qglTexCoord2f(p[0], p[1]);
1325                                                         }
1326                                                         else
1327                                                         {
1328                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
1329                                                                 qglTexCoord1f(p[0]);
1330                                                         }
1331                                                 }
1332                                         }
1333                                 }
1334                                 if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1335                                 {
1336                                         p = ((const GLfloat *)(gl_state.pointer_color)) + element * 4;
1337                                         qglColor4f(p[0], p[1], p[2], p[3]);
1338                                 }
1339                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + element * 3;
1340                                 qglVertex3f(p[0], p[1], p[2]);
1341                         }
1342                         qglEnd();
1343                         CHECKGLERROR
1344                 }
1345                 else if (gl_mesh_testarrayelement.integer)
1346                 {
1347                         int i;
1348                         qglBegin(GL_TRIANGLES);
1349                         if (element3i)
1350                         {
1351                                 for (i = 0;i < numtriangles * 3;i++)
1352                                         qglArrayElement(element3i[i]);
1353                         }
1354                         else if (element3s)
1355                         {
1356                                 for (i = 0;i < numtriangles * 3;i++)
1357                                         qglArrayElement(element3s[i]);
1358                         }
1359                         qglEnd();
1360                         CHECKGLERROR
1361                 }
1362                 else if (bufferobject3s)
1363                 {
1364                         GL_BindEBO(bufferobject3s);
1365                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1366                         {
1367                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
1368                                 CHECKGLERROR
1369                         }
1370                         else
1371                         {
1372                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
1373                                 CHECKGLERROR
1374                         }
1375                 }
1376                 else if (bufferobject3i)
1377                 {
1378                         GL_BindEBO(bufferobject3i);
1379                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1380                         {
1381                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
1382                                 CHECKGLERROR
1383                         }
1384                         else
1385                         {
1386                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
1387                                 CHECKGLERROR
1388                         }
1389                 }
1390                 else if (element3s)
1391                 {
1392                         GL_BindEBO(0);
1393                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1394                         {
1395                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
1396                                 CHECKGLERROR
1397                         }
1398                         else
1399                         {
1400                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
1401                                 CHECKGLERROR
1402                         }
1403                 }
1404                 else if (element3i)
1405                 {
1406                         GL_BindEBO(0);
1407                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1408                         {
1409                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
1410                                 CHECKGLERROR
1411                         }
1412                         else
1413                         {
1414                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
1415                                 CHECKGLERROR
1416                         }
1417                 }
1418         }
1419 }
1420
1421 // restores backend state, used when done with 3D rendering
1422 void R_Mesh_Finish(void)
1423 {
1424         unsigned int i;
1425         BACKENDACTIVECHECK
1426         CHECKGLERROR
1427         GL_LockArrays(0, 0);
1428         CHECKGLERROR
1429
1430         for (i = 0;i < vid.teximageunits;i++)
1431         {
1432                 GL_ActiveTexture(i);
1433                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1434                 if (gl_texture3d)
1435                 {
1436                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1437                 }
1438                 if (gl_texturecubemap)
1439                 {
1440                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1441                 }
1442                 if (gl_texturerectangle)
1443                 {
1444                         qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
1445                 }
1446         }
1447         for (i = 0;i < vid.texarrayunits;i++)
1448         {
1449                 GL_ActiveTexture(vid.texarrayunits - 1 - i);
1450                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1451         }
1452         for (i = 0;i < vid.texunits;i++)
1453         {
1454                 GL_ActiveTexture(vid.texunits - 1 - i);
1455                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1456                 if (gl_texture3d)
1457                 {
1458                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1459                 }
1460                 if (gl_texturecubemap)
1461                 {
1462                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1463                 }
1464                 if (gl_texturerectangle)
1465                 {
1466                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1467                 }
1468                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1469                 if (gl_combine.integer)
1470                 {
1471                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1472                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1473                 }
1474         }
1475         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1476         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1477
1478         qglDisable(GL_BLEND);CHECKGLERROR
1479         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1480         qglDepthMask(GL_TRUE);CHECKGLERROR
1481         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1482 }
1483
1484 int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name)
1485 {
1486         gl_bufferobjectinfo_t *info;
1487         GLuint bufferobject;
1488
1489         if (!gl_vbo.integer)
1490                 return 0;
1491
1492         qglGenBuffersARB(1, &bufferobject);
1493         switch(target)
1494         {
1495         case GL_ELEMENT_ARRAY_BUFFER_ARB: GL_BindEBO(bufferobject);break;
1496         case GL_ARRAY_BUFFER_ARB: GL_BindVBO(bufferobject);break;
1497         default: Sys_Error("R_Mesh_CreateStaticBufferObject: unknown target type %i\n", target);return 0;
1498         }
1499         qglBufferDataARB(target, size, data, GL_STATIC_DRAW_ARB);
1500
1501         info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_AllocRecord(&gl_bufferobjectinfoarray);
1502         memset(info, 0, sizeof(*info));
1503         info->target = target;
1504         info->object = bufferobject;
1505         info->size = size;
1506         strlcpy(info->name, name, sizeof(info->name));
1507
1508         return (int)bufferobject;
1509 }
1510
1511 void R_Mesh_DestroyBufferObject(int bufferobject)
1512 {
1513         int i, endindex;
1514         gl_bufferobjectinfo_t *info;
1515
1516         qglDeleteBuffersARB(1, (GLuint *)&bufferobject);
1517
1518         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1519         for (i = 0;i < endindex;i++)
1520         {
1521                 info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1522                 if (!info)
1523                         continue;
1524                 if (info->object == bufferobject)
1525                 {
1526                         Mem_ExpandableArray_FreeRecord(&gl_bufferobjectinfoarray, (void *)info);
1527                         break;
1528                 }
1529         }
1530 }
1531
1532 void GL_Mesh_ListVBOs(qboolean printeach)
1533 {
1534         int i, endindex;
1535         size_t ebocount = 0, ebomemory = 0;
1536         size_t vbocount = 0, vbomemory = 0;
1537         gl_bufferobjectinfo_t *info;
1538         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1539         for (i = 0;i < endindex;i++)
1540         {
1541                 info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1542                 if (!info)
1543                         continue;
1544                 switch(info->target)
1545                 {
1546                 case GL_ELEMENT_ARRAY_BUFFER_ARB: ebocount++;ebomemory += info->size;if (printeach) Con_Printf("EBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break;
1547                 case GL_ARRAY_BUFFER_ARB: vbocount++;vbomemory += info->size;if (printeach) Con_Printf("VBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break;
1548                 default: Con_Printf("gl_vbostats: unknown target type %i\n", info->target);break;
1549                 }
1550         }
1551         Con_Printf("vertex buffers: %i element buffers totalling %i bytes (%.3f MB), %i vertex buffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0);
1552 }
1553
1554 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1555 {
1556         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1557         {
1558                 float glmatrix[16];
1559                 backend_modelmatrix = *matrix;
1560                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewport.viewmatrix, &backend_modelmatrix);
1561                 Matrix4x4_ToArrayFloatGL(&backend_modelviewmatrix, glmatrix);
1562                 CHECKGLERROR
1563                 qglLoadMatrixf(glmatrix);CHECKGLERROR
1564         }
1565 }
1566
1567 void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset)
1568 {
1569         if (!gl_vbo.integer || gl_mesh_testarrayelement.integer)
1570                 bufferobject = 0;
1571         if (gl_state.pointer_vertex != vertex3f || gl_state.pointer_vertex_buffer != bufferobject || gl_state.pointer_vertex_offset != bufferoffset)
1572         {
1573                 gl_state.pointer_vertex = vertex3f;
1574                 gl_state.pointer_vertex_buffer = bufferobject;
1575                 gl_state.pointer_vertex_offset = bufferoffset;
1576                 CHECKGLERROR
1577                 GL_BindVBO(bufferobject);
1578                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), bufferobject ? (void *)bufferoffset : vertex3f);CHECKGLERROR
1579         }
1580 }
1581
1582 void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset)
1583 {
1584         // note: this can not rely on bufferobject to decide whether a color array
1585         // is supplied, because surfmesh_t shares one vbo for all arrays, which
1586         // means that a valid vbo may be supplied even if there is no color array.
1587         if (color4f)
1588         {
1589                 if (!gl_vbo.integer || gl_mesh_testarrayelement.integer)
1590                         bufferobject = 0;
1591                 // caller wants color array enabled
1592                 if (!gl_state.pointer_color_enabled)
1593                 {
1594                         gl_state.pointer_color_enabled = true;
1595                         CHECKGLERROR
1596                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1597                 }
1598                 if (gl_state.pointer_color != color4f || gl_state.pointer_color_buffer != bufferobject || gl_state.pointer_color_offset != bufferoffset)
1599                 {
1600                         gl_state.pointer_color = color4f;
1601                         gl_state.pointer_color_buffer = bufferobject;
1602                         gl_state.pointer_color_offset = bufferoffset;
1603                         CHECKGLERROR
1604                         GL_BindVBO(bufferobject);
1605                         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), bufferobject ? (void *)bufferoffset : color4f);CHECKGLERROR
1606                 }
1607         }
1608         else
1609         {
1610                 // caller wants color array disabled
1611                 if (gl_state.pointer_color_enabled)
1612                 {
1613                         gl_state.pointer_color_enabled = false;
1614                         CHECKGLERROR
1615                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1616                         // when color array is on the glColor gets trashed, set it again
1617                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1618                 }
1619         }
1620 }
1621
1622 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset)
1623 {
1624         gltextureunit_t *unit = gl_state.units + unitnum;
1625         // update array settings
1626         CHECKGLERROR
1627         // note: there is no need to check bufferobject here because all cases
1628         // that involve a valid bufferobject also supply a texcoord array
1629         if (texcoord)
1630         {
1631                 if (!gl_vbo.integer || gl_mesh_testarrayelement.integer)
1632                         bufferobject = 0;
1633                 // texture array unit is enabled, enable the array
1634                 if (!unit->arrayenabled)
1635                 {
1636                         unit->arrayenabled = true;
1637                         GL_ClientActiveTexture(unitnum);
1638                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1639                 }
1640                 // texcoord array
1641                 if (unit->pointer_texcoord != texcoord || unit->pointer_texcoord_buffer != bufferobject || unit->pointer_texcoord_offset != bufferoffset || unit->arraycomponents != numcomponents)
1642                 {
1643                         unit->pointer_texcoord = texcoord;
1644                         unit->pointer_texcoord_buffer = bufferobject;
1645                         unit->pointer_texcoord_offset = bufferoffset;
1646                         unit->arraycomponents = numcomponents;
1647                         GL_ClientActiveTexture(unitnum);
1648                         GL_BindVBO(bufferobject);
1649                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, bufferobject ? (void *)bufferoffset : texcoord);CHECKGLERROR
1650                 }
1651         }
1652         else
1653         {
1654                 // texture array unit is disabled, disable the array
1655                 if (unit->arrayenabled)
1656                 {
1657                         unit->arrayenabled = false;
1658                         GL_ClientActiveTexture(unitnum);
1659                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1660                 }
1661         }
1662 }
1663
1664 void R_Mesh_TexBindAll(unsigned int unitnum, int tex2d, int tex3d, int texcubemap, int texrectangle)
1665 {
1666         gltextureunit_t *unit = gl_state.units + unitnum;
1667         if (unitnum >= vid.teximageunits)
1668                 return;
1669         // update 2d texture binding
1670         if (unit->t2d != tex2d)
1671         {
1672                 GL_ActiveTexture(unitnum);
1673                 if (unitnum < vid.texunits)
1674                 {
1675                         if (tex2d)
1676                         {
1677                                 if (unit->t2d == 0)
1678                                 {
1679                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1680                                 }
1681                         }
1682                         else
1683                         {
1684                                 if (unit->t2d)
1685                                 {
1686                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1687                                 }
1688                         }
1689                 }
1690                 unit->t2d = tex2d;
1691                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1692         }
1693         // update 3d texture binding
1694         if (unit->t3d != tex3d)
1695         {
1696                 GL_ActiveTexture(unitnum);
1697                 if (unitnum < vid.texunits)
1698                 {
1699                         if (tex3d)
1700                         {
1701                                 if (unit->t3d == 0)
1702                                 {
1703                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1704                                 }
1705                         }
1706                         else
1707                         {
1708                                 if (unit->t3d)
1709                                 {
1710                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1711                                 }
1712                         }
1713                 }
1714                 unit->t3d = tex3d;
1715                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1716         }
1717         // update cubemap texture binding
1718         if (unit->tcubemap != texcubemap)
1719         {
1720                 GL_ActiveTexture(unitnum);
1721                 if (unitnum < vid.texunits)
1722                 {
1723                         if (texcubemap)
1724                         {
1725                                 if (unit->tcubemap == 0)
1726                                 {
1727                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1728                                 }
1729                         }
1730                         else
1731                         {
1732                                 if (unit->tcubemap)
1733                                 {
1734                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1735                                 }
1736                         }
1737                 }
1738                 unit->tcubemap = texcubemap;
1739                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1740         }
1741         // update rectangle texture binding
1742         if (unit->trectangle != texrectangle)
1743         {
1744                 GL_ActiveTexture(unitnum);
1745                 if (unitnum < vid.texunits)
1746                 {
1747                         if (texrectangle)
1748                         {
1749                                 if (unit->trectangle == 0)
1750                                 {
1751                                         qglEnable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1752                                 }
1753                         }
1754                         else
1755                         {
1756                                 if (unit->trectangle)
1757                                 {
1758                                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1759                                 }
1760                         }
1761                 }
1762                 unit->trectangle = texrectangle;
1763                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1764         }
1765 }
1766
1767 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1768 {
1769         gltextureunit_t *unit = gl_state.units + unitnum;
1770         if (unitnum >= vid.teximageunits)
1771                 return;
1772         // update 2d texture binding
1773         if (unit->t2d != texnum)
1774         {
1775                 GL_ActiveTexture(unitnum);
1776                 if (unitnum < vid.texunits)
1777                 {
1778                         if (texnum)
1779                         {
1780                                 if (unit->t2d == 0)
1781                                 {
1782                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1783                                 }
1784                         }
1785                         else
1786                         {
1787                                 if (unit->t2d)
1788                                 {
1789                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1790                                 }
1791                         }
1792                 }
1793                 unit->t2d = texnum;
1794                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1795         }
1796         // update 3d texture binding
1797         if (unit->t3d)
1798         {
1799                 GL_ActiveTexture(unitnum);
1800                 if (unitnum < vid.texunits)
1801                 {
1802                         if (unit->t3d)
1803                         {
1804                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1805                         }
1806                 }
1807                 unit->t3d = 0;
1808                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1809         }
1810         // update cubemap texture binding
1811         if (unit->tcubemap != 0)
1812         {
1813                 GL_ActiveTexture(unitnum);
1814                 if (unitnum < vid.texunits)
1815                 {
1816                         if (unit->tcubemap)
1817                         {
1818                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1819                         }
1820                 }
1821                 unit->tcubemap = 0;
1822                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1823         }
1824         // update rectangle texture binding
1825         if (unit->trectangle != 0)
1826         {
1827                 GL_ActiveTexture(unitnum);
1828                 if (unitnum < vid.texunits)
1829                 {
1830                         if (unit->trectangle)
1831                         {
1832                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1833                         }
1834                 }
1835                 unit->trectangle = 0;
1836                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1837         }
1838 }
1839
1840 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1841 {
1842         gltextureunit_t *unit = gl_state.units + unitnum;
1843         if (unitnum >= vid.teximageunits)
1844                 return;
1845         // update 2d texture binding
1846         if (unit->t2d)
1847         {
1848                 GL_ActiveTexture(unitnum);
1849                 if (unitnum < vid.texunits)
1850                 {
1851                         if (unit->t2d)
1852                         {
1853                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1854                         }
1855                 }
1856                 unit->t2d = 0;
1857                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1858         }
1859         // update 3d texture binding
1860         if (unit->t3d != texnum)
1861         {
1862                 GL_ActiveTexture(unitnum);
1863                 if (unitnum < vid.texunits)
1864                 {
1865                         if (texnum)
1866                         {
1867                                 if (unit->t3d == 0)
1868                                 {
1869                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1870                                 }
1871                         }
1872                         else
1873                         {
1874                                 if (unit->t3d)
1875                                 {
1876                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1877                                 }
1878                         }
1879                 }
1880                 unit->t3d = texnum;
1881                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1882         }
1883         // update cubemap texture binding
1884         if (unit->tcubemap != 0)
1885         {
1886                 GL_ActiveTexture(unitnum);
1887                 if (unitnum < vid.texunits)
1888                 {
1889                         if (unit->tcubemap)
1890                         {
1891                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1892                         }
1893                 }
1894                 unit->tcubemap = 0;
1895                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1896         }
1897         // update rectangle texture binding
1898         if (unit->trectangle != 0)
1899         {
1900                 GL_ActiveTexture(unitnum);
1901                 if (unitnum < vid.texunits)
1902                 {
1903                         if (unit->trectangle)
1904                         {
1905                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1906                         }
1907                 }
1908                 unit->trectangle = 0;
1909                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1910         }
1911 }
1912
1913 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1914 {
1915         gltextureunit_t *unit = gl_state.units + unitnum;
1916         if (unitnum >= vid.teximageunits)
1917                 return;
1918         // update 2d texture binding
1919         if (unit->t2d)
1920         {
1921                 GL_ActiveTexture(unitnum);
1922                 if (unitnum < vid.texunits)
1923                 {
1924                         if (unit->t2d)
1925                         {
1926                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1927                         }
1928                 }
1929                 unit->t2d = 0;
1930                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1931         }
1932         // update 3d texture binding
1933         if (unit->t3d)
1934         {
1935                 GL_ActiveTexture(unitnum);
1936                 if (unitnum < vid.texunits)
1937                 {
1938                         if (unit->t3d)
1939                         {
1940                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1941                         }
1942                 }
1943                 unit->t3d = 0;
1944                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1945         }
1946         // update cubemap texture binding
1947         if (unit->tcubemap != texnum)
1948         {
1949                 GL_ActiveTexture(unitnum);
1950                 if (unitnum < vid.texunits)
1951                 {
1952                         if (texnum)
1953                         {
1954                                 if (unit->tcubemap == 0)
1955                                 {
1956                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1957                                 }
1958                         }
1959                         else
1960                         {
1961                                 if (unit->tcubemap)
1962                                 {
1963                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1964                                 }
1965                         }
1966                 }
1967                 unit->tcubemap = texnum;
1968                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1969         }
1970         // update rectangle texture binding
1971         if (unit->trectangle != 0)
1972         {
1973                 GL_ActiveTexture(unitnum);
1974                 if (unitnum < vid.texunits)
1975                 {
1976                         if (unit->trectangle)
1977                         {
1978                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1979                         }
1980                 }
1981                 unit->trectangle = 0;
1982                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1983         }
1984 }
1985
1986 void R_Mesh_TexBindRectangle(unsigned int unitnum, int texnum)
1987 {
1988         gltextureunit_t *unit = gl_state.units + unitnum;
1989         if (unitnum >= vid.teximageunits)
1990                 return;
1991         // update 2d texture binding
1992         if (unit->t2d)
1993         {
1994                 GL_ActiveTexture(unitnum);
1995                 if (unitnum < vid.texunits)
1996                 {
1997                         if (unit->t2d)
1998                         {
1999                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
2000                         }
2001                 }
2002                 unit->t2d = 0;
2003                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
2004         }
2005         // update 3d texture binding
2006         if (unit->t3d)
2007         {
2008                 GL_ActiveTexture(unitnum);
2009                 if (unitnum < vid.texunits)
2010                 {
2011                         if (unit->t3d)
2012                         {
2013                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
2014                         }
2015                 }
2016                 unit->t3d = 0;
2017                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
2018         }
2019         // update cubemap texture binding
2020         if (unit->tcubemap != 0)
2021         {
2022                 GL_ActiveTexture(unitnum);
2023                 if (unitnum < vid.texunits)
2024                 {
2025                         if (unit->tcubemap)
2026                         {
2027                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2028                         }
2029                 }
2030                 unit->tcubemap = 0;
2031                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
2032         }
2033         // update rectangle texture binding
2034         if (unit->trectangle != texnum)
2035         {
2036                 GL_ActiveTexture(unitnum);
2037                 if (unitnum < vid.texunits)
2038                 {
2039                         if (texnum)
2040                         {
2041                                 if (unit->trectangle == 0)
2042                                 {
2043                                         qglEnable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2044                                 }
2045                         }
2046                         else
2047                         {
2048                                 if (unit->trectangle)
2049                                 {
2050                                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2051                                 }
2052                         }
2053                 }
2054                 unit->trectangle = texnum;
2055                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
2056         }
2057 }
2058
2059 static const float gl_identitymatrix[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
2060
2061 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
2062 {
2063         gltextureunit_t *unit = gl_state.units + unitnum;
2064         if (matrix->m[3][3])
2065         {
2066                 // texmatrix specified, check if it is different
2067                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
2068                 {
2069                         float glmatrix[16];
2070                         unit->texmatrixenabled = true;
2071                         unit->matrix = *matrix;
2072                         CHECKGLERROR
2073                         Matrix4x4_ToArrayFloatGL(&unit->matrix, glmatrix);
2074                         GL_ActiveTexture(unitnum);
2075                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2076                         qglLoadMatrixf(glmatrix);CHECKGLERROR
2077                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2078                 }
2079         }
2080         else
2081         {
2082                 // no texmatrix specified, revert to identity
2083                 if (unit->texmatrixenabled)
2084                 {
2085                         unit->texmatrixenabled = false;
2086                         unit->matrix = identitymatrix;
2087                         CHECKGLERROR
2088                         GL_ActiveTexture(unitnum);
2089                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2090                         qglLoadIdentity();CHECKGLERROR
2091                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2092                 }
2093         }
2094 }
2095
2096 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
2097 {
2098         gltextureunit_t *unit = gl_state.units + unitnum;
2099         CHECKGLERROR
2100         if (gl_combine.integer)
2101         {
2102                 // GL_ARB_texture_env_combine
2103                 if (!combinergb)
2104                         combinergb = GL_MODULATE;
2105                 if (!combinealpha)
2106                         combinealpha = GL_MODULATE;
2107                 if (!rgbscale)
2108                         rgbscale = 1;
2109                 if (!alphascale)
2110                         alphascale = 1;
2111                 if (unit->combinergb != combinergb)
2112                 {
2113                         unit->combinergb = combinergb;
2114                         GL_ActiveTexture(unitnum);
2115                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
2116                 }
2117                 if (unit->combinealpha != combinealpha)
2118                 {
2119                         unit->combinealpha = combinealpha;
2120                         GL_ActiveTexture(unitnum);
2121                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
2122                 }
2123                 if (unit->rgbscale != rgbscale)
2124                 {
2125                         GL_ActiveTexture(unitnum);
2126                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
2127                 }
2128                 if (unit->alphascale != alphascale)
2129                 {
2130                         GL_ActiveTexture(unitnum);
2131                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
2132                 }
2133         }
2134         else
2135         {
2136                 // normal GL texenv
2137                 if (!combinergb)
2138                         combinergb = GL_MODULATE;
2139                 if (unit->combinergb != combinergb)
2140                 {
2141                         unit->combinergb = combinergb;
2142                         GL_ActiveTexture(unitnum);
2143                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
2144                 }
2145         }
2146 }
2147
2148 void R_Mesh_TextureState(const rmeshstate_t *m)
2149 {
2150         unsigned int i;
2151
2152         BACKENDACTIVECHECK
2153
2154         CHECKGLERROR
2155         for (i = 0;i < vid.teximageunits;i++)
2156                 R_Mesh_TexBindAll(i, m->tex[i], m->tex3d[i], m->texcubemap[i], m->texrectangle[i]);
2157         for (i = 0;i < vid.texarrayunits;i++)
2158         {
2159                 if (m->pointer_texcoord3f[i])
2160                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
2161                 else
2162                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
2163         }
2164         for (i = 0;i < vid.texunits;i++)
2165         {
2166                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
2167                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
2168         }
2169         CHECKGLERROR
2170 }
2171
2172 void R_Mesh_ResetTextureState(void)
2173 {
2174         unsigned int unitnum;
2175
2176         BACKENDACTIVECHECK
2177
2178         CHECKGLERROR
2179         for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
2180         {
2181                 gltextureunit_t *unit = gl_state.units + unitnum;
2182                 // update 2d texture binding
2183                 if (unit->t2d)
2184                 {
2185                         GL_ActiveTexture(unitnum);
2186                         if (unitnum < vid.texunits)
2187                         {
2188                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
2189                         }
2190                         unit->t2d = 0;
2191                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
2192                 }
2193                 // update 3d texture binding
2194                 if (unit->t3d)
2195                 {
2196                         GL_ActiveTexture(unitnum);
2197                         if (unitnum < vid.texunits)
2198                         {
2199                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
2200                         }
2201                         unit->t3d = 0;
2202                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
2203                 }
2204                 // update cubemap texture binding
2205                 if (unit->tcubemap)
2206                 {
2207                         GL_ActiveTexture(unitnum);
2208                         if (unitnum < vid.texunits)
2209                         {
2210                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2211                         }
2212                         unit->tcubemap = 0;
2213                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
2214                 }
2215                 // update rectangle texture binding
2216                 if (unit->trectangle)
2217                 {
2218                         GL_ActiveTexture(unitnum);
2219                         if (unitnum < vid.texunits)
2220                         {
2221                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2222                         }
2223                         unit->trectangle = 0;
2224                         qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
2225                 }
2226         }
2227         for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++)
2228         {
2229                 gltextureunit_t *unit = gl_state.units + unitnum;
2230                 // texture array unit is disabled, disable the array
2231                 if (unit->arrayenabled)
2232                 {
2233                         unit->arrayenabled = false;
2234                         GL_ClientActiveTexture(unitnum);
2235                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
2236                 }
2237         }
2238         for (unitnum = 0;unitnum < vid.texunits;unitnum++)
2239         {
2240                 gltextureunit_t *unit = gl_state.units + unitnum;
2241                 // no texmatrix specified, revert to identity
2242                 if (unit->texmatrixenabled)
2243                 {
2244                         unit->texmatrixenabled = false;
2245                         unit->matrix = identitymatrix;
2246                         CHECKGLERROR
2247                         GL_ActiveTexture(unitnum);
2248                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2249                         qglLoadIdentity();CHECKGLERROR
2250                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2251                 }
2252                 if (gl_combine.integer)
2253                 {
2254                         // GL_ARB_texture_env_combine
2255                         if (unit->combinergb != GL_MODULATE)
2256                         {
2257                                 unit->combinergb = GL_MODULATE;
2258                                 GL_ActiveTexture(unitnum);
2259                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
2260                         }
2261                         if (unit->combinealpha != GL_MODULATE)
2262                         {
2263                                 unit->combinealpha = GL_MODULATE;
2264                                 GL_ActiveTexture(unitnum);
2265                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
2266                         }
2267                         if (unit->rgbscale != 1)
2268                         {
2269                                 GL_ActiveTexture(unitnum);
2270                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = 1));CHECKGLERROR
2271                         }
2272                         if (unit->alphascale != 1)
2273                         {
2274                                 GL_ActiveTexture(unitnum);
2275                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = 1));CHECKGLERROR
2276                         }
2277                 }
2278                 else
2279                 {
2280                         // normal GL texenv
2281                         if (unit->combinergb != GL_MODULATE)
2282                         {
2283                                 unit->combinergb = GL_MODULATE;
2284                                 GL_ActiveTexture(unitnum);
2285                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
2286                         }
2287                 }
2288         }
2289 }