]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
while I am at it, also dp_specularscalemod
[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         if (border > size - 2)
550                 border = size - 2;
551         memset(v, 0, sizeof(*v));
552         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
553         v->cameramatrix = *cameramatrix;
554         v->x = (side & 1) * size;
555         v->y = (side >> 1) * size;
556         v->width = size;
557         v->height = size;
558         v->depth = 1;
559         v->m[0] = v->m[5] = 1.0f * ((float)size - border) / size;
560         v->m[10] = -(farclip + nearclip) / (farclip - nearclip);
561         v->m[11] = -1;
562         v->m[14] = -2 * nearclip * farclip / (farclip - nearclip);
563
564         Matrix4x4_FromArrayFloatGL(&basematrix, rectviewmatrix[side]);
565         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
566         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
567         Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
568
569         if (nearplane)
570                 R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
571 }
572
573 void R_SetViewport(const r_viewport_t *v)
574 {
575         float glmatrix[16];
576         backend_viewport = *v;
577
578         CHECKGLERROR
579         qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
580
581         // Load the projection matrix into OpenGL
582         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
583         qglLoadMatrixd(backend_viewport.m);CHECKGLERROR
584         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
585
586         // FIXME: v_flipped_state is evil, this probably breaks somewhere
587         GL_SetMirrorState(v_flipped.integer && (v->type == R_VIEWPORTTYPE_PERSPECTIVE || v->type == R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP));
588
589         // directly force an update of the modelview matrix
590         Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewport.viewmatrix, &backend_modelmatrix);
591         Matrix4x4_ToArrayFloatGL(&backend_modelviewmatrix, glmatrix);
592         qglLoadMatrixf(glmatrix);CHECKGLERROR
593 }
594
595 void R_GetViewport(r_viewport_t *v)
596 {
597         *v = backend_viewport;
598 }
599
600 typedef struct gltextureunit_s
601 {
602         const void *pointer_texcoord;
603         size_t pointer_texcoord_offset;
604         int pointer_texcoord_buffer;
605         int t1d, t2d, t3d, tcubemap, trectangle;
606         int arrayenabled;
607         unsigned int arraycomponents;
608         int rgbscale, alphascale;
609         int combinergb, combinealpha;
610         // FIXME: add more combine stuff
611         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
612         int texmatrixenabled;
613         matrix4x4_t matrix;
614 }
615 gltextureunit_t;
616
617 static struct gl_state_s
618 {
619         int cullface;
620         int cullfaceenable;
621         int blendfunc1;
622         int blendfunc2;
623         int blend;
624         GLboolean depthmask;
625         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
626         int depthtest;
627         float depthrange[2];
628         float polygonoffset[2];
629         int alphatest;
630         int scissortest;
631         unsigned int unit;
632         unsigned int clientunit;
633         gltextureunit_t units[MAX_TEXTUREUNITS];
634         float color4f[4];
635         int lockrange_first;
636         int lockrange_count;
637         int vertexbufferobject;
638         int elementbufferobject;
639         qboolean pointer_color_enabled;
640         const void *pointer_vertex;
641         const void *pointer_color;
642         size_t pointer_vertex_offset;
643         size_t pointer_color_offset;
644         int pointer_vertex_buffer;
645         int pointer_color_buffer;
646 }
647 gl_state;
648
649 static void GL_BindVBO(int bufferobject)
650 {
651         if (gl_state.vertexbufferobject != bufferobject)
652         {
653                 gl_state.vertexbufferobject = bufferobject;
654                 CHECKGLERROR
655                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);
656                 CHECKGLERROR
657         }
658 }
659
660 static void GL_BindEBO(int bufferobject)
661 {
662         if (gl_state.elementbufferobject != bufferobject)
663         {
664                 gl_state.elementbufferobject = bufferobject;
665                 CHECKGLERROR
666                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);
667                 CHECKGLERROR
668         }
669 }
670
671 void GL_SetupTextureState(void)
672 {
673         unsigned int i;
674         gltextureunit_t *unit;
675         CHECKGLERROR
676         gl_state.unit = MAX_TEXTUREUNITS;
677         gl_state.clientunit = MAX_TEXTUREUNITS;
678         for (i = 0;i < MAX_TEXTUREUNITS;i++)
679         {
680                 unit = gl_state.units + i;
681                 unit->t1d = 0;
682                 unit->t2d = 0;
683                 unit->t3d = 0;
684                 unit->tcubemap = 0;
685                 unit->arrayenabled = false;
686                 unit->arraycomponents = 0;
687                 unit->pointer_texcoord = NULL;
688                 unit->pointer_texcoord_buffer = 0;
689                 unit->pointer_texcoord_offset = 0;
690                 unit->rgbscale = 1;
691                 unit->alphascale = 1;
692                 unit->combinergb = GL_MODULATE;
693                 unit->combinealpha = GL_MODULATE;
694                 unit->texmatrixenabled = false;
695                 unit->matrix = identitymatrix;
696         }
697
698         for (i = 0;i < backendimageunits;i++)
699         {
700                 GL_ActiveTexture(i);
701                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
702                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
703                 if (gl_texture3d)
704                 {
705                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
706                 }
707                 if (gl_texturecubemap)
708                 {
709                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
710                 }
711                 if (gl_texturerectangle)
712                 {
713                         qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
714                 }
715         }
716
717         for (i = 0;i < backendarrayunits;i++)
718         {
719                 GL_ClientActiveTexture(i);
720                 GL_BindVBO(0);
721                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
722                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
723         }
724
725         for (i = 0;i < backendunits;i++)
726         {
727                 GL_ActiveTexture(i);
728                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
729                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
730                 if (gl_texture3d)
731                 {
732                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
733                 }
734                 if (gl_texturecubemap)
735                 {
736                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
737                 }
738                 if (gl_texturerectangle)
739                 {
740                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
741                 }
742                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
743                 qglLoadIdentity();CHECKGLERROR
744                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
745                 if (gl_combine.integer)
746                 {
747                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
748                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
749                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
750                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
751                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
752                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
753                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
754                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
755                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
756                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
757                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
758                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
759                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
760                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
761                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
762                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
763                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
764                 }
765                 else
766                 {
767                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
768                 }
769                 CHECKGLERROR
770         }
771         CHECKGLERROR
772 }
773
774 void GL_Backend_ResetState(void)
775 {
776         memset(&gl_state, 0, sizeof(gl_state));
777         gl_state.depthtest = true;
778         gl_state.alphatest = false;
779         gl_state.blendfunc1 = GL_ONE;
780         gl_state.blendfunc2 = GL_ZERO;
781         gl_state.blend = false;
782         gl_state.depthmask = GL_TRUE;
783         gl_state.colormask = 15;
784         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
785         gl_state.lockrange_first = 0;
786         gl_state.lockrange_count = 0;
787         gl_state.cullface = v_flipped_state ? GL_BACK : GL_FRONT; // quake is backwards, this culls back faces
788         gl_state.cullfaceenable = true;
789         gl_state.polygonoffset[0] = 0;
790         gl_state.polygonoffset[1] = 0;
791
792         CHECKGLERROR
793
794         qglColorMask(1, 1, 1, 1);
795         qglAlphaFunc(GL_GEQUAL, 0.5);CHECKGLERROR
796         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
797         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
798         qglDisable(GL_BLEND);CHECKGLERROR
799         qglCullFace(gl_state.cullface);CHECKGLERROR
800         qglEnable(GL_CULL_FACE);CHECKGLERROR
801         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
802         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
803         qglDepthMask(gl_state.depthmask);CHECKGLERROR
804         qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
805
806         if (gl_support_arb_vertex_buffer_object)
807         {
808                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
809                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
810         }
811
812         if (gl_support_ext_framebuffer_object)
813         {
814                 qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
815                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
816         }
817
818         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
819         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
820
821         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
822         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
823
824         GL_Color(0, 0, 0, 0);
825         GL_Color(1, 1, 1, 1);
826
827         GL_SetupTextureState();
828 }
829
830 void GL_ActiveTexture(unsigned int num)
831 {
832         if (gl_state.unit != num)
833         {
834                 gl_state.unit = num;
835                 if (qglActiveTexture)
836                 {
837                         CHECKGLERROR
838                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
839                         CHECKGLERROR
840                 }
841         }
842 }
843
844 void GL_ClientActiveTexture(unsigned int num)
845 {
846         if (gl_state.clientunit != num)
847         {
848                 gl_state.clientunit = num;
849                 if (qglActiveTexture)
850                 {
851                         CHECKGLERROR
852                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
853                         CHECKGLERROR
854                 }
855         }
856 }
857
858 void GL_BlendFunc(int blendfunc1, int blendfunc2)
859 {
860         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
861         {
862                 CHECKGLERROR
863                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
864                 if (gl_state.blendfunc2 == GL_ZERO)
865                 {
866                         if (gl_state.blendfunc1 == GL_ONE)
867                         {
868                                 if (gl_state.blend)
869                                 {
870                                         gl_state.blend = 0;
871                                         qglDisable(GL_BLEND);CHECKGLERROR
872                                 }
873                         }
874                         else
875                         {
876                                 if (!gl_state.blend)
877                                 {
878                                         gl_state.blend = 1;
879                                         qglEnable(GL_BLEND);CHECKGLERROR
880                                 }
881                         }
882                 }
883                 else
884                 {
885                         if (!gl_state.blend)
886                         {
887                                 gl_state.blend = 1;
888                                 qglEnable(GL_BLEND);CHECKGLERROR
889                         }
890                 }
891         }
892 }
893
894 void GL_DepthMask(int state)
895 {
896         if (gl_state.depthmask != state)
897         {
898                 CHECKGLERROR
899                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
900         }
901 }
902
903 void GL_DepthTest(int state)
904 {
905         if (gl_state.depthtest != state)
906         {
907                 gl_state.depthtest = state;
908                 CHECKGLERROR
909                 if (gl_state.depthtest)
910                 {
911                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
912                 }
913                 else
914                 {
915                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
916                 }
917         }
918 }
919
920 void GL_DepthRange(float nearfrac, float farfrac)
921 {
922         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
923         {
924                 gl_state.depthrange[0] = nearfrac;
925                 gl_state.depthrange[1] = farfrac;
926                 qglDepthRange(nearfrac, farfrac);
927         }
928 }
929
930 void GL_PolygonOffset(float planeoffset, float depthoffset)
931 {
932         if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset)
933         {
934                 gl_state.polygonoffset[0] = planeoffset;
935                 gl_state.polygonoffset[1] = depthoffset;
936                 qglPolygonOffset(planeoffset, depthoffset);
937         }
938 }
939
940 void GL_SetMirrorState(qboolean state)
941 {
942         if(!state != !v_flipped_state)
943         {
944                 // change cull face mode!
945                 if(gl_state.cullface == GL_BACK)
946                         qglCullFace((gl_state.cullface = GL_FRONT));
947                 else if(gl_state.cullface == GL_FRONT)
948                         qglCullFace((gl_state.cullface = GL_BACK));
949         }
950         v_flipped_state = state;
951 }
952
953 void GL_CullFace(int state)
954 {
955         CHECKGLERROR
956
957         if(v_flipped_state)
958         {
959                 if(state == GL_FRONT)
960                         state = GL_BACK;
961                 else if(state == GL_BACK)
962                         state = GL_FRONT;
963         }
964
965         if (state != GL_NONE)
966         {
967                 if (!gl_state.cullfaceenable)
968                 {
969                         gl_state.cullfaceenable = true;
970                         qglEnable(GL_CULL_FACE);CHECKGLERROR
971                 }
972                 if (gl_state.cullface != state)
973                 {
974                         gl_state.cullface = state;
975                         qglCullFace(gl_state.cullface);CHECKGLERROR
976                 }
977         }
978         else
979         {
980                 if (gl_state.cullfaceenable)
981                 {
982                         gl_state.cullfaceenable = false;
983                         qglDisable(GL_CULL_FACE);CHECKGLERROR
984                 }
985         }
986 }
987
988 void GL_AlphaTest(int state)
989 {
990         if (gl_state.alphatest != state)
991         {
992                 gl_state.alphatest = state;
993                 CHECKGLERROR
994                 if (gl_state.alphatest)
995                 {
996                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
997                 }
998                 else
999                 {
1000                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
1001                 }
1002         }
1003 }
1004
1005 void GL_ColorMask(int r, int g, int b, int a)
1006 {
1007         int state = r*8 + g*4 + b*2 + a*1;
1008         if (gl_state.colormask != state)
1009         {
1010                 gl_state.colormask = state;
1011                 CHECKGLERROR
1012                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
1013         }
1014 }
1015
1016 void GL_Color(float cr, float cg, float cb, float ca)
1017 {
1018         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)
1019         {
1020                 gl_state.color4f[0] = cr;
1021                 gl_state.color4f[1] = cg;
1022                 gl_state.color4f[2] = cb;
1023                 gl_state.color4f[3] = ca;
1024                 CHECKGLERROR
1025                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
1026                 CHECKGLERROR
1027         }
1028 }
1029
1030 void GL_LockArrays(int first, int count)
1031 {
1032         if (count < gl_lockarrays_minimumvertices.integer)
1033         {
1034                 first = 0;
1035                 count = 0;
1036         }
1037         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
1038         {
1039                 if (gl_state.lockrange_count)
1040                 {
1041                         gl_state.lockrange_count = 0;
1042                         CHECKGLERROR
1043                         qglUnlockArraysEXT();
1044                         CHECKGLERROR
1045                 }
1046                 if (count && gl_supportslockarrays && gl_lockarrays.integer)
1047                 {
1048                         gl_state.lockrange_first = first;
1049                         gl_state.lockrange_count = count;
1050                         CHECKGLERROR
1051                         qglLockArraysEXT(first, count);
1052                         CHECKGLERROR
1053                 }
1054         }
1055 }
1056
1057 void GL_Scissor (int x, int y, int width, int height)
1058 {
1059         CHECKGLERROR
1060         qglScissor(x, y,width,height);
1061         CHECKGLERROR
1062 }
1063
1064 void GL_ScissorTest(int state)
1065 {
1066         if(gl_state.scissortest == state)
1067                 return;
1068
1069         CHECKGLERROR
1070         if((gl_state.scissortest = state))
1071                 qglEnable(GL_SCISSOR_TEST);
1072         else
1073                 qglDisable(GL_SCISSOR_TEST);
1074         CHECKGLERROR
1075 }
1076
1077 void GL_Clear(int mask)
1078 {
1079         CHECKGLERROR
1080         qglClear(mask);CHECKGLERROR
1081 }
1082
1083 // called at beginning of frame
1084 void R_Mesh_Start(void)
1085 {
1086         BACKENDACTIVECHECK
1087         CHECKGLERROR
1088         if (gl_printcheckerror.integer && !gl_paranoid.integer)
1089         {
1090                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
1091                 Cvar_SetValueQuick(&gl_paranoid, 1);
1092         }
1093         GL_Backend_ResetState();
1094 }
1095
1096 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
1097 {
1098         int shaderobject;
1099         int shadercompiled;
1100         char compilelog[MAX_INPUTLINE];
1101         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
1102         if (!shaderobject)
1103                 return false;
1104         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
1105         qglCompileShaderARB(shaderobject);CHECKGLERROR
1106         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
1107         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
1108         if (compilelog[0] && developer.integer > 0)
1109         {
1110                 int i, j, pretextlines = 0;
1111                 for (i = 0;i < numstrings - 1;i++)
1112                         for (j = 0;strings[i][j];j++)
1113                                 if (strings[i][j] == '\n')
1114                                         pretextlines++;
1115                 Con_DPrintf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
1116         }
1117         if (!shadercompiled)
1118         {
1119                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
1120                 return false;
1121         }
1122         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
1123         qglDeleteObjectARB(shaderobject);CHECKGLERROR
1124         return true;
1125 }
1126
1127 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)
1128 {
1129         GLint programlinked;
1130         GLuint programobject = 0;
1131         char linklog[MAX_INPUTLINE];
1132         CHECKGLERROR
1133
1134         programobject = qglCreateProgramObjectARB();CHECKGLERROR
1135         if (!programobject)
1136                 return 0;
1137
1138         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
1139                 goto cleanup;
1140
1141 #ifdef GL_GEOMETRY_SHADER_ARB
1142         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
1143                 goto cleanup;
1144 #endif
1145
1146         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
1147                 goto cleanup;
1148
1149         qglLinkProgramARB(programobject);CHECKGLERROR
1150         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
1151         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
1152         if (linklog[0])
1153         {
1154                 Con_DPrintf("program link log:\n%s\n", linklog);
1155                 // software vertex shader is ok but software fragment shader is WAY
1156                 // too slow, fail program if so.
1157                 // NOTE: this string might be ATI specific, but that's ok because the
1158                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
1159                 // software fragment shader due to low instruction and dependent
1160                 // texture limits.
1161                 if (strstr(linklog, "fragment shader will run in software"))
1162                         programlinked = false;
1163         }
1164         if (!programlinked)
1165                 goto cleanup;
1166         return programobject;
1167 cleanup:
1168         qglDeleteObjectARB(programobject);CHECKGLERROR
1169         return 0;
1170 }
1171
1172 void GL_Backend_FreeProgram(unsigned int prog)
1173 {
1174         CHECKGLERROR
1175         qglDeleteObjectARB(prog);
1176         CHECKGLERROR
1177 }
1178
1179 int gl_backend_rebindtextures;
1180
1181 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
1182 {
1183         int i;
1184         if (offset)
1185         {
1186                 for (i = 0;i < count;i++)
1187                         *out++ = *in++ + offset;
1188         }
1189         else
1190                 memcpy(out, in, sizeof(*out) * count);
1191 }
1192
1193 // renders triangles using vertices from the active arrays
1194 int paranoidblah = 0;
1195 void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int bufferobject3i, int bufferobject3s)
1196 {
1197         unsigned int numelements = numtriangles * 3;
1198         if (numvertices < 3 || numtriangles < 1)
1199         {
1200                 if (numvertices < 0 || numtriangles < 0 || developer.integer >= 100)
1201                         Con_Printf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %i, %i);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3s, bufferobject3i, bufferobject3s);
1202                 return;
1203         }
1204         if (!gl_mesh_prefer_short_elements.integer)
1205         {
1206                 if (element3i)
1207                         element3s = NULL;
1208                 if (bufferobject3i)
1209                         bufferobject3s = 0;
1210         }
1211         if (element3i)
1212                 element3i += firsttriangle * 3;
1213         if (element3s)
1214                 element3s += firsttriangle * 3;
1215         switch (gl_vbo.integer)
1216         {
1217         default:
1218         case 0:
1219         case 2:
1220                 bufferobject3i = bufferobject3s = 0;
1221                 break;
1222         case 1:
1223                 break;
1224         case 3:
1225                 if (firsttriangle)
1226                         bufferobject3i = bufferobject3s = 0;
1227                 break;
1228         }
1229         CHECKGLERROR
1230         r_refdef.stats.meshes++;
1231         r_refdef.stats.meshes_elements += numelements;
1232         if (gl_paranoid.integer)
1233         {
1234                 unsigned int i, j, size;
1235                 const int *p;
1236                 // note: there's no validation done here on buffer objects because it
1237                 // is somewhat difficult to get at the data, and gl_paranoid can be
1238                 // used without buffer objects if the need arises
1239                 // (the data could be gotten using glMapBuffer but it would be very
1240                 //  slow due to uncachable video memory reads)
1241                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
1242                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
1243                 CHECKGLERROR
1244                 if (gl_state.pointer_vertex)
1245                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
1246                                 paranoidblah += *p;
1247                 if (gl_state.pointer_color_enabled)
1248                 {
1249                         if (!qglIsEnabled(GL_COLOR_ARRAY))
1250                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
1251                         CHECKGLERROR
1252                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1253                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
1254                                         paranoidblah += *p;
1255                 }
1256                 for (i = 0;i < backendarrayunits;i++)
1257                 {
1258                         if (gl_state.units[i].arrayenabled)
1259                         {
1260                                 GL_ClientActiveTexture(i);
1261                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
1262                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
1263                                 CHECKGLERROR
1264                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
1265                                         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++)
1266                                                 paranoidblah += *p;
1267                         }
1268                 }
1269                 if (element3i)
1270                 {
1271                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1272                         {
1273                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
1274                                 {
1275                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
1276                                         return;
1277                                 }
1278                         }
1279                 }
1280                 if (element3s)
1281                 {
1282                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1283                         {
1284                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
1285                                 {
1286                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
1287                                         return;
1288                                 }
1289                         }
1290                 }
1291                 CHECKGLERROR
1292         }
1293         if (r_render.integer || r_refdef.draw2dstage)
1294         {
1295                 CHECKGLERROR
1296                 if (gl_mesh_testmanualfeeding.integer)
1297                 {
1298                         unsigned int i, j, element;
1299                         const GLfloat *p;
1300                         qglBegin(GL_TRIANGLES);
1301                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1302                         {
1303                                 element = element3i ? element3i[i] : element3s[i];
1304                                 for (j = 0;j < backendarrayunits;j++)
1305                                 {
1306                                         if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled)
1307                                         {
1308                                                 if (backendarrayunits > 1)
1309                                                 {
1310                                                         if (gl_state.units[j].arraycomponents == 4)
1311                                                         {
1312                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4;
1313                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
1314                                                         }
1315                                                         else if (gl_state.units[j].arraycomponents == 3)
1316                                                         {
1317                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3;
1318                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
1319                                                         }
1320                                                         else if (gl_state.units[j].arraycomponents == 2)
1321                                                         {
1322                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2;
1323                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
1324                                                         }
1325                                                         else
1326                                                         {
1327                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
1328                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
1329                                                         }
1330                                                 }
1331                                                 else
1332                                                 {
1333                                                         if (gl_state.units[j].arraycomponents == 4)
1334                                                         {
1335                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4;
1336                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
1337                                                         }
1338                                                         else if (gl_state.units[j].arraycomponents == 3)
1339                                                         {
1340                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3;
1341                                                                 qglTexCoord3f(p[0], p[1], p[2]);
1342                                                         }
1343                                                         else if (gl_state.units[j].arraycomponents == 2)
1344                                                         {
1345                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2;
1346                                                                 qglTexCoord2f(p[0], p[1]);
1347                                                         }
1348                                                         else
1349                                                         {
1350                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
1351                                                                 qglTexCoord1f(p[0]);
1352                                                         }
1353                                                 }
1354                                         }
1355                                 }
1356                                 if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1357                                 {
1358                                         p = ((const GLfloat *)(gl_state.pointer_color)) + element * 4;
1359                                         qglColor4f(p[0], p[1], p[2], p[3]);
1360                                 }
1361                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + element * 3;
1362                                 qglVertex3f(p[0], p[1], p[2]);
1363                         }
1364                         qglEnd();
1365                         CHECKGLERROR
1366                 }
1367                 else if (gl_mesh_testarrayelement.integer)
1368                 {
1369                         int i;
1370                         qglBegin(GL_TRIANGLES);
1371                         if (element3i)
1372                         {
1373                                 for (i = 0;i < numtriangles * 3;i++)
1374                                         qglArrayElement(element3i[i]);
1375                         }
1376                         else if (element3s)
1377                         {
1378                                 for (i = 0;i < numtriangles * 3;i++)
1379                                         qglArrayElement(element3s[i]);
1380                         }
1381                         qglEnd();
1382                         CHECKGLERROR
1383                 }
1384                 else if (bufferobject3s)
1385                 {
1386                         GL_BindEBO(bufferobject3s);
1387                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1388                         {
1389                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
1390                                 CHECKGLERROR
1391                         }
1392                         else
1393                         {
1394                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
1395                                 CHECKGLERROR
1396                         }
1397                 }
1398                 else if (bufferobject3i)
1399                 {
1400                         GL_BindEBO(bufferobject3i);
1401                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1402                         {
1403                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
1404                                 CHECKGLERROR
1405                         }
1406                         else
1407                         {
1408                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
1409                                 CHECKGLERROR
1410                         }
1411                 }
1412                 else if (element3s)
1413                 {
1414                         GL_BindEBO(0);
1415                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1416                         {
1417                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
1418                                 CHECKGLERROR
1419                         }
1420                         else
1421                         {
1422                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
1423                                 CHECKGLERROR
1424                         }
1425                 }
1426                 else if (element3i)
1427                 {
1428                         GL_BindEBO(0);
1429                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1430                         {
1431                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
1432                                 CHECKGLERROR
1433                         }
1434                         else
1435                         {
1436                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
1437                                 CHECKGLERROR
1438                         }
1439                 }
1440         }
1441 }
1442
1443 // restores backend state, used when done with 3D rendering
1444 void R_Mesh_Finish(void)
1445 {
1446         unsigned int i;
1447         BACKENDACTIVECHECK
1448         CHECKGLERROR
1449         GL_LockArrays(0, 0);
1450         CHECKGLERROR
1451
1452         for (i = 0;i < backendimageunits;i++)
1453         {
1454                 GL_ActiveTexture(i);
1455                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
1456                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1457                 if (gl_texture3d)
1458                 {
1459                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1460                 }
1461                 if (gl_texturecubemap)
1462                 {
1463                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1464                 }
1465                 if (gl_texturerectangle)
1466                 {
1467                         qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
1468                 }
1469         }
1470         for (i = 0;i < backendarrayunits;i++)
1471         {
1472                 GL_ActiveTexture(backendarrayunits - 1 - i);
1473                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1474         }
1475         for (i = 0;i < backendunits;i++)
1476         {
1477                 GL_ActiveTexture(backendunits - 1 - i);
1478                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1479                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1480                 if (gl_texture3d)
1481                 {
1482                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1483                 }
1484                 if (gl_texturecubemap)
1485                 {
1486                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1487                 }
1488                 if (gl_texturerectangle)
1489                 {
1490                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1491                 }
1492                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1493                 if (gl_combine.integer)
1494                 {
1495                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1496                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1497                 }
1498         }
1499         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1500         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1501
1502         qglDisable(GL_BLEND);CHECKGLERROR
1503         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1504         qglDepthMask(GL_TRUE);CHECKGLERROR
1505         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1506 }
1507
1508 int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name)
1509 {
1510         gl_bufferobjectinfo_t *info;
1511         GLuint bufferobject;
1512
1513         if (!gl_vbo.integer)
1514                 return 0;
1515
1516         qglGenBuffersARB(1, &bufferobject);
1517         switch(target)
1518         {
1519         case GL_ELEMENT_ARRAY_BUFFER_ARB: GL_BindEBO(bufferobject);break;
1520         case GL_ARRAY_BUFFER_ARB: GL_BindVBO(bufferobject);break;
1521         default: Sys_Error("R_Mesh_CreateStaticBufferObject: unknown target type %i\n", target);return 0;
1522         }
1523         qglBufferDataARB(target, size, data, GL_STATIC_DRAW_ARB);
1524
1525         info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_AllocRecord(&gl_bufferobjectinfoarray);
1526         memset(info, 0, sizeof(*info));
1527         info->target = target;
1528         info->object = bufferobject;
1529         info->size = size;
1530         strlcpy(info->name, name, sizeof(info->name));
1531
1532         return (int)bufferobject;
1533 }
1534
1535 void R_Mesh_DestroyBufferObject(int bufferobject)
1536 {
1537         int i, endindex;
1538         gl_bufferobjectinfo_t *info;
1539
1540         qglDeleteBuffersARB(1, (GLuint *)&bufferobject);
1541
1542         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1543         for (i = 0;i < endindex;i++)
1544         {
1545                 info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1546                 if (!info)
1547                         continue;
1548                 if (info->object == bufferobject)
1549                 {
1550                         Mem_ExpandableArray_FreeRecord(&gl_bufferobjectinfoarray, (void *)info);
1551                         break;
1552                 }
1553         }
1554 }
1555
1556 void GL_Mesh_ListVBOs(qboolean printeach)
1557 {
1558         int i, endindex;
1559         size_t ebocount = 0, ebomemory = 0;
1560         size_t vbocount = 0, vbomemory = 0;
1561         gl_bufferobjectinfo_t *info;
1562         endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray);
1563         for (i = 0;i < endindex;i++)
1564         {
1565                 info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i);
1566                 if (!info)
1567                         continue;
1568                 switch(info->target)
1569                 {
1570                 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;
1571                 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;
1572                 default: Con_Printf("gl_vbostats: unknown target type %i\n", info->target);break;
1573                 }
1574         }
1575         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);
1576 }
1577
1578 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1579 {
1580         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1581         {
1582                 float glmatrix[16];
1583                 backend_modelmatrix = *matrix;
1584                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewport.viewmatrix, &backend_modelmatrix);
1585                 Matrix4x4_ToArrayFloatGL(&backend_modelviewmatrix, glmatrix);
1586                 CHECKGLERROR
1587                 qglLoadMatrixf(glmatrix);CHECKGLERROR
1588         }
1589 }
1590
1591 void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset)
1592 {
1593         if (!gl_vbo.integer)
1594                 bufferobject = 0;
1595         if (gl_state.pointer_vertex != vertex3f || gl_state.pointer_vertex_buffer != bufferobject || gl_state.pointer_vertex_offset != bufferoffset)
1596         {
1597                 gl_state.pointer_vertex = vertex3f;
1598                 gl_state.pointer_vertex_buffer = bufferobject;
1599                 gl_state.pointer_vertex_offset = bufferoffset;
1600                 CHECKGLERROR
1601                 GL_BindVBO(bufferobject);
1602                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), bufferobject ? (void *)bufferoffset : vertex3f);CHECKGLERROR
1603         }
1604 }
1605
1606 void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset)
1607 {
1608         // note: this can not rely on bufferobject to decide whether a color array
1609         // is supplied, because surfmesh_t shares one vbo for all arrays, which
1610         // means that a valid vbo may be supplied even if there is no color array.
1611         if (color4f)
1612         {
1613                 if (!gl_vbo.integer)
1614                         bufferobject = 0;
1615                 // caller wants color array enabled
1616                 if (!gl_state.pointer_color_enabled)
1617                 {
1618                         gl_state.pointer_color_enabled = true;
1619                         CHECKGLERROR
1620                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1621                 }
1622                 if (gl_state.pointer_color != color4f || gl_state.pointer_color_buffer != bufferobject || gl_state.pointer_color_offset != bufferoffset)
1623                 {
1624                         gl_state.pointer_color = color4f;
1625                         gl_state.pointer_color_buffer = bufferobject;
1626                         gl_state.pointer_color_offset = bufferoffset;
1627                         CHECKGLERROR
1628                         GL_BindVBO(bufferobject);
1629                         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), bufferobject ? (void *)bufferoffset : color4f);CHECKGLERROR
1630                 }
1631         }
1632         else
1633         {
1634                 // caller wants color array disabled
1635                 if (gl_state.pointer_color_enabled)
1636                 {
1637                         gl_state.pointer_color_enabled = false;
1638                         CHECKGLERROR
1639                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1640                         // when color array is on the glColor gets trashed, set it again
1641                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1642                 }
1643         }
1644 }
1645
1646 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset)
1647 {
1648         gltextureunit_t *unit = gl_state.units + unitnum;
1649         // update array settings
1650         CHECKGLERROR
1651         // note: there is no need to check bufferobject here because all cases
1652         // that involve a valid bufferobject also supply a texcoord array
1653         if (texcoord)
1654         {
1655                 if (!gl_vbo.integer)
1656                         bufferobject = 0;
1657                 // texture array unit is enabled, enable the array
1658                 if (!unit->arrayenabled)
1659                 {
1660                         unit->arrayenabled = true;
1661                         GL_ClientActiveTexture(unitnum);
1662                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1663                 }
1664                 // texcoord array
1665                 if (unit->pointer_texcoord != texcoord || unit->pointer_texcoord_buffer != bufferobject || unit->pointer_texcoord_offset != bufferoffset || unit->arraycomponents != numcomponents)
1666                 {
1667                         unit->pointer_texcoord = texcoord;
1668                         unit->pointer_texcoord_buffer = bufferobject;
1669                         unit->pointer_texcoord_offset = bufferoffset;
1670                         unit->arraycomponents = numcomponents;
1671                         GL_ClientActiveTexture(unitnum);
1672                         GL_BindVBO(bufferobject);
1673                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, bufferobject ? (void *)bufferoffset : texcoord);CHECKGLERROR
1674                 }
1675         }
1676         else
1677         {
1678                 // texture array unit is disabled, disable the array
1679                 if (unit->arrayenabled)
1680                 {
1681                         unit->arrayenabled = false;
1682                         GL_ClientActiveTexture(unitnum);
1683                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1684                 }
1685         }
1686 }
1687
1688 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap, int texrectangle)
1689 {
1690         gltextureunit_t *unit = gl_state.units + unitnum;
1691         if (unitnum >= backendimageunits)
1692                 return;
1693         // update 1d texture binding
1694         if (unit->t1d != tex1d)
1695         {
1696                 GL_ActiveTexture(unitnum);
1697                 if (unitnum < backendunits)
1698                 {
1699                         if (tex1d)
1700                         {
1701                                 if (unit->t1d == 0)
1702                                 {
1703                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1704                                 }
1705                         }
1706                         else
1707                         {
1708                                 if (unit->t1d)
1709                                 {
1710                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1711                                 }
1712                         }
1713                 }
1714                 unit->t1d = tex1d;
1715                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1716         }
1717         // update 2d texture binding
1718         if (unit->t2d != tex2d)
1719         {
1720                 GL_ActiveTexture(unitnum);
1721                 if (unitnum < backendunits)
1722                 {
1723                         if (tex2d)
1724                         {
1725                                 if (unit->t2d == 0)
1726                                 {
1727                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1728                                 }
1729                         }
1730                         else
1731                         {
1732                                 if (unit->t2d)
1733                                 {
1734                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1735                                 }
1736                         }
1737                 }
1738                 unit->t2d = tex2d;
1739                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1740         }
1741         // update 3d texture binding
1742         if (unit->t3d != tex3d)
1743         {
1744                 GL_ActiveTexture(unitnum);
1745                 if (unitnum < backendunits)
1746                 {
1747                         if (tex3d)
1748                         {
1749                                 if (unit->t3d == 0)
1750                                 {
1751                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1752                                 }
1753                         }
1754                         else
1755                         {
1756                                 if (unit->t3d)
1757                                 {
1758                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1759                                 }
1760                         }
1761                 }
1762                 unit->t3d = tex3d;
1763                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1764         }
1765         // update cubemap texture binding
1766         if (unit->tcubemap != texcubemap)
1767         {
1768                 GL_ActiveTexture(unitnum);
1769                 if (unitnum < backendunits)
1770                 {
1771                         if (texcubemap)
1772                         {
1773                                 if (unit->tcubemap == 0)
1774                                 {
1775                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1776                                 }
1777                         }
1778                         else
1779                         {
1780                                 if (unit->tcubemap)
1781                                 {
1782                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1783                                 }
1784                         }
1785                 }
1786                 unit->tcubemap = texcubemap;
1787                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1788         }
1789         // update rectangle texture binding
1790         if (unit->trectangle != texrectangle)
1791         {
1792                 GL_ActiveTexture(unitnum);
1793                 if (unitnum < backendunits)
1794                 {
1795                         if (texrectangle)
1796                         {
1797                                 if (unit->trectangle == 0)
1798                                 {
1799                                         qglEnable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1800                                 }
1801                         }
1802                         else
1803                         {
1804                                 if (unit->trectangle)
1805                                 {
1806                                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1807                                 }
1808                         }
1809                 }
1810                 unit->trectangle = texrectangle;
1811                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1812         }
1813 }
1814
1815 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1816 {
1817         gltextureunit_t *unit = gl_state.units + unitnum;
1818         if (unitnum >= backendimageunits)
1819                 return;
1820         // update 1d texture binding
1821         if (unit->t1d != texnum)
1822         {
1823                 GL_ActiveTexture(unitnum);
1824                 if (unitnum < backendunits)
1825                 {
1826                         if (texnum)
1827                         {
1828                                 if (unit->t1d == 0)
1829                                 {
1830                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1831                                 }
1832                         }
1833                         else
1834                         {
1835                                 if (unit->t1d)
1836                                 {
1837                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1838                                 }
1839                         }
1840                 }
1841                 unit->t1d = texnum;
1842                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1843         }
1844         // update 2d texture binding
1845         if (unit->t2d)
1846         {
1847                 GL_ActiveTexture(unitnum);
1848                 if (unitnum < backendunits)
1849                 {
1850                         if (unit->t2d)
1851                         {
1852                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1853                         }
1854                 }
1855                 unit->t2d = 0;
1856                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1857         }
1858         // update 3d texture binding
1859         if (unit->t3d)
1860         {
1861                 GL_ActiveTexture(unitnum);
1862                 if (unitnum < backendunits)
1863                 {
1864                         if (unit->t3d)
1865                         {
1866                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1867                         }
1868                 }
1869                 unit->t3d = 0;
1870                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1871         }
1872         // update cubemap texture binding
1873         if (unit->tcubemap)
1874         {
1875                 GL_ActiveTexture(unitnum);
1876                 if (unitnum < backendunits)
1877                 {
1878                         if (unit->tcubemap)
1879                         {
1880                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1881                         }
1882                 }
1883                 unit->tcubemap = 0;
1884                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1885         }
1886         // update rectangle texture binding
1887         if (unit->trectangle)
1888         {
1889                 GL_ActiveTexture(unitnum);
1890                 if (unitnum < backendunits)
1891                 {
1892                         if (unit->trectangle)
1893                         {
1894                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1895                         }
1896                 }
1897                 unit->trectangle = 0;
1898                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1899         }
1900 }
1901
1902 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1903 {
1904         gltextureunit_t *unit = gl_state.units + unitnum;
1905         if (unitnum >= backendimageunits)
1906                 return;
1907         // update 1d texture binding
1908         if (unit->t1d)
1909         {
1910                 GL_ActiveTexture(unitnum);
1911                 if (unitnum < backendunits)
1912                 {
1913                         if (unit->t1d)
1914                         {
1915                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1916                         }
1917                 }
1918                 unit->t1d = 0;
1919                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1920         }
1921         // update 2d texture binding
1922         if (unit->t2d != texnum)
1923         {
1924                 GL_ActiveTexture(unitnum);
1925                 if (unitnum < backendunits)
1926                 {
1927                         if (texnum)
1928                         {
1929                                 if (unit->t2d == 0)
1930                                 {
1931                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1932                                 }
1933                         }
1934                         else
1935                         {
1936                                 if (unit->t2d)
1937                                 {
1938                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1939                                 }
1940                         }
1941                 }
1942                 unit->t2d = texnum;
1943                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1944         }
1945         // update 3d texture binding
1946         if (unit->t3d)
1947         {
1948                 GL_ActiveTexture(unitnum);
1949                 if (unitnum < backendunits)
1950                 {
1951                         if (unit->t3d)
1952                         {
1953                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1954                         }
1955                 }
1956                 unit->t3d = 0;
1957                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1958         }
1959         // update cubemap texture binding
1960         if (unit->tcubemap != 0)
1961         {
1962                 GL_ActiveTexture(unitnum);
1963                 if (unitnum < backendunits)
1964                 {
1965                         if (unit->tcubemap)
1966                         {
1967                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1968                         }
1969                 }
1970                 unit->tcubemap = 0;
1971                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1972         }
1973         // update rectangle texture binding
1974         if (unit->trectangle != 0)
1975         {
1976                 GL_ActiveTexture(unitnum);
1977                 if (unitnum < backendunits)
1978                 {
1979                         if (unit->trectangle)
1980                         {
1981                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
1982                         }
1983                 }
1984                 unit->trectangle = 0;
1985                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1986         }
1987 }
1988
1989 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1990 {
1991         gltextureunit_t *unit = gl_state.units + unitnum;
1992         if (unitnum >= backendimageunits)
1993                 return;
1994         // update 1d texture binding
1995         if (unit->t1d)
1996         {
1997                 GL_ActiveTexture(unitnum);
1998                 if (unitnum < backendunits)
1999                 {
2000                         if (unit->t1d)
2001                         {
2002                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
2003                         }
2004                 }
2005                 unit->t1d = 0;
2006                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
2007         }
2008         // update 2d texture binding
2009         if (unit->t2d)
2010         {
2011                 GL_ActiveTexture(unitnum);
2012                 if (unitnum < backendunits)
2013                 {
2014                         if (unit->t2d)
2015                         {
2016                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
2017                         }
2018                 }
2019                 unit->t2d = 0;
2020                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
2021         }
2022         // update 3d texture binding
2023         if (unit->t3d != texnum)
2024         {
2025                 GL_ActiveTexture(unitnum);
2026                 if (unitnum < backendunits)
2027                 {
2028                         if (texnum)
2029                         {
2030                                 if (unit->t3d == 0)
2031                                 {
2032                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
2033                                 }
2034                         }
2035                         else
2036                         {
2037                                 if (unit->t3d)
2038                                 {
2039                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
2040                                 }
2041                         }
2042                 }
2043                 unit->t3d = texnum;
2044                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
2045         }
2046         // update cubemap texture binding
2047         if (unit->tcubemap != 0)
2048         {
2049                 GL_ActiveTexture(unitnum);
2050                 if (unitnum < backendunits)
2051                 {
2052                         if (unit->tcubemap)
2053                         {
2054                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2055                         }
2056                 }
2057                 unit->tcubemap = 0;
2058                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
2059         }
2060         // update rectangle texture binding
2061         if (unit->trectangle != 0)
2062         {
2063                 GL_ActiveTexture(unitnum);
2064                 if (unitnum < backendunits)
2065                 {
2066                         if (unit->trectangle)
2067                         {
2068                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2069                         }
2070                 }
2071                 unit->trectangle = 0;
2072                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
2073         }
2074 }
2075
2076 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
2077 {
2078         gltextureunit_t *unit = gl_state.units + unitnum;
2079         if (unitnum >= backendimageunits)
2080                 return;
2081         // update 1d texture binding
2082         if (unit->t1d)
2083         {
2084                 GL_ActiveTexture(unitnum);
2085                 if (unitnum < backendunits)
2086                 {
2087                         if (unit->t1d)
2088                         {
2089                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
2090                         }
2091                 }
2092                 unit->t1d = 0;
2093                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
2094         }
2095         // update 2d texture binding
2096         if (unit->t2d)
2097         {
2098                 GL_ActiveTexture(unitnum);
2099                 if (unitnum < backendunits)
2100                 {
2101                         if (unit->t2d)
2102                         {
2103                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
2104                         }
2105                 }
2106                 unit->t2d = 0;
2107                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
2108         }
2109         // update 3d texture binding
2110         if (unit->t3d)
2111         {
2112                 GL_ActiveTexture(unitnum);
2113                 if (unitnum < backendunits)
2114                 {
2115                         if (unit->t3d)
2116                         {
2117                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
2118                         }
2119                 }
2120                 unit->t3d = 0;
2121                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
2122         }
2123         // update cubemap texture binding
2124         if (unit->tcubemap != texnum)
2125         {
2126                 GL_ActiveTexture(unitnum);
2127                 if (unitnum < backendunits)
2128                 {
2129                         if (texnum)
2130                         {
2131                                 if (unit->tcubemap == 0)
2132                                 {
2133                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2134                                 }
2135                         }
2136                         else
2137                         {
2138                                 if (unit->tcubemap)
2139                                 {
2140                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2141                                 }
2142                         }
2143                 }
2144                 unit->tcubemap = texnum;
2145                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
2146         }
2147         // update rectangle texture binding
2148         if (unit->trectangle != 0)
2149         {
2150                 GL_ActiveTexture(unitnum);
2151                 if (unitnum < backendunits)
2152                 {
2153                         if (unit->trectangle)
2154                         {
2155                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2156                         }
2157                 }
2158                 unit->trectangle = 0;
2159                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
2160         }
2161 }
2162
2163 void R_Mesh_TexBindRectangle(unsigned int unitnum, int texnum)
2164 {
2165         gltextureunit_t *unit = gl_state.units + unitnum;
2166         if (unitnum >= backendimageunits)
2167                 return;
2168         // update 1d texture binding
2169         if (unit->t1d)
2170         {
2171                 GL_ActiveTexture(unitnum);
2172                 if (unitnum < backendunits)
2173                 {
2174                         if (unit->t1d)
2175                         {
2176                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
2177                         }
2178                 }
2179                 unit->t1d = 0;
2180                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
2181         }
2182         // update 2d texture binding
2183         if (unit->t2d)
2184         {
2185                 GL_ActiveTexture(unitnum);
2186                 if (unitnum < backendunits)
2187                 {
2188                         if (unit->t2d)
2189                         {
2190                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
2191                         }
2192                 }
2193                 unit->t2d = 0;
2194                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
2195         }
2196         // update 3d texture binding
2197         if (unit->t3d)
2198         {
2199                 GL_ActiveTexture(unitnum);
2200                 if (unitnum < backendunits)
2201                 {
2202                         if (unit->t3d)
2203                         {
2204                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
2205                         }
2206                 }
2207                 unit->t3d = 0;
2208                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
2209         }
2210         // update cubemap texture binding
2211         if (unit->tcubemap != 0)
2212         {
2213                 GL_ActiveTexture(unitnum);
2214                 if (unitnum < backendunits)
2215                 {
2216                         if (unit->tcubemap)
2217                         {
2218                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2219                         }
2220                 }
2221                 unit->tcubemap = 0;
2222                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
2223         }
2224         // update rectangle texture binding
2225         if (unit->trectangle != texnum)
2226         {
2227                 GL_ActiveTexture(unitnum);
2228                 if (unitnum < backendunits)
2229                 {
2230                         if (texnum)
2231                         {
2232                                 if (unit->trectangle == 0)
2233                                 {
2234                                         qglEnable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2235                                 }
2236                         }
2237                         else
2238                         {
2239                                 if (unit->trectangle)
2240                                 {
2241                                         qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2242                                 }
2243                         }
2244                 }
2245                 unit->trectangle = texnum;
2246                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
2247         }
2248 }
2249
2250 static const double gl_identitymatrix[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
2251
2252 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
2253 {
2254         gltextureunit_t *unit = gl_state.units + unitnum;
2255         if (matrix->m[3][3])
2256         {
2257                 // texmatrix specified, check if it is different
2258                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
2259                 {
2260                         double glmatrix[16];
2261                         unit->texmatrixenabled = true;
2262                         unit->matrix = *matrix;
2263                         CHECKGLERROR
2264                         Matrix4x4_ToArrayDoubleGL(&unit->matrix, glmatrix);
2265                         GL_ActiveTexture(unitnum);
2266                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2267                         qglLoadMatrixd(glmatrix);CHECKGLERROR
2268                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2269                 }
2270         }
2271         else
2272         {
2273                 // no texmatrix specified, revert to identity
2274                 if (unit->texmatrixenabled)
2275                 {
2276                         unit->texmatrixenabled = false;
2277                         unit->matrix = identitymatrix;
2278                         CHECKGLERROR
2279                         GL_ActiveTexture(unitnum);
2280                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2281                         qglLoadIdentity();CHECKGLERROR
2282                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2283                 }
2284         }
2285 }
2286
2287 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
2288 {
2289         gltextureunit_t *unit = gl_state.units + unitnum;
2290         CHECKGLERROR
2291         if (gl_combine.integer)
2292         {
2293                 // GL_ARB_texture_env_combine
2294                 if (!combinergb)
2295                         combinergb = GL_MODULATE;
2296                 if (!combinealpha)
2297                         combinealpha = GL_MODULATE;
2298                 if (!rgbscale)
2299                         rgbscale = 1;
2300                 if (!alphascale)
2301                         alphascale = 1;
2302                 if (unit->combinergb != combinergb)
2303                 {
2304                         unit->combinergb = combinergb;
2305                         GL_ActiveTexture(unitnum);
2306                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
2307                 }
2308                 if (unit->combinealpha != combinealpha)
2309                 {
2310                         unit->combinealpha = combinealpha;
2311                         GL_ActiveTexture(unitnum);
2312                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
2313                 }
2314                 if (unit->rgbscale != rgbscale)
2315                 {
2316                         GL_ActiveTexture(unitnum);
2317                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
2318                 }
2319                 if (unit->alphascale != alphascale)
2320                 {
2321                         GL_ActiveTexture(unitnum);
2322                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
2323                 }
2324         }
2325         else
2326         {
2327                 // normal GL texenv
2328                 if (!combinergb)
2329                         combinergb = GL_MODULATE;
2330                 if (unit->combinergb != combinergb)
2331                 {
2332                         unit->combinergb = combinergb;
2333                         GL_ActiveTexture(unitnum);
2334                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
2335                 }
2336         }
2337 }
2338
2339 void R_Mesh_TextureState(const rmeshstate_t *m)
2340 {
2341         unsigned int i;
2342
2343         BACKENDACTIVECHECK
2344
2345         CHECKGLERROR
2346         if (gl_backend_rebindtextures)
2347         {
2348                 gl_backend_rebindtextures = false;
2349                 GL_SetupTextureState();
2350                 CHECKGLERROR
2351         }
2352
2353         for (i = 0;i < backendimageunits;i++)
2354                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i], m->texrectangle[i]);
2355         for (i = 0;i < backendarrayunits;i++)
2356         {
2357                 if (m->pointer_texcoord3f[i])
2358                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
2359                 else
2360                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
2361         }
2362         for (i = 0;i < backendunits;i++)
2363         {
2364                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
2365                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
2366         }
2367         CHECKGLERROR
2368 }
2369
2370 void R_Mesh_ResetTextureState(void)
2371 {
2372         unsigned int unitnum;
2373
2374         BACKENDACTIVECHECK
2375
2376         CHECKGLERROR
2377         if (gl_backend_rebindtextures)
2378         {
2379                 gl_backend_rebindtextures = false;
2380                 GL_SetupTextureState();
2381                 CHECKGLERROR
2382         }
2383
2384         for (unitnum = 0;unitnum < backendimageunits;unitnum++)
2385         {
2386                 gltextureunit_t *unit = gl_state.units + unitnum;
2387                 // update 1d texture binding
2388                 if (unit->t1d)
2389                 {
2390                         GL_ActiveTexture(unitnum);
2391                         if (unitnum < backendunits)
2392                         {
2393                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
2394                         }
2395                         unit->t1d = 0;
2396                         qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
2397                 }
2398                 // update 2d texture binding
2399                 if (unit->t2d)
2400                 {
2401                         GL_ActiveTexture(unitnum);
2402                         if (unitnum < backendunits)
2403                         {
2404                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
2405                         }
2406                         unit->t2d = 0;
2407                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
2408                 }
2409                 // update 3d texture binding
2410                 if (unit->t3d)
2411                 {
2412                         GL_ActiveTexture(unitnum);
2413                         if (unitnum < backendunits)
2414                         {
2415                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
2416                         }
2417                         unit->t3d = 0;
2418                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
2419                 }
2420                 // update cubemap texture binding
2421                 if (unit->tcubemap)
2422                 {
2423                         GL_ActiveTexture(unitnum);
2424                         if (unitnum < backendunits)
2425                         {
2426                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2427                         }
2428                         unit->tcubemap = 0;
2429                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
2430                 }
2431                 // update rectangle texture binding
2432                 if (unit->trectangle)
2433                 {
2434                         GL_ActiveTexture(unitnum);
2435                         if (unitnum < backendunits)
2436                         {
2437                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2438                         }
2439                         unit->trectangle = 0;
2440                         qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
2441                 }
2442         }
2443         for (unitnum = 0;unitnum < backendarrayunits;unitnum++)
2444         {
2445                 gltextureunit_t *unit = gl_state.units + unitnum;
2446                 // texture array unit is disabled, disable the array
2447                 if (unit->arrayenabled)
2448                 {
2449                         unit->arrayenabled = false;
2450                         GL_ClientActiveTexture(unitnum);
2451                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
2452                 }
2453         }
2454         for (unitnum = 0;unitnum < backendunits;unitnum++)
2455         {
2456                 gltextureunit_t *unit = gl_state.units + unitnum;
2457                 // no texmatrix specified, revert to identity
2458                 if (unit->texmatrixenabled)
2459                 {
2460                         unit->texmatrixenabled = false;
2461                         unit->matrix = identitymatrix;
2462                         CHECKGLERROR
2463                         GL_ActiveTexture(unitnum);
2464                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2465                         qglLoadIdentity();CHECKGLERROR
2466                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2467                 }
2468                 if (gl_combine.integer)
2469                 {
2470                         // GL_ARB_texture_env_combine
2471                         if (unit->combinergb != GL_MODULATE)
2472                         {
2473                                 unit->combinergb = GL_MODULATE;
2474                                 GL_ActiveTexture(unitnum);
2475                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
2476                         }
2477                         if (unit->combinealpha != GL_MODULATE)
2478                         {
2479                                 unit->combinealpha = GL_MODULATE;
2480                                 GL_ActiveTexture(unitnum);
2481                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
2482                         }
2483                         if (unit->rgbscale != 1)
2484                         {
2485                                 GL_ActiveTexture(unitnum);
2486                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = 1));CHECKGLERROR
2487                         }
2488                         if (unit->alphascale != 1)
2489                         {
2490                                 GL_ActiveTexture(unitnum);
2491                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = 1));CHECKGLERROR
2492                         }
2493                 }
2494                 else
2495                 {
2496                         // normal GL texenv
2497                         if (unit->combinergb != GL_MODULATE)
2498                         {
2499                                 unit->combinergb = GL_MODULATE;
2500                                 GL_ActiveTexture(unitnum);
2501                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
2502                         }
2503                 }
2504         }
2505 }