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