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