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