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