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