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