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