]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
Merge PR 'Use the text from modinfo.txt as the mod menu entry'
[xonotic/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4
5 #define MAX_RENDERTARGETS 4
6
7 cvar_t gl_debug = {CF_CLIENT, "gl_debug", "0", "enables OpenGL debug output, 0 = off, 1 = HIGH severity only, 2 = also MEDIUM severity, 3 = also LOW severity messages.  (note: enabling may not take effect until vid_restart on some drivers)"};
8 cvar_t gl_paranoid = {CF_CLIENT, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
9 cvar_t gl_printcheckerror = {CF_CLIENT, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
10
11 cvar_t r_render = {CF_CLIENT, "r_render", "1", "enables rendering 3D views (you want this on!)"};
12 cvar_t r_renderview = {CF_CLIENT, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
13 cvar_t r_waterwarp = {CF_CLIENT | CF_ARCHIVE, "r_waterwarp", "1", "warp view while underwater"};
14 cvar_t gl_polyblend = {CF_CLIENT | CF_ARCHIVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
15
16 cvar_t v_flipped = {CF_CLIENT, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
17 qbool v_flipped_state = false;
18
19 r_viewport_t gl_viewport;
20 matrix4x4_t gl_modelmatrix;
21 matrix4x4_t gl_viewmatrix;
22 matrix4x4_t gl_modelviewmatrix;
23 matrix4x4_t gl_projectionmatrix;
24 matrix4x4_t gl_modelviewprojectionmatrix;
25 float gl_modelview16f[16];
26 float gl_modelviewprojection16f[16];
27 qbool gl_modelmatrixchanged;
28
29 #ifdef DEBUGGL
30 void GL_PrintError(GLenum errornumber, const char *filename, unsigned int linenumber)
31 {
32         switch(errornumber)
33         {
34 #ifdef GL_INVALID_ENUM
35         case GL_INVALID_ENUM:
36                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
37                 break;
38 #endif
39 #ifdef GL_INVALID_VALUE
40         case GL_INVALID_VALUE:
41                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
42                 break;
43 #endif
44 #ifdef GL_INVALID_OPERATION
45         case GL_INVALID_OPERATION:
46                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
47                 break;
48 #endif
49 #ifdef GL_STACK_OVERFLOW
50         case GL_STACK_OVERFLOW:
51                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
52                 break;
53 #endif
54 #ifdef GL_STACK_UNDERFLOW
55         case GL_STACK_UNDERFLOW:
56                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
57                 break;
58 #endif
59 #ifdef GL_OUT_OF_MEMORY
60         case GL_OUT_OF_MEMORY:
61                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
62                 break;
63 #endif
64 #ifdef GL_TABLE_TOO_LARGE
65         case GL_TABLE_TOO_LARGE:
66                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
67                 break;
68 #endif
69 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION
70         case GL_INVALID_FRAMEBUFFER_OPERATION:
71                 Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber);
72                 break;
73 #endif
74         default:
75                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
76                 break;
77         }
78 }
79
80 static void GLAPIENTRY GL_DebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const GLvoid* userParam)
81 {
82         const char *sev = "ENUM?", *typ = "ENUM?", *src = "ENUM?";
83         switch (severity)
84         {
85         case GL_DEBUG_SEVERITY_LOW_ARB: sev = "LOW"; break;
86         case GL_DEBUG_SEVERITY_MEDIUM_ARB: sev = "MED"; break;
87         case GL_DEBUG_SEVERITY_HIGH_ARB: sev = "HIGH"; break;
88         }
89         switch (type)
90         {
91         case GL_DEBUG_TYPE_ERROR_ARB: typ = "ERROR"; break;
92         case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: typ = "DEPRECATED"; break;
93         case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: typ = "UNDEFINED"; break;
94         case GL_DEBUG_TYPE_PORTABILITY_ARB: typ = "PORTABILITY"; break;
95         case GL_DEBUG_TYPE_PERFORMANCE_ARB: typ = "PERFORMANCE"; break;
96         case GL_DEBUG_TYPE_OTHER_ARB: typ = "OTHER"; break;
97         }
98         switch (source)
99         {
100         case GL_DEBUG_SOURCE_API_ARB: src = "API"; break;
101         case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: src = "SHADER"; break;
102         case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: src = "WIN"; break;
103         case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: src = "THIRDPARTY"; break;
104         case GL_DEBUG_SOURCE_APPLICATION_ARB: src = "APP"; break;
105         case GL_DEBUG_SOURCE_OTHER_ARB: src = "OTHER"; break;
106         }
107         Con_Printf("GLDEBUG: %s %s %s: %u: %s\n", sev, typ, src, (unsigned int)id, message);
108 }
109 #endif
110
111 #define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active");
112
113 void SCR_ScreenShot_f(cmd_state_t *cmd);
114
115 typedef struct gltextureunit_s
116 {
117         int pointer_texcoord_components;
118         int pointer_texcoord_gltype;
119         size_t pointer_texcoord_stride;
120         const void *pointer_texcoord_pointer;
121         const r_meshbuffer_t *pointer_texcoord_vertexbuffer;
122         size_t pointer_texcoord_offset;
123
124         rtexture_t *texture;
125         int t2d, t3d, tcubemap;
126         int arrayenabled;
127 }
128 gltextureunit_t;
129
130 typedef struct gl_state_s
131 {
132         int cullface;
133         int cullfaceenable;
134         int blendfunc1;
135         int blendfunc2;
136         qbool blend;
137         GLboolean depthmask;
138         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
139         int depthtest;
140         int depthfunc;
141         float depthrange[2];
142         float polygonoffset[2];
143         qbool alphatocoverage;
144         int scissortest;
145         unsigned int unit;
146         gltextureunit_t units[MAX_TEXTUREUNITS];
147         float color4f[4];
148         int lockrange_first;
149         int lockrange_count;
150         int vertexbufferobject;
151         int elementbufferobject;
152         int uniformbufferobject;
153         int framebufferobject;
154         int defaultframebufferobject; // deal with platforms that use a non-zero default fbo
155         qbool pointer_color_enabled;
156
157         // GL3.2 Core requires that we have a GL_VERTEX_ARRAY_OBJECT, but... just one.
158         unsigned int defaultvao;
159
160         int pointer_vertex_components;
161         int pointer_vertex_gltype;
162         size_t pointer_vertex_stride;
163         const void *pointer_vertex_pointer;
164         const r_meshbuffer_t *pointer_vertex_vertexbuffer;
165         size_t pointer_vertex_offset;
166
167         int pointer_color_components;
168         int pointer_color_gltype;
169         size_t pointer_color_stride;
170         const void *pointer_color_pointer;
171         const r_meshbuffer_t *pointer_color_vertexbuffer;
172         size_t pointer_color_offset;
173
174         void *preparevertices_tempdata;
175         size_t preparevertices_tempdatamaxsize;
176         int preparevertices_numvertices;
177
178         memexpandablearray_t meshbufferarray;
179
180         qbool active;
181 }
182 gl_state_t;
183
184 static gl_state_t gl_state;
185
186
187 /*
188 note: here's strip order for a terrain row:
189 0--1--2--3--4
190 |\ |\ |\ |\ |
191 | \| \| \| \|
192 A--B--C--D--E
193 clockwise
194
195 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
196
197 *elements++ = i + row;
198 *elements++ = i;
199 *elements++ = i + row + 1;
200 *elements++ = i;
201 *elements++ = i + 1;
202 *elements++ = i + row + 1;
203
204
205 for (y = 0;y < rows - 1;y++)
206 {
207         for (x = 0;x < columns - 1;x++)
208         {
209                 i = y * rows + x;
210                 *elements++ = i + columns;
211                 *elements++ = i;
212                 *elements++ = i + columns + 1;
213                 *elements++ = i;
214                 *elements++ = i + 1;
215                 *elements++ = i + columns + 1;
216         }
217 }
218
219 alternative:
220 0--1--2--3--4
221 | /| /|\ | /|
222 |/ |/ | \|/ |
223 A--B--C--D--E
224 counterclockwise
225
226 for (y = 0;y < rows - 1;y++)
227 {
228         for (x = 0;x < columns - 1;x++)
229         {
230                 i = y * rows + x;
231                 *elements++ = i;
232                 *elements++ = i + columns;
233                 *elements++ = i + columns + 1;
234                 *elements++ = i + columns;
235                 *elements++ = i + columns + 1;
236                 *elements++ = i + 1;
237         }
238 }
239 */
240
241 int polygonelement3i[(POLYGONELEMENTS_MAXPOINTS-2)*3];
242 unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3];
243 int quadelement3i[QUADELEMENTS_MAXQUADS*6];
244 unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6];
245
246 static void GL_VBOStats_f(cmd_state_t *cmd)
247 {
248         GL_Mesh_ListVBOs(true);
249 }
250
251 static void GL_Backend_ResetState(void);
252
253 static void gl_backend_start(void)
254 {
255         memset(&gl_state, 0, sizeof(gl_state));
256
257         Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128);
258
259         Con_Printf("OpenGL backend started\n");
260
261         CHECKGLERROR
262
263         switch(vid.renderpath)
264         {
265 #ifndef USE_GLES2
266         case RENDERPATH_GL32:
267                 // GL3.2 Core requires that we have a VAO bound - but using more than one has no performance benefit so this is just placeholder
268                 qglGenVertexArrays(1, &gl_state.defaultvao);
269                 qglBindVertexArray(gl_state.defaultvao);
270                 // fall through
271 #endif //USE_GLES2
272         case RENDERPATH_GLES2:
273                 // fetch current fbo here (default fbo is not 0 on some GLES devices)
274                 CHECKGLERROR
275                 qglGetIntegerv(GL_FRAMEBUFFER_BINDING, &gl_state.defaultframebufferobject);CHECKGLERROR
276                 break;
277         }
278
279         GL_Backend_ResetState();
280 }
281
282 static void gl_backend_shutdown(void)
283 {
284         Con_Print("OpenGL backend shutting down\n");
285
286         switch(vid.renderpath)
287         {
288         case RENDERPATH_GL32:
289         case RENDERPATH_GLES2:
290                 break;
291         }
292
293         if (gl_state.preparevertices_tempdata)
294                 Mem_Free(gl_state.preparevertices_tempdata);
295
296         Mem_ExpandableArray_FreeArray(&gl_state.meshbufferarray);
297
298         memset(&gl_state, 0, sizeof(gl_state));
299 }
300
301 static void gl_backend_newmap(void)
302 {
303 }
304
305 static void gl_backend_devicelost(void)
306 {
307         int i, endindex;
308         r_meshbuffer_t *buffer;
309         switch(vid.renderpath)
310         {
311         case RENDERPATH_GL32:
312         case RENDERPATH_GLES2:
313                 break;
314         }
315         endindex = (int)Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
316         for (i = 0;i < endindex;i++)
317         {
318                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
319                 if (!buffer || !buffer->isdynamic)
320                         continue;
321                 switch(vid.renderpath)
322                 {
323                 case RENDERPATH_GL32:
324                 case RENDERPATH_GLES2:
325                         break;
326                 }
327         }
328 }
329
330 static void gl_backend_devicerestored(void)
331 {
332         switch(vid.renderpath)
333         {
334         case RENDERPATH_GL32:
335         case RENDERPATH_GLES2:
336                 break;
337         }
338 }
339
340 void gl_backend_init(void)
341 {
342         int i;
343
344         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
345         {
346                 polygonelement3s[i * 3 + 0] = 0;
347                 polygonelement3s[i * 3 + 1] = i + 1;
348                 polygonelement3s[i * 3 + 2] = i + 2;
349         }
350         // elements for rendering a series of quads as triangles
351         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
352         {
353                 quadelement3s[i * 6 + 0] = i * 4;
354                 quadelement3s[i * 6 + 1] = i * 4 + 1;
355                 quadelement3s[i * 6 + 2] = i * 4 + 2;
356                 quadelement3s[i * 6 + 3] = i * 4;
357                 quadelement3s[i * 6 + 4] = i * 4 + 2;
358                 quadelement3s[i * 6 + 5] = i * 4 + 3;
359         }
360
361         for (i = 0;i < (POLYGONELEMENTS_MAXPOINTS - 2)*3;i++)
362                 polygonelement3i[i] = polygonelement3s[i];
363         for (i = 0;i < QUADELEMENTS_MAXQUADS*6;i++)
364                 quadelement3i[i] = quadelement3s[i];
365
366         Cvar_RegisterVariable(&r_render);
367         Cvar_RegisterVariable(&r_renderview);
368         Cvar_RegisterVariable(&r_waterwarp);
369         Cvar_RegisterVariable(&gl_polyblend);
370         Cvar_RegisterVariable(&v_flipped);
371         Cvar_RegisterVariable(&gl_debug);
372         Cvar_RegisterVariable(&gl_paranoid);
373         Cvar_RegisterVariable(&gl_printcheckerror);
374
375         Cmd_AddCommand(CF_CLIENT, "gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them");
376
377         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap, gl_backend_devicelost, gl_backend_devicerestored);
378 }
379
380 void GL_SetMirrorState(qbool state);
381
382 void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out)
383 {
384         vec4_t temp;
385         float iw;
386         Matrix4x4_Transform4 (&v->viewmatrix, in, temp);
387         Matrix4x4_Transform4 (&v->projectmatrix, temp, out);
388         iw = 1.0f / out[3];
389         out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f;
390
391         // for an odd reason, inverting this is wrong for R_Shadow_ScissorForBBox (we then get badly scissored lights)
392         //out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f;
393         out[1] = v->y + (out[1] * iw + 1.0f) * v->height * 0.5f;
394
395         out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f;
396 }
397
398 void GL_Finish(void)
399 {
400         switch(vid.renderpath)
401         {
402         case RENDERPATH_GL32:
403         case RENDERPATH_GLES2:
404                 CHECKGLERROR
405                 qglFinish();CHECKGLERROR
406                 break;
407         }
408 }
409
410 static int bboxedges[12][2] =
411 {
412         // top
413         {0, 1}, // +X
414         {0, 2}, // +Y
415         {1, 3}, // Y, +X
416         {2, 3}, // X, +Y
417         // bottom
418         {4, 5}, // +X
419         {4, 6}, // +Y
420         {5, 7}, // Y, +X
421         {6, 7}, // X, +Y
422         // verticals
423         {0, 4}, // +Z
424         {1, 5}, // X, +Z
425         {2, 6}, // Y, +Z
426         {3, 7}, // XY, +Z
427 };
428
429 qbool R_ScissorForBBox(const float *mins, const float *maxs, int *scissor)
430 {
431         int i, ix1, iy1, ix2, iy2;
432         float x1, y1, x2, y2;
433         vec4_t v, v2;
434         float vertex[20][3];
435         int j, k;
436         vec4_t plane4f;
437         int numvertices;
438         float corner[8][4];
439         float dist[8];
440         int sign[8];
441         float f;
442
443         scissor[0] = r_refdef.view.viewport.x;
444         scissor[1] = r_refdef.view.viewport.y;
445         scissor[2] = r_refdef.view.viewport.width;
446         scissor[3] = r_refdef.view.viewport.height;
447
448         // if view is inside the box, just say yes it's visible
449         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
450                 return false;
451
452         // transform all corners that are infront of the nearclip plane
453         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
454         plane4f[3] = r_refdef.view.frustum[4].dist;
455         numvertices = 0;
456         for (i = 0;i < 8;i++)
457         {
458                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
459                 dist[i] = DotProduct4(corner[i], plane4f);
460                 sign[i] = dist[i] > 0;
461                 if (!sign[i])
462                 {
463                         VectorCopy(corner[i], vertex[numvertices]);
464                         numvertices++;
465                 }
466         }
467         // if some points are behind the nearclip, add clipped edge points to make
468         // sure that the scissor boundary is complete
469         if (numvertices > 0 && numvertices < 8)
470         {
471                 // add clipped edge points
472                 for (i = 0;i < 12;i++)
473                 {
474                         j = bboxedges[i][0];
475                         k = bboxedges[i][1];
476                         if (sign[j] != sign[k])
477                         {
478                                 f = dist[j] / (dist[j] - dist[k]);
479                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
480                                 numvertices++;
481                         }
482                 }
483         }
484
485         // if we have no points to check, it is behind the view plane
486         if (!numvertices)
487                 return true;
488
489         // if we have some points to transform, check what screen area is covered
490         x1 = y1 = x2 = y2 = 0;
491         v[3] = 1.0f;
492         //Con_Printf("%i vertices to transform...\n", numvertices);
493         for (i = 0;i < numvertices;i++)
494         {
495                 VectorCopy(vertex[i], v);
496                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
497                 //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]);
498                 if (i)
499                 {
500                         if (x1 > v2[0]) x1 = v2[0];
501                         if (x2 < v2[0]) x2 = v2[0];
502                         if (y1 > v2[1]) y1 = v2[1];
503                         if (y2 < v2[1]) y2 = v2[1];
504                 }
505                 else
506                 {
507                         x1 = x2 = v2[0];
508                         y1 = y2 = v2[1];
509                 }
510         }
511
512         // now convert the scissor rectangle to integer screen coordinates
513         ix1 = (int)(x1 - 1.0f);
514         //iy1 = vid.height - (int)(y2 - 1.0f);
515         //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f);
516         iy1 = (int)(y1 - 1.0f);
517         ix2 = (int)(x2 + 1.0f);
518         //iy2 = vid.height - (int)(y1 + 1.0f);
519         //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f);
520         iy2 = (int)(y2 + 1.0f);
521         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
522
523         // clamp it to the screen
524         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
525         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
526         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
527         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
528
529         // if it is inside out, it's not visible
530         if (ix2 <= ix1 || iy2 <= iy1)
531                 return true;
532
533         // the light area is visible, set up the scissor rectangle
534         scissor[0] = ix1;
535         scissor[1] = iy1;
536         scissor[2] = ix2 - ix1;
537         scissor[3] = iy2 - iy1;
538
539         // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
540         switch(vid.renderpath)
541         {
542         case RENDERPATH_GL32:
543         case RENDERPATH_GLES2:
544                 break;
545         }
546
547         return false;
548 }
549
550
551 static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m, float normalx, float normaly, float normalz, float dist)
552 {
553         float q[4];
554         float d;
555         float clipPlane[4], v3[3], v4[3];
556         float normal[3];
557
558         // This is inspired by Oblique Depth Projection from http://www.terathon.com/code/oblique.php
559
560         VectorSet(normal, normalx, normaly, normalz);
561         Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane);
562         VectorScale(normal, -dist, v3);
563         Matrix4x4_Transform(&v->viewmatrix, v3, v4);
564         // FIXME: LadyHavoc: I think this can be done more efficiently somehow but I can't remember the technique
565         clipPlane[3] = -DotProduct(v4, clipPlane);
566
567         // Calculate the clip-space corner point opposite the clipping plane
568         // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
569         // transform it into camera space by multiplying it
570         // by the inverse of the projection matrix
571         q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + m[8]) / m[0];
572         q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + m[9]) / m[5];
573         q[2] = -1.0f;
574         q[3] = (1.0f + m[10]) / m[14];
575
576         // Calculate the scaled plane vector
577         d = 2.0f / DotProduct4(clipPlane, q);
578
579         // Replace the third row of the projection matrix
580         m[2] = clipPlane[0] * d;
581         m[6] = clipPlane[1] * d;
582         m[10] = clipPlane[2] * d + 1.0f;
583         m[14] = clipPlane[3] * d;
584 }
585
586 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)
587 {
588         float left = x1, right = x2, bottom = y2, top = y1, zNear = nearclip, zFar = farclip;
589         float m[16];
590         memset(v, 0, sizeof(*v));
591         v->type = R_VIEWPORTTYPE_ORTHO;
592         v->cameramatrix = *cameramatrix;
593         v->x = x;
594         v->y = y;
595         v->z = 0;
596         v->width = width;
597         v->height = height;
598         v->depth = 1;
599         memset(m, 0, sizeof(m));
600         m[0]  = 2/(right - left);
601         m[5]  = 2/(top - bottom);
602         m[10] = -2/(zFar - zNear);
603         m[12] = - (right + left)/(right - left);
604         m[13] = - (top + bottom)/(top - bottom);
605         m[14] = - (zFar + zNear)/(zFar - zNear);
606         m[15] = 1;
607         switch(vid.renderpath)
608         {
609         case RENDERPATH_GL32:
610         case RENDERPATH_GLES2:
611                 break;
612         }
613         v->screentodepth[0] = -farclip / (farclip - nearclip);
614         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
615
616         Matrix4x4_Invert_Full(&v->viewmatrix, &v->cameramatrix);
617
618         if (nearplane)
619                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
620
621         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
622
623 #if 0
624         {
625                 vec4_t test1;
626                 vec4_t test2;
627                 Vector4Set(test1, (x1+x2)*0.5f, (y1+y2)*0.5f, 0.0f, 1.0f);
628                 R_Viewport_TransformToScreen(v, test1, test2);
629                 Con_Printf("%f %f %f -> %f %f %f\n", test1[0], test1[1], test1[2], test2[0], test2[1], test2[2]);
630         }
631 #endif
632 }
633
634 void R_Viewport_InitOrtho3D(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)
635 {
636         matrix4x4_t tempmatrix, basematrix;
637         float m[16];
638         memset(v, 0, sizeof(*v));
639
640         v->type = R_VIEWPORTTYPE_PERSPECTIVE;
641         v->cameramatrix = *cameramatrix;
642         v->x = x;
643         v->y = y;
644         v->z = 0;
645         v->width = width;
646         v->height = height;
647         v->depth = 1;
648         memset(m, 0, sizeof(m));
649         m[0]  = 1.0 / frustumx;
650         m[5]  = 1.0 / frustumy;
651         m[10] = -2 / (farclip - nearclip);
652         m[14] = -(farclip + nearclip) / (farclip - nearclip);
653         m[15] = 1;
654         v->screentodepth[0] = -farclip / (farclip - nearclip);
655         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
656
657         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
658         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
659         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
660         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
661
662         if (nearplane)
663                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
664
665         if(v_flipped.integer)
666         {
667                 m[0] = -m[0];
668                 m[4] = -m[4];
669                 m[8] = -m[8];
670                 m[12] = -m[12];
671         }
672
673         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
674 }
675
676 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)
677 {
678         matrix4x4_t tempmatrix, basematrix;
679         float m[16];
680         memset(v, 0, sizeof(*v));
681
682         v->type = R_VIEWPORTTYPE_PERSPECTIVE;
683         v->cameramatrix = *cameramatrix;
684         v->x = x;
685         v->y = y;
686         v->z = 0;
687         v->width = width;
688         v->height = height;
689         v->depth = 1;
690         memset(m, 0, sizeof(m));
691         m[0]  = 1.0 / frustumx;
692         m[5]  = 1.0 / frustumy;
693         m[10] = -(farclip + nearclip) / (farclip - nearclip);
694         m[11] = -1;
695         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
696         v->screentodepth[0] = -farclip / (farclip - nearclip);
697         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
698
699         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
700         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
701         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
702         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
703
704         if (nearplane)
705                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
706
707         if(v_flipped.integer)
708         {
709                 m[0] = -m[0];
710                 m[4] = -m[4];
711                 m[8] = -m[8];
712                 m[12] = -m[12];
713         }
714
715         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
716 }
717
718 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)
719 {
720         matrix4x4_t tempmatrix, basematrix;
721         const float nudge = 1.0 - 1.0 / (1<<23);
722         float m[16];
723         memset(v, 0, sizeof(*v));
724
725         v->type = R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP;
726         v->cameramatrix = *cameramatrix;
727         v->x = x;
728         v->y = y;
729         v->z = 0;
730         v->width = width;
731         v->height = height;
732         v->depth = 1;
733         memset(m, 0, sizeof(m));
734         m[ 0] = 1.0 / frustumx;
735         m[ 5] = 1.0 / frustumy;
736         m[10] = -nudge;
737         m[11] = -1;
738         m[14] = -2 * nearclip * nudge;
739         v->screentodepth[0] = (m[10] + 1) * 0.5 - 1;
740         v->screentodepth[1] = m[14] * -0.5;
741
742         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
743         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
744         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
745         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
746
747         if (nearplane)
748                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
749
750         if(v_flipped.integer)
751         {
752                 m[0] = -m[0];
753                 m[4] = -m[4];
754                 m[8] = -m[8];
755                 m[12] = -m[12];
756         }
757
758         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
759 }
760
761 float cubeviewmatrix[6][16] =
762 {
763     // standard cubemap projections
764     { // +X
765          0, 0,-1, 0,
766          0,-1, 0, 0,
767         -1, 0, 0, 0,
768          0, 0, 0, 1,
769     },
770     { // -X
771          0, 0, 1, 0,
772          0,-1, 0, 0,
773          1, 0, 0, 0,
774          0, 0, 0, 1,
775     },
776     { // +Y
777          1, 0, 0, 0,
778          0, 0,-1, 0,
779          0, 1, 0, 0,
780          0, 0, 0, 1,
781     },
782     { // -Y
783          1, 0, 0, 0,
784          0, 0, 1, 0,
785          0,-1, 0, 0,
786          0, 0, 0, 1,
787     },
788     { // +Z
789          1, 0, 0, 0,
790          0,-1, 0, 0,
791          0, 0,-1, 0,
792          0, 0, 0, 1,
793     },
794     { // -Z
795         -1, 0, 0, 0,
796          0,-1, 0, 0,
797          0, 0, 1, 0,
798          0, 0, 0, 1,
799     },
800 };
801 float rectviewmatrix[6][16] =
802 {
803     // sign-preserving cubemap projections
804     { // +X
805          0, 0,-1, 0,
806          0, 1, 0, 0,
807          1, 0, 0, 0,
808          0, 0, 0, 1,
809     },
810     { // -X
811          0, 0, 1, 0,
812          0, 1, 0, 0,
813          1, 0, 0, 0,
814          0, 0, 0, 1,
815     },
816     { // +Y
817          1, 0, 0, 0,
818          0, 0,-1, 0,
819          0, 1, 0, 0,
820          0, 0, 0, 1,
821     },
822     { // -Y
823          1, 0, 0, 0,
824          0, 0, 1, 0,
825          0, 1, 0, 0,
826          0, 0, 0, 1,
827     },
828     { // +Z
829          1, 0, 0, 0,
830          0, 1, 0, 0,
831          0, 0,-1, 0,
832          0, 0, 0, 1,
833     },
834     { // -Z
835          1, 0, 0, 0,
836          0, 1, 0, 0,
837          0, 0, 1, 0,
838          0, 0, 0, 1,
839     },
840 };
841
842 void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane)
843 {
844         matrix4x4_t tempmatrix, basematrix;
845         float m[16];
846         memset(v, 0, sizeof(*v));
847         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
848         v->cameramatrix = *cameramatrix;
849         v->width = size;
850         v->height = size;
851         v->depth = 1;
852         memset(m, 0, sizeof(m));
853         m[0] = m[5] = 1.0f;
854         m[10] = -(farclip + nearclip) / (farclip - nearclip);
855         m[11] = -1;
856         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
857
858         Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]);
859         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
860         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
861
862         if (nearplane)
863                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
864
865         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
866 }
867
868 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, int offsetx, int offsety)
869 {
870         matrix4x4_t tempmatrix, basematrix;
871         float m[16];
872         memset(v, 0, sizeof(*v));
873         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
874         v->cameramatrix = *cameramatrix;
875         v->x = offsetx + (side & 1) * size;
876         v->y = offsety + (side >> 1) * size;
877         v->width = size;
878         v->height = size;
879         v->depth = 1;
880         memset(m, 0, sizeof(m));
881         m[0] = m[5] = 1.0f * ((float)size - border) / size;
882         m[10] = -(farclip + nearclip) / (farclip - nearclip);
883         m[11] = -1;
884         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
885
886         Matrix4x4_FromArrayFloatGL(&basematrix, rectviewmatrix[side]);
887         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
888         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
889
890         if (nearplane)
891                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
892
893         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
894 }
895
896 void R_SetViewport(const r_viewport_t *v)
897 {
898         gl_viewport = *v;
899
900         // FIXME: v_flipped_state is evil, this probably breaks somewhere
901         GL_SetMirrorState(v_flipped.integer && (v->type == R_VIEWPORTTYPE_PERSPECTIVE || v->type == R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP));
902
903         // copy over the matrices to our state
904         gl_viewmatrix = v->viewmatrix;
905         gl_projectionmatrix = v->projectmatrix;
906
907         switch(vid.renderpath)
908         {
909         case RENDERPATH_GL32:
910         case RENDERPATH_GLES2:
911                 CHECKGLERROR
912                 qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
913                 break;
914         }
915
916         // force an update of the derived matrices
917         gl_modelmatrixchanged = true;
918         R_EntityMatrix(&gl_modelmatrix);
919 }
920
921 void R_GetViewport(r_viewport_t *v)
922 {
923         *v = gl_viewport;
924 }
925
926 static void GL_BindVBO(int bufferobject)
927 {
928         if (gl_state.vertexbufferobject != bufferobject)
929         {
930                 gl_state.vertexbufferobject = bufferobject;
931                 CHECKGLERROR
932                 qglBindBuffer(GL_ARRAY_BUFFER, bufferobject);CHECKGLERROR
933         }
934 }
935
936 static void GL_BindEBO(int bufferobject)
937 {
938         if (gl_state.elementbufferobject != bufferobject)
939         {
940                 gl_state.elementbufferobject = bufferobject;
941                 CHECKGLERROR
942                 qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferobject);CHECKGLERROR
943         }
944 }
945
946 static void GL_BindUBO(int bufferobject)
947 {
948         if (gl_state.uniformbufferobject != bufferobject)
949         {
950                 gl_state.uniformbufferobject = bufferobject;
951 #ifdef GL_UNIFORM_BUFFER
952                 CHECKGLERROR
953                 qglBindBuffer(GL_UNIFORM_BUFFER, bufferobject);CHECKGLERROR
954 #endif
955         }
956 }
957
958 static const GLuint drawbuffers[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
959 int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
960 {
961         int temp;
962         GLuint status;
963         switch(vid.renderpath)
964         {
965         case RENDERPATH_GL32:
966         case RENDERPATH_GLES2:
967                 CHECKGLERROR
968                 qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
969                 R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
970                 // GL_ARB_framebuffer_object (GL3-class hardware) - depth stencil attachment
971 #ifdef USE_GLES2
972                 // FIXME: separate stencil attachment on GLES
973                 if (depthtexture  && depthtexture->texnum ) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR }
974                 if (depthtexture  && depthtexture->renderbuffernum ) { qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR }
975 #else
976                 if (depthtexture  && depthtexture->texnum )
977                 {
978                         qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
979                         if (depthtexture->glisdepthstencil) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR }
980                 }
981                 if (depthtexture  && depthtexture->renderbuffernum )
982                 {
983                         qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
984                         if (depthtexture->glisdepthstencil) { qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR }
985                 }
986 #endif
987                 if (colortexture  && colortexture->texnum ) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR }
988                 if (colortexture2 && colortexture2->texnum) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR }
989                 if (colortexture3 && colortexture3->texnum) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR }
990                 if (colortexture4 && colortexture4->texnum) { qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR }
991                 if (colortexture  && colortexture->renderbuffernum ) { qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR }
992                 if (colortexture2 && colortexture2->renderbuffernum) { qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR }
993                 if (colortexture3 && colortexture3->renderbuffernum) { qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR }
994                 if (colortexture4 && colortexture4->renderbuffernum) { qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR }
995
996 #ifndef USE_GLES2
997                 if (colortexture4)
998                 {
999                         qglDrawBuffers(4, drawbuffers);CHECKGLERROR
1000                         qglReadBuffer(GL_NONE);CHECKGLERROR
1001                 }
1002                 else if (colortexture3)
1003                 {
1004                         qglDrawBuffers(3, drawbuffers);CHECKGLERROR
1005                         qglReadBuffer(GL_NONE);CHECKGLERROR
1006                 }
1007                 else if (colortexture2)
1008                 {
1009                         qglDrawBuffers(2, drawbuffers);CHECKGLERROR
1010                         qglReadBuffer(GL_NONE);CHECKGLERROR
1011                 }
1012                 else if (colortexture)
1013                 {
1014                         qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
1015                         qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
1016                 }
1017                 else
1018                 {
1019                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1020                         qglReadBuffer(GL_NONE);CHECKGLERROR
1021                 }
1022 #endif
1023                 status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
1024                 if (status != GL_FRAMEBUFFER_COMPLETE)
1025                 {
1026                         Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
1027                         gl_state.framebufferobject = 0; // GL unbinds it for us
1028                         qglDeleteFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
1029                         temp = 0;
1030                 }
1031                 return temp;
1032         }
1033         return 0;
1034 }
1035
1036 void R_Mesh_DestroyFramebufferObject(int fbo)
1037 {
1038         switch(vid.renderpath)
1039         {
1040         case RENDERPATH_GL32:
1041         case RENDERPATH_GLES2:
1042                 if (fbo)
1043                 {
1044                         // GL clears the binding if we delete something bound
1045                         if (gl_state.framebufferobject == fbo)
1046                                 gl_state.framebufferobject = 0;
1047                         qglDeleteFramebuffers(1, (GLuint*)&fbo);CHECKGLERROR
1048                 }
1049                 break;
1050         }
1051 }
1052
1053 void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
1054 {
1055         unsigned int i;
1056         unsigned int j;
1057         rtexture_t *textures[5];
1058         Vector4Set(textures, colortexture, colortexture2, colortexture3, colortexture4);
1059         textures[4] = depthtexture;
1060         // unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target
1061         for (j = 0;j < 5;j++)
1062                 if (textures[j])
1063                         for (i = 0;i < MAX_TEXTUREUNITS;i++)
1064                                 if (gl_state.units[i].texture == textures[j])
1065                                         R_Mesh_TexBind(i, NULL);
1066         // set up framebuffer object or render targets for the active rendering API
1067         switch (vid.renderpath)
1068         {
1069         case RENDERPATH_GL32:
1070         case RENDERPATH_GLES2:
1071                 if (gl_state.framebufferobject != fbo)
1072                 {
1073                         gl_state.framebufferobject = fbo;
1074                         qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);CHECKGLERROR
1075                 }
1076                 break;
1077         }
1078 }
1079
1080 static void GL_Backend_ResetState(void)
1081 {
1082         gl_state.active = true;
1083         gl_state.depthtest = true;
1084         gl_state.alphatocoverage = false;
1085         gl_state.blendfunc1 = GL_ONE;
1086         gl_state.blendfunc2 = GL_ZERO;
1087         gl_state.blend = false;
1088         gl_state.depthmask = GL_TRUE;
1089         gl_state.colormask = 15;
1090         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
1091         gl_state.lockrange_first = 0;
1092         gl_state.lockrange_count = 0;
1093         gl_state.cullface = GL_FRONT;
1094         gl_state.cullfaceenable = false;
1095         gl_state.polygonoffset[0] = 0;
1096         gl_state.polygonoffset[1] = 0;
1097         gl_state.framebufferobject = 0;
1098         gl_state.depthfunc = GL_LEQUAL;
1099
1100         switch(vid.renderpath)
1101         {
1102         case RENDERPATH_GL32:
1103         case RENDERPATH_GLES2:
1104                 // set up debug output early
1105 #ifdef DEBUGGL
1106                 if (vid.support.arb_debug_output)
1107                 {
1108                         GLuint unused = 0;
1109                         CHECKGLERROR
1110                         if (gl_debug.integer >= 1)
1111                                 qglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
1112                         if (gl_debug.integer >= 3)
1113                                 qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unused, gl_debug.integer >= 3 ? GL_TRUE : GL_FALSE);
1114                         else if (gl_debug.integer >= 1)
1115                         {
1116                                 qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, &unused, gl_debug.integer >= 3 ? GL_TRUE : GL_FALSE);
1117                                 qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM_ARB, 0, &unused, gl_debug.integer >= 2 ? GL_TRUE : GL_FALSE);
1118                                 qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH_ARB, 0, &unused, gl_debug.integer >= 1 ? GL_TRUE : GL_FALSE);
1119                         }
1120                         else
1121                                 qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unused, GL_FALSE);
1122                         qglDebugMessageCallbackARB(GL_DebugOutputCallback, NULL);
1123                 }
1124 #endif //DEBUGGL
1125                 CHECKGLERROR
1126                 qglColorMask(1, 1, 1, 1);CHECKGLERROR
1127                 qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1128                 qglDisable(GL_BLEND);CHECKGLERROR
1129                 qglCullFace(gl_state.cullface);CHECKGLERROR
1130                 qglDisable(GL_CULL_FACE);CHECKGLERROR
1131                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1132                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1133                 qglDepthMask(gl_state.depthmask);CHECKGLERROR
1134                 qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1135                 qglBindBuffer(GL_ARRAY_BUFFER, 0);
1136                 qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1137                 qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.defaultframebufferobject);
1138                 qglEnableVertexAttribArray(GLSLATTRIB_POSITION);
1139                 qglDisableVertexAttribArray(GLSLATTRIB_COLOR);
1140                 qglVertexAttrib4f(GLSLATTRIB_COLOR, 1, 1, 1, 1);
1141                 gl_state.unit = MAX_TEXTUREUNITS;
1142                 CHECKGLERROR
1143                 break;
1144         }
1145 }
1146
1147 void GL_ActiveTexture(unsigned int num)
1148 {
1149         if (gl_state.unit != num)
1150         {
1151                 gl_state.unit = num;
1152                 switch(vid.renderpath)
1153                 {
1154                 case RENDERPATH_GL32:
1155                 case RENDERPATH_GLES2:
1156                         CHECKGLERROR
1157                         qglActiveTexture(GL_TEXTURE0 + gl_state.unit);CHECKGLERROR
1158                         break;
1159                 }
1160         }
1161 }
1162
1163 void GL_BlendFunc(int blendfunc1, int blendfunc2)
1164 {
1165         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
1166         {
1167                 qbool blendenable;
1168                 gl_state.blendfunc1 = blendfunc1;
1169                 gl_state.blendfunc2 = blendfunc2;
1170                 blendenable = (gl_state.blendfunc1 != GL_ONE || gl_state.blendfunc2 != GL_ZERO);
1171                 switch(vid.renderpath)
1172                 {
1173                 case RENDERPATH_GL32:
1174                 case RENDERPATH_GLES2:
1175                         CHECKGLERROR
1176                         if (qglBlendFuncSeparate)
1177                         {
1178                                 qglBlendFuncSeparate(gl_state.blendfunc1, gl_state.blendfunc2, GL_ZERO, GL_ONE);CHECKGLERROR // ELUAN: Adreno 225 (and others) compositing workaround
1179                         }
1180                         else
1181                         {
1182                                 qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1183                         }
1184                         if (gl_state.blend != blendenable)
1185                         {
1186                                 gl_state.blend = blendenable;
1187                                 if (!gl_state.blend)
1188                                 {
1189                                         qglDisable(GL_BLEND);CHECKGLERROR
1190                                 }
1191                                 else
1192                                 {
1193                                         qglEnable(GL_BLEND);CHECKGLERROR
1194                                 }
1195                         }
1196                         break;
1197                 }
1198         }
1199 }
1200
1201 void GL_DepthMask(int state)
1202 {
1203         if (gl_state.depthmask != state)
1204         {
1205                 gl_state.depthmask = state;
1206                 switch(vid.renderpath)
1207                 {
1208                 case RENDERPATH_GL32:
1209                 case RENDERPATH_GLES2:
1210                         CHECKGLERROR
1211                         qglDepthMask(gl_state.depthmask);CHECKGLERROR
1212                         break;
1213                 }
1214         }
1215 }
1216
1217 void GL_DepthTest(int state)
1218 {
1219         if (gl_state.depthtest != state)
1220         {
1221                 gl_state.depthtest = state;
1222                 switch(vid.renderpath)
1223                 {
1224                 case RENDERPATH_GL32:
1225                 case RENDERPATH_GLES2:
1226                         CHECKGLERROR
1227                         if (gl_state.depthtest)
1228                         {
1229                                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1230                         }
1231                         else
1232                         {
1233                                 qglDisable(GL_DEPTH_TEST);CHECKGLERROR
1234                         }
1235                         break;
1236                 }
1237         }
1238 }
1239
1240 void GL_DepthFunc(int state)
1241 {
1242         if (gl_state.depthfunc != state)
1243         {
1244                 gl_state.depthfunc = state;
1245                 switch(vid.renderpath)
1246                 {
1247                 case RENDERPATH_GL32:
1248                 case RENDERPATH_GLES2:
1249                         CHECKGLERROR
1250                         qglDepthFunc(gl_state.depthfunc);CHECKGLERROR
1251                         break;
1252                 }
1253         }
1254 }
1255
1256 void GL_DepthRange(float nearfrac, float farfrac)
1257 {
1258         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
1259         {
1260                 gl_state.depthrange[0] = nearfrac;
1261                 gl_state.depthrange[1] = farfrac;
1262                 switch(vid.renderpath)
1263                 {
1264                 case RENDERPATH_GL32:
1265                 case RENDERPATH_GLES2:
1266                         CHECKGLERROR
1267 #ifdef USE_GLES2
1268                         qglDepthRangef(gl_state.depthrange[0], gl_state.depthrange[1]);CHECKGLERROR
1269 #else
1270                         qglDepthRange(gl_state.depthrange[0], gl_state.depthrange[1]);CHECKGLERROR
1271 #endif
1272                         break;
1273                 }
1274         }
1275 }
1276
1277 void R_SetStencil(qbool enable, int writemask, int fail, int zfail, int zpass, int compare, int comparereference, int comparemask)
1278 {
1279         switch (vid.renderpath)
1280         {
1281         case RENDERPATH_GL32:
1282         case RENDERPATH_GLES2:
1283                 CHECKGLERROR
1284                 if (enable)
1285                 {
1286                         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1287                 }
1288                 else
1289                 {
1290                         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1291                 }
1292                 qglStencilMask(writemask);CHECKGLERROR
1293                 qglStencilOp(fail, zfail, zpass);CHECKGLERROR
1294                 qglStencilFunc(compare, comparereference, comparemask);CHECKGLERROR
1295                 CHECKGLERROR
1296                 break;
1297         }
1298 }
1299
1300 void GL_PolygonOffset(float planeoffset, float depthoffset)
1301 {
1302         if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset)
1303         {
1304                 gl_state.polygonoffset[0] = planeoffset;
1305                 gl_state.polygonoffset[1] = depthoffset;
1306                 switch(vid.renderpath)
1307                 {
1308                 case RENDERPATH_GL32:
1309                 case RENDERPATH_GLES2:
1310                         CHECKGLERROR
1311                         qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);CHECKGLERROR
1312                         break;
1313                 }
1314         }
1315 }
1316
1317 void GL_SetMirrorState(qbool state)
1318 {
1319         if (v_flipped_state != state)
1320         {
1321                 v_flipped_state = state;
1322                 if (gl_state.cullface == GL_BACK)
1323                         gl_state.cullface = GL_FRONT;
1324                 else if (gl_state.cullface == GL_FRONT)
1325                         gl_state.cullface = GL_BACK;
1326                 else
1327                         return;
1328                 switch(vid.renderpath)
1329                 {
1330                 case RENDERPATH_GL32:
1331                 case RENDERPATH_GLES2:
1332                         CHECKGLERROR
1333                         qglCullFace(gl_state.cullface);CHECKGLERROR
1334                         break;
1335                 }
1336         }
1337 }
1338
1339 void GL_CullFace(int state)
1340 {
1341         if(v_flipped_state)
1342         {
1343                 if(state == GL_FRONT)
1344                         state = GL_BACK;
1345                 else if(state == GL_BACK)
1346                         state = GL_FRONT;
1347         }
1348
1349         switch(vid.renderpath)
1350         {
1351         case RENDERPATH_GL32:
1352         case RENDERPATH_GLES2:
1353                 CHECKGLERROR
1354
1355                 if (state != GL_NONE)
1356                 {
1357                         if (!gl_state.cullfaceenable)
1358                         {
1359                                 gl_state.cullfaceenable = true;
1360                                 qglEnable(GL_CULL_FACE);CHECKGLERROR
1361                         }
1362                         if (gl_state.cullface != state)
1363                         {
1364                                 gl_state.cullface = state;
1365                                 qglCullFace(gl_state.cullface);CHECKGLERROR
1366                         }
1367                 }
1368                 else
1369                 {
1370                         if (gl_state.cullfaceenable)
1371                         {
1372                                 gl_state.cullfaceenable = false;
1373                                 qglDisable(GL_CULL_FACE);CHECKGLERROR
1374                         }
1375                 }
1376                 break;
1377         }
1378 }
1379
1380 void GL_AlphaToCoverage(qbool state)
1381 {
1382         if (gl_state.alphatocoverage != state)
1383         {
1384                 gl_state.alphatocoverage = state;
1385                 switch(vid.renderpath)
1386                 {
1387                 case RENDERPATH_GLES2:
1388                         break;
1389                 case RENDERPATH_GL32:
1390 #ifndef USE_GLES2
1391                         // alpha to coverage turns the alpha value of the pixel into 0%, 25%, 50%, 75% or 100% by masking the multisample fragments accordingly
1392                         CHECKGLERROR
1393                         if (gl_state.alphatocoverage)
1394                         {
1395                                 qglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);CHECKGLERROR
1396 //                              qglEnable(GL_MULTISAMPLE);CHECKGLERROR
1397                         }
1398                         else
1399                         {
1400                                 qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);CHECKGLERROR
1401 //                              qglDisable(GL_MULTISAMPLE);CHECKGLERROR
1402                         }
1403 #endif
1404                         break;
1405                 }
1406         }
1407 }
1408
1409 void GL_ColorMask(int r, int g, int b, int a)
1410 {
1411         // NOTE: this matches D3DCOLORWRITEENABLE_RED, GREEN, BLUE, ALPHA
1412         int state = (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0) | (a ? 8 : 0);
1413         if (gl_state.colormask != state)
1414         {
1415                 gl_state.colormask = state;
1416                 switch(vid.renderpath)
1417                 {
1418                 case RENDERPATH_GL32:
1419                 case RENDERPATH_GLES2:
1420                         CHECKGLERROR
1421                         qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
1422                         break;
1423                 }
1424         }
1425 }
1426
1427 void GL_Color(float cr, float cg, float cb, float ca)
1428 {
1429         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)
1430         {
1431                 gl_state.color4f[0] = cr;
1432                 gl_state.color4f[1] = cg;
1433                 gl_state.color4f[2] = cb;
1434                 gl_state.color4f[3] = ca;
1435                 switch(vid.renderpath)
1436                 {
1437                 case RENDERPATH_GL32:
1438                 case RENDERPATH_GLES2:
1439                         qglVertexAttrib4f(GLSLATTRIB_COLOR, cr, cg, cb, ca);CHECKGLERROR
1440                         break;
1441                 }
1442         }
1443 }
1444
1445 void GL_Scissor (int x, int y, int width, int height)
1446 {
1447         switch(vid.renderpath)
1448         {
1449         case RENDERPATH_GL32:
1450         case RENDERPATH_GLES2:
1451                 CHECKGLERROR
1452                 qglScissor(x, y,width,height);CHECKGLERROR
1453                 break;
1454         }
1455 }
1456
1457 void GL_ScissorTest(int state)
1458 {
1459         if (gl_state.scissortest != state)
1460         {
1461                 gl_state.scissortest = state;
1462                 switch(vid.renderpath)
1463                 {
1464                 case RENDERPATH_GL32:
1465                 case RENDERPATH_GLES2:
1466                         CHECKGLERROR
1467                         if(gl_state.scissortest)
1468                                 qglEnable(GL_SCISSOR_TEST);
1469                         else
1470                                 qglDisable(GL_SCISSOR_TEST);
1471                         CHECKGLERROR
1472                         break;
1473                 }
1474         }
1475 }
1476
1477 void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilvalue)
1478 {
1479         // opaque black - if you want transparent black, you'll need to pass in a colorvalue
1480         static const float blackcolor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
1481         // prevent warnings when trying to clear a buffer that does not exist
1482         if (!colorvalue)
1483                 colorvalue = blackcolor;
1484         if (!vid.stencil)
1485         {
1486                 mask &= ~GL_STENCIL_BUFFER_BIT;
1487                 stencilvalue = 0;
1488         }
1489         switch(vid.renderpath)
1490         {
1491         case RENDERPATH_GL32:
1492         case RENDERPATH_GLES2:
1493                 CHECKGLERROR
1494                 if (mask & GL_COLOR_BUFFER_BIT)
1495                 {
1496                         qglClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);CHECKGLERROR
1497                 }
1498                 if (mask & GL_DEPTH_BUFFER_BIT)
1499                 {
1500 #ifdef USE_GLES2
1501                         //qglClearDepthf(depthvalue);CHECKGLERROR
1502 #else
1503                         qglClearDepth(depthvalue);CHECKGLERROR
1504 #endif
1505                 }
1506                 if (mask & GL_STENCIL_BUFFER_BIT)
1507                 {
1508                         qglClearStencil(stencilvalue);CHECKGLERROR
1509                 }
1510                 qglClear(mask);CHECKGLERROR
1511                 break;
1512         }
1513 }
1514
1515 void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels)
1516 {
1517         switch(vid.renderpath)
1518         {
1519         case RENDERPATH_GL32:
1520         case RENDERPATH_GLES2:
1521                 CHECKGLERROR
1522 #ifndef GL_BGRA
1523                 {
1524                         int i;
1525                         int r;
1526                 //      int g;
1527                         int b;
1528                 //      int a;
1529                         qglReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, outpixels);CHECKGLERROR
1530                         for (i = 0;i < width * height * 4;i += 4)
1531                         {
1532                                 r = outpixels[i+0];
1533                 //              g = outpixels[i+1];
1534                                 b = outpixels[i+2];
1535                 //              a = outpixels[i+3];
1536                                 outpixels[i+0] = b;
1537                 //              outpixels[i+1] = g;
1538                                 outpixels[i+2] = r;
1539                 //              outpixels[i+3] = a;
1540                         }
1541                 }
1542 #else
1543                 qglReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, outpixels);CHECKGLERROR
1544 #endif
1545                         break;
1546         }
1547 }
1548
1549 // called at beginning of frame
1550 void R_Mesh_Start(void)
1551 {
1552         BACKENDACTIVECHECK
1553         R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
1554         if (gl_printcheckerror.integer && !gl_paranoid.integer)
1555         {
1556                 Con_Printf(CON_WARN "WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
1557                 Cvar_SetValueQuick(&gl_paranoid, 1);
1558         }
1559 }
1560
1561 static qbool GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
1562 {
1563         int shaderobject;
1564         int shadercompiled;
1565         char compilelog[MAX_INPUTLINE];
1566         shaderobject = qglCreateShader(shadertypeenum);CHECKGLERROR
1567         if (!shaderobject)
1568                 return false;
1569         qglShaderSource(shaderobject, numstrings, strings, NULL);CHECKGLERROR
1570         qglCompileShader(shaderobject);CHECKGLERROR
1571         qglGetShaderiv(shaderobject, GL_COMPILE_STATUS, &shadercompiled);CHECKGLERROR
1572         qglGetShaderInfoLog(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
1573         if (compilelog[0] && ((strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error")) || ((strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")) && developer.integer) || developer_extra.integer))
1574         {
1575                 int i, j, pretextlines = 0;
1576                 for (i = 0;i < numstrings - 1;i++)
1577                         for (j = 0;strings[i][j];j++)
1578                                 if (strings[i][j] == '\n')
1579                                         pretextlines++;
1580                 Con_Printf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
1581         }
1582         if (!shadercompiled)
1583         {
1584                 qglDeleteShader(shaderobject);CHECKGLERROR
1585                 return false;
1586         }
1587         qglAttachShader(programobject, shaderobject);CHECKGLERROR
1588         qglDeleteShader(shaderobject);CHECKGLERROR
1589         return true;
1590 }
1591
1592 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)
1593 {
1594         GLint programlinked;
1595         GLuint programobject = 0;
1596         char linklog[MAX_INPUTLINE];
1597         CHECKGLERROR
1598
1599         programobject = qglCreateProgram();CHECKGLERROR
1600         if (!programobject)
1601                 return 0;
1602
1603         qglBindAttribLocation(programobject, GLSLATTRIB_POSITION , "Attrib_Position" );
1604         qglBindAttribLocation(programobject, GLSLATTRIB_COLOR    , "Attrib_Color"    );
1605         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD0, "Attrib_TexCoord0");
1606         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD1, "Attrib_TexCoord1");
1607         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD2, "Attrib_TexCoord2");
1608         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD3, "Attrib_TexCoord3");
1609         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD4, "Attrib_TexCoord4");
1610         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD5, "Attrib_TexCoord5");
1611         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD6, "Attrib_SkeletalIndex");
1612         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD7, "Attrib_SkeletalWeight");
1613 #ifndef USE_GLES2
1614         qglBindFragDataLocation(programobject, 0, "dp_FragColor");
1615 #endif
1616         CHECKGLERROR
1617
1618         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER, "vertex", vertexstrings_count, vertexstrings_list))
1619                 goto cleanup;
1620
1621 #if defined(GL_GEOMETRY_SHADER) && !defined(USE_GLES2)
1622         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER, "geometry", geometrystrings_count, geometrystrings_list))
1623                 goto cleanup;
1624 #endif
1625
1626         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER, "fragment", fragmentstrings_count, fragmentstrings_list))
1627                 goto cleanup;
1628
1629         qglLinkProgram(programobject);CHECKGLERROR
1630         qglGetProgramiv(programobject, GL_LINK_STATUS, &programlinked);CHECKGLERROR
1631         qglGetProgramInfoLog(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
1632
1633         if (linklog[0])
1634         {
1635
1636                 if (strstr(linklog, "error") || strstr(linklog, "ERROR") || strstr(linklog, "Error") || strstr(linklog, "WARNING") || strstr(linklog, "warning") || strstr(linklog, "Warning") || developer_extra.integer)
1637                         Con_DPrintf("program link log:\n%s\n", linklog);
1638
1639                 // software vertex shader is ok but software fragment shader is WAY
1640                 // too slow, fail program if so.
1641                 // NOTE: this string might be ATI specific, but that's ok because the
1642                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
1643                 // software fragment shader due to low instruction and dependent
1644                 // texture limits.
1645                 if (strstr(linklog, "fragment shader will run in software"))
1646                         programlinked = false;
1647         }
1648
1649         if (!programlinked)
1650                 goto cleanup;
1651
1652         return programobject;
1653 cleanup:
1654         qglDeleteProgram(programobject);CHECKGLERROR
1655         return 0;
1656 }
1657
1658 void GL_Backend_FreeProgram(unsigned int prog)
1659 {
1660         CHECKGLERROR
1661         qglDeleteProgram(prog);
1662         CHECKGLERROR
1663 }
1664
1665 // renders triangles using vertices from the active arrays
1666 void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, int element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, int element3s_bufferoffset)
1667 {
1668         unsigned int numelements = numtriangles * 3;
1669         int bufferobject3i;
1670         size_t bufferoffset3i;
1671         int bufferobject3s;
1672         size_t bufferoffset3s;
1673         if (numvertices < 3 || numtriangles < 1)
1674         {
1675                 if (numvertices < 0 || numtriangles < 0 || developer_extra.integer)
1676                         Con_DPrintf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %8x, %8p, %8p, %8x);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3i_indexbuffer, (int)element3i_bufferoffset, (void *)element3s, (void *)element3s_indexbuffer, (int)element3s_bufferoffset);
1677                 return;
1678         }
1679         // adjust the pointers for firsttriangle
1680         if (element3i)
1681                 element3i += firsttriangle * 3;
1682         if (element3i_indexbuffer)
1683                 element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i);
1684         if (element3s)
1685                 element3s += firsttriangle * 3;
1686         if (element3s_indexbuffer)
1687                 element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
1688         // upload a dynamic index buffer if needed
1689         if (element3s)
1690         {
1691                 if (!element3s_indexbuffer)
1692                         element3s_indexbuffer = R_BufferData_Store(numelements * sizeof(*element3s), (void *)element3s, R_BUFFERDATA_INDEX16, &element3s_bufferoffset);
1693         }
1694         else if (element3i)
1695         {
1696                 if (!element3i_indexbuffer)
1697                         element3i_indexbuffer = R_BufferData_Store(numelements * sizeof(*element3i), (void *)element3i, R_BUFFERDATA_INDEX32, &element3i_bufferoffset);
1698         }
1699         bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
1700         bufferoffset3i = element3i_bufferoffset;
1701         bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0;
1702         bufferoffset3s = element3s_bufferoffset;
1703         r_refdef.stats[r_stat_draws]++;
1704         r_refdef.stats[r_stat_draws_vertices] += numvertices;
1705         r_refdef.stats[r_stat_draws_elements] += numelements;
1706         if (gl_paranoid.integer)
1707         {
1708                 unsigned int i;
1709                 if (element3i)
1710                 {
1711                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1712                         {
1713                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
1714                                 {
1715                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
1716                                         return;
1717                                 }
1718                         }
1719                 }
1720                 if (element3s)
1721                 {
1722                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1723                         {
1724                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
1725                                 {
1726                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
1727                                         return;
1728                                 }
1729                         }
1730                 }
1731         }
1732         if (r_render.integer || r_refdef.draw2dstage)
1733         {
1734                 switch(vid.renderpath)
1735                 {
1736                 case RENDERPATH_GL32:
1737                 case RENDERPATH_GLES2:
1738                         CHECKGLERROR
1739                         if (bufferobject3s)
1740                         {
1741                                 GL_BindEBO(bufferobject3s);
1742                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);CHECKGLERROR
1743                         }
1744                         else if (bufferobject3i)
1745                         {
1746                                 GL_BindEBO(bufferobject3i);
1747                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);CHECKGLERROR
1748                         }
1749                         else
1750                         {
1751                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);CHECKGLERROR
1752                         }
1753                         break;
1754                 }
1755         }
1756 }
1757
1758 // restores backend state, used when done with 3D rendering
1759 void R_Mesh_Finish(void)
1760 {
1761         R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
1762 }
1763
1764 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qbool isindexbuffer, qbool isuniformbuffer, qbool isdynamic, qbool isindex16)
1765 {
1766         r_meshbuffer_t *buffer;
1767         buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
1768         memset(buffer, 0, sizeof(*buffer));
1769         buffer->bufferobject = 0;
1770         buffer->devicebuffer = NULL;
1771         buffer->size = size;
1772         buffer->isindexbuffer = isindexbuffer;
1773         buffer->isuniformbuffer = isuniformbuffer;
1774         buffer->isdynamic = isdynamic;
1775         buffer->isindex16 = isindex16;
1776         strlcpy(buffer->name, name, sizeof(buffer->name));
1777         R_Mesh_UpdateMeshBuffer(buffer, data, size, false, 0);
1778         return buffer;
1779 }
1780
1781 void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size, qbool subdata, size_t offset)
1782 {
1783         if (!buffer)
1784                 return;
1785         if (buffer->isindexbuffer)
1786         {
1787                 r_refdef.stats[r_stat_indexbufferuploadcount]++;
1788                 r_refdef.stats[r_stat_indexbufferuploadsize] += (int)size;
1789         }
1790         else
1791         {
1792                 r_refdef.stats[r_stat_vertexbufferuploadcount]++;
1793                 r_refdef.stats[r_stat_vertexbufferuploadsize] += (int)size;
1794         }
1795         if (!subdata)
1796                 buffer->size = size;
1797         switch(vid.renderpath)
1798         {
1799         case RENDERPATH_GL32:
1800         case RENDERPATH_GLES2:
1801                 if (!buffer->bufferobject)
1802                         qglGenBuffers(1, (GLuint *)&buffer->bufferobject);
1803                 CHECKGLERROR
1804                 if (buffer->isuniformbuffer)
1805                         GL_BindUBO(buffer->bufferobject);
1806                 else if (buffer->isindexbuffer)
1807                         GL_BindEBO(buffer->bufferobject);
1808                 else
1809                         GL_BindVBO(buffer->bufferobject);
1810
1811                 {
1812                         int buffertype;
1813                         buffertype = buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
1814 #ifdef GL_UNIFORM_BUFFER
1815                         if (buffer->isuniformbuffer)
1816                                 buffertype = GL_UNIFORM_BUFFER;
1817 #endif
1818                         CHECKGLERROR
1819                         if (subdata)
1820                                 qglBufferSubData(buffertype, offset, size, data);
1821                         else
1822                                 qglBufferData(buffertype, size, data, buffer->isdynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW);
1823                         CHECKGLERROR
1824                 }
1825                 if (buffer->isuniformbuffer)
1826                         GL_BindUBO(0);
1827                 break;
1828         }
1829 }
1830
1831 void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
1832 {
1833         if (!buffer)
1834                 return;
1835         switch(vid.renderpath)
1836         {
1837         case RENDERPATH_GL32:
1838         case RENDERPATH_GLES2:
1839                 // GL clears the binding if we delete something bound
1840                 if (gl_state.uniformbufferobject == buffer->bufferobject)
1841                         gl_state.uniformbufferobject = 0;
1842                 if (gl_state.vertexbufferobject == buffer->bufferobject)
1843                         gl_state.vertexbufferobject = 0;
1844                 if (gl_state.elementbufferobject == buffer->bufferobject)
1845                         gl_state.elementbufferobject = 0;
1846                 CHECKGLERROR
1847                 qglDeleteBuffers(1, (GLuint *)&buffer->bufferobject);CHECKGLERROR
1848                 break;
1849         }
1850         Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
1851 }
1852
1853 static const char *buffertypename[R_BUFFERDATA_COUNT] = {"vertex", "index16", "index32", "uniform"};
1854 void GL_Mesh_ListVBOs(qbool printeach)
1855 {
1856         int i, endindex;
1857         int type;
1858         int isdynamic;
1859         int index16count, index16mem;
1860         int index32count, index32mem;
1861         int vertexcount, vertexmem;
1862         int uniformcount, uniformmem;
1863         int totalcount, totalmem;
1864         size_t bufferstat[R_BUFFERDATA_COUNT][2][2];
1865         r_meshbuffer_t *buffer;
1866         memset(bufferstat, 0, sizeof(bufferstat));
1867         endindex = (int)Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
1868         for (i = 0;i < endindex;i++)
1869         {
1870                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
1871                 if (!buffer)
1872                         continue;
1873                 if (buffer->isuniformbuffer)
1874                         type = R_BUFFERDATA_UNIFORM;
1875                 else if (buffer->isindexbuffer && buffer->isindex16)
1876                         type = R_BUFFERDATA_INDEX16;
1877                 else if (buffer->isindexbuffer)
1878                         type = R_BUFFERDATA_INDEX32;
1879                 else
1880                         type = R_BUFFERDATA_VERTEX;
1881                 isdynamic = buffer->isdynamic;
1882                 bufferstat[type][isdynamic][0]++;
1883                 bufferstat[type][isdynamic][1] += buffer->size;
1884                 if (printeach)
1885                         Con_Printf("buffer #%i %s = %i bytes (%s %s)\n", i, buffer->name, (int)buffer->size, isdynamic ? "dynamic" : "static", buffertypename[type]);
1886         }
1887         index16count   = (int)(bufferstat[R_BUFFERDATA_INDEX16][0][0] + bufferstat[R_BUFFERDATA_INDEX16][1][0]);
1888         index16mem     = (int)(bufferstat[R_BUFFERDATA_INDEX16][0][1] + bufferstat[R_BUFFERDATA_INDEX16][1][1]);
1889         index32count   = (int)(bufferstat[R_BUFFERDATA_INDEX32][0][0] + bufferstat[R_BUFFERDATA_INDEX32][1][0]);
1890         index32mem     = (int)(bufferstat[R_BUFFERDATA_INDEX32][0][1] + bufferstat[R_BUFFERDATA_INDEX32][1][1]);
1891         vertexcount  = (int)(bufferstat[R_BUFFERDATA_VERTEX ][0][0] + bufferstat[R_BUFFERDATA_VERTEX ][1][0]);
1892         vertexmem    = (int)(bufferstat[R_BUFFERDATA_VERTEX ][0][1] + bufferstat[R_BUFFERDATA_VERTEX ][1][1]);
1893         uniformcount = (int)(bufferstat[R_BUFFERDATA_UNIFORM][0][0] + bufferstat[R_BUFFERDATA_UNIFORM][1][0]);
1894         uniformmem   = (int)(bufferstat[R_BUFFERDATA_UNIFORM][0][1] + bufferstat[R_BUFFERDATA_UNIFORM][1][1]);
1895         totalcount = index16count + index32count + vertexcount + uniformcount;
1896         totalmem = index16mem + index32mem + vertexmem + uniformmem;
1897         Con_Printf("%i 16bit indexbuffers totalling %i bytes (%.3f MB)\n%i 32bit indexbuffers totalling %i bytes (%.3f MB)\n%i vertexbuffers totalling %i bytes (%.3f MB)\n%i uniformbuffers totalling %i bytes (%.3f MB)\ncombined %i buffers totalling %i bytes (%.3fMB)\n", index16count, index16mem, index16mem / 10248576.0, index32count, index32mem, index32mem / 10248576.0, vertexcount, vertexmem, vertexmem / 10248576.0, uniformcount, uniformmem, uniformmem / 10248576.0, totalcount, totalmem, totalmem / 10248576.0);
1898 }
1899
1900
1901
1902 void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
1903 {
1904         switch(vid.renderpath)
1905         {
1906         case RENDERPATH_GL32:
1907         case RENDERPATH_GLES2:
1908                 if (gl_state.pointer_vertex_components != components || gl_state.pointer_vertex_gltype != gltype || gl_state.pointer_vertex_stride != stride || gl_state.pointer_vertex_pointer != pointer || gl_state.pointer_vertex_vertexbuffer != vertexbuffer || gl_state.pointer_vertex_offset != bufferoffset)
1909                 {
1910                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
1911                         if (!bufferobject && gl_paranoid.integer)
1912                                 Con_DPrintf("Warning: no bufferobject in R_Mesh_VertexPointer(%i, %i, %i, %p, %p, %08x)", components, gltype, (int)stride, pointer, (void *)vertexbuffer, (unsigned int)bufferoffset);
1913                         gl_state.pointer_vertex_components = components;
1914                         gl_state.pointer_vertex_gltype = gltype;
1915                         gl_state.pointer_vertex_stride = stride;
1916                         gl_state.pointer_vertex_pointer = pointer;
1917                         gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
1918                         gl_state.pointer_vertex_offset = bufferoffset;
1919                         CHECKGLERROR
1920                         GL_BindVBO(bufferobject);
1921                         // LadyHavoc: special flag added to gltype for unnormalized types
1922                         qglVertexAttribPointer(GLSLATTRIB_POSITION, components, gltype & ~0x80000000, (gltype & 0x80000000) == 0, (GLsizei)stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
1923                 }
1924                 break;
1925         }
1926 }
1927
1928 void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
1929 {
1930         // note: vertexbuffer may be non-NULL even if pointer is NULL, so check
1931         // the pointer only.
1932         switch(vid.renderpath)
1933         {
1934         case RENDERPATH_GL32:
1935         case RENDERPATH_GLES2:
1936                 CHECKGLERROR
1937                 if (pointer)
1938                 {
1939                         // caller wants color array enabled
1940                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
1941                         if (!gl_state.pointer_color_enabled)
1942                         {
1943                                 gl_state.pointer_color_enabled = true;
1944                                 CHECKGLERROR
1945                                 qglEnableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR
1946                         }
1947                         if (gl_state.pointer_color_components != components || gl_state.pointer_color_gltype != gltype || gl_state.pointer_color_stride != stride || gl_state.pointer_color_pointer != pointer || gl_state.pointer_color_vertexbuffer != vertexbuffer || gl_state.pointer_color_offset != bufferoffset)
1948                         {
1949                                 gl_state.pointer_color_components = components;
1950                                 gl_state.pointer_color_gltype = gltype;
1951                                 gl_state.pointer_color_stride = stride;
1952                                 gl_state.pointer_color_pointer = pointer;
1953                                 gl_state.pointer_color_vertexbuffer = vertexbuffer;
1954                                 gl_state.pointer_color_offset = bufferoffset;
1955                                 CHECKGLERROR
1956                                 GL_BindVBO(bufferobject);
1957                                 // LadyHavoc: special flag added to gltype for unnormalized types
1958                                 qglVertexAttribPointer(GLSLATTRIB_COLOR, components, gltype & ~0x80000000, (gltype & 0x80000000) == 0, (GLsizei)stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
1959                         }
1960                 }
1961                 else
1962                 {
1963                         // caller wants color array disabled
1964                         if (gl_state.pointer_color_enabled)
1965                         {
1966                                 gl_state.pointer_color_enabled = false;
1967                                 CHECKGLERROR
1968                                 qglDisableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR
1969                                 // when color array is on the current color gets trashed, set it again
1970                                 qglVertexAttrib4f(GLSLATTRIB_COLOR, gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1971                         }
1972                 }
1973                 break;
1974         }
1975 }
1976
1977 void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
1978 {
1979         gltextureunit_t *unit = gl_state.units + unitnum;
1980         if (unitnum >= MAX_TEXTUREUNITS)
1981                 Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
1982         // update array settings
1983         // note: there is no need to check bufferobject here because all cases
1984         // that involve a valid bufferobject also supply a texcoord array
1985         switch(vid.renderpath)
1986         {
1987         case RENDERPATH_GL32:
1988         case RENDERPATH_GLES2:
1989                 CHECKGLERROR
1990                 if (pointer)
1991                 {
1992                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
1993                         // texture array unit is enabled, enable the array
1994                         if (!unit->arrayenabled)
1995                         {
1996                                 unit->arrayenabled = true;
1997                                 qglEnableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
1998                         }
1999                         // texcoord array
2000                         if (unit->pointer_texcoord_components != components || unit->pointer_texcoord_gltype != gltype || unit->pointer_texcoord_stride != stride || unit->pointer_texcoord_pointer != pointer || unit->pointer_texcoord_vertexbuffer != vertexbuffer || unit->pointer_texcoord_offset != bufferoffset)
2001                         {
2002                                 unit->pointer_texcoord_components = components;
2003                                 unit->pointer_texcoord_gltype = gltype;
2004                                 unit->pointer_texcoord_stride = stride;
2005                                 unit->pointer_texcoord_pointer = pointer;
2006                                 unit->pointer_texcoord_vertexbuffer = vertexbuffer;
2007                                 unit->pointer_texcoord_offset = bufferoffset;
2008                                 GL_BindVBO(bufferobject);
2009                                 // LadyHavoc: special flag added to gltype for unnormalized types
2010                                 qglVertexAttribPointer(unitnum+GLSLATTRIB_TEXCOORD0, components, gltype & ~0x80000000, (gltype & 0x80000000) == 0, (GLsizei)stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
2011                         }
2012                 }
2013                 else
2014                 {
2015                         // texture array unit is disabled, disable the array
2016                         if (unit->arrayenabled)
2017                         {
2018                                 unit->arrayenabled = false;
2019                                 qglDisableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
2020                         }
2021                 }
2022                 break;
2023         }
2024 }
2025
2026 int R_Mesh_TexBound(unsigned int unitnum, int id)
2027 {
2028         gltextureunit_t *unit = gl_state.units + unitnum;
2029         if (unitnum >= MAX_TEXTUREUNITS)
2030                 Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
2031         if (id == GL_TEXTURE_2D)
2032                 return unit->t2d;
2033         if (id == GL_TEXTURE_3D)
2034                 return unit->t3d;
2035         if (id == GL_TEXTURE_CUBE_MAP)
2036                 return unit->tcubemap;
2037         return 0;
2038 }
2039
2040 void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int width, int height)
2041 {
2042         switch(vid.renderpath)
2043         {
2044         case RENDERPATH_GL32:
2045         case RENDERPATH_GLES2:
2046                 R_Mesh_TexBind(0, tex);
2047                 GL_ActiveTexture(0);CHECKGLERROR
2048                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, sx, sy, width, height);CHECKGLERROR
2049                 break;
2050         }
2051 }
2052
2053 void R_Mesh_ClearBindingsForTexture(int texnum)
2054 {
2055         gltextureunit_t *unit;
2056         unsigned int unitnum;
2057         // unbind the texture from any units it is bound on - this prevents accidental reuse of certain textures whose bindings can linger far too long otherwise (e.g. bouncegrid which is a 3D texture) and confuse the driver later.
2058         for (unitnum = 0; unitnum < MAX_TEXTUREUNITS; unitnum++)
2059         {
2060                 unit = gl_state.units + unitnum;
2061                 if (unit->texture && unit->texture->texnum == texnum)
2062                         R_Mesh_TexBind(unitnum, NULL);
2063         }
2064 }
2065
2066 void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
2067 {
2068         gltextureunit_t *unit = gl_state.units + unitnum;
2069         int texnum;
2070         if (unitnum >= MAX_TEXTUREUNITS)
2071                 Sys_Error("R_Mesh_TexBind: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
2072         switch(vid.renderpath)
2073         {
2074         case RENDERPATH_GL32:
2075         case RENDERPATH_GLES2:
2076                 if (tex)
2077                 {
2078                         texnum = R_GetTexture(tex);
2079                         switch (tex->gltexturetypeenum)
2080                         {
2081                         case GL_TEXTURE_2D:
2082                                 if (unit->t2d != texnum) { GL_ActiveTexture(unitnum);qglBindTexture(GL_TEXTURE_2D, texnum); CHECKGLERROR unit->t2d = texnum; }
2083                                 if (unit->t3d) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_3D, 0); CHECKGLERROR unit->t3d = 0; }
2084                                 if (unit->tcubemap) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_CUBE_MAP, 0); CHECKGLERROR unit->tcubemap = 0; }
2085                                 break;
2086                         case GL_TEXTURE_3D:
2087                                 if (unit->t2d) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_2D, 0); CHECKGLERROR unit->t2d = 0; }
2088                                 if (unit->t3d != texnum) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_3D, texnum); CHECKGLERROR unit->t3d = texnum; }
2089                                 if (unit->tcubemap) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_CUBE_MAP, 0); CHECKGLERROR unit->tcubemap = 0; }
2090                                 break;
2091                         case GL_TEXTURE_CUBE_MAP:
2092                                 if (unit->t2d) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_2D, 0); CHECKGLERROR unit->t2d = 0; }
2093                                 if (unit->t3d) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_3D, 0); CHECKGLERROR unit->t3d = 0; }
2094                                 if (unit->tcubemap != texnum) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_CUBE_MAP, texnum); CHECKGLERROR unit->tcubemap = texnum; }
2095                                 break;
2096                         }
2097                 }
2098                 else
2099                 {
2100                         if (unit->t2d) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_2D, 0); CHECKGLERROR unit->t2d = 0; }
2101                         if (unit->t3d) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_3D, 0); CHECKGLERROR unit->t3d = 0; }
2102                         if (unit->tcubemap) { GL_ActiveTexture(unitnum); qglBindTexture(GL_TEXTURE_CUBE_MAP, 0); CHECKGLERROR unit->tcubemap = 0; }
2103                 }
2104         }
2105         unit->texture = tex;
2106 }
2107
2108 void R_Mesh_ResetTextureState(void)
2109 {
2110 #if 0
2111         unsigned int unitnum;
2112         
2113         BACKENDACTIVECHECK
2114
2115         for (unitnum = 0;unitnum < MAX_TEXTUREUNITS;unitnum++)
2116                 R_Mesh_TexBind(unitnum, NULL);
2117 #endif
2118 }
2119
2120 void R_Mesh_PrepareVertices_Vertex3f(int numvertices, const float *vertex3f, const r_meshbuffer_t *vertexbuffer, int bufferoffset)
2121 {
2122         // upload temporary vertexbuffer for this rendering
2123         if (!vertexbuffer)
2124                 vertexbuffer = R_BufferData_Store(numvertices * sizeof(float[3]), (void *)vertex3f, R_BUFFERDATA_VERTEX, &bufferoffset);
2125         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f  , vertexbuffer     , bufferoffset           );
2126         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , NULL      , NULL             , 0                      );
2127         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , NULL      , NULL             , 0                      );
2128         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , NULL      , NULL             , 0                      );
2129         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , NULL      , NULL             , 0                      );
2130         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , NULL      , NULL             , 0                      );
2131         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , NULL      , NULL             , 0                      );
2132         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL      , NULL             , 0                      );
2133         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL      , NULL             , 0                      );
2134         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL      , NULL             , 0                      );
2135 }
2136
2137 void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f)
2138 {
2139         r_meshbuffer_t *buffer_vertex3f = NULL;
2140         r_meshbuffer_t *buffer_color4f = NULL;
2141         r_meshbuffer_t *buffer_texcoord2f = NULL;
2142         int bufferoffset_vertex3f = 0;
2143         int bufferoffset_color4f = 0;
2144         int bufferoffset_texcoord2f = 0;
2145         if (color4f)
2146                 buffer_color4f    = R_BufferData_Store(numvertices * sizeof(float[4]), color4f   , R_BUFFERDATA_VERTEX, &bufferoffset_color4f   );
2147         if (vertex3f)
2148                 buffer_vertex3f   = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f  , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f  );
2149         if (texcoord2f)
2150                 buffer_texcoord2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoord2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoord2f);
2151         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f          , buffer_vertex3f          , bufferoffset_vertex3f          );
2152         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , color4f           , buffer_color4f           , bufferoffset_color4f           );
2153         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , texcoord2f        , buffer_texcoord2f        , bufferoffset_texcoord2f        );
2154         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
2155         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
2156         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
2157         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
2158         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
2159         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
2160         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
2161 }
2162
2163 void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f)
2164 {
2165         r_meshbuffer_t *buffer_vertex3f = NULL;
2166         r_meshbuffer_t *buffer_color4f = NULL;
2167         r_meshbuffer_t *buffer_texcoordtexture2f = NULL;
2168         r_meshbuffer_t *buffer_svector3f = NULL;
2169         r_meshbuffer_t *buffer_tvector3f = NULL;
2170         r_meshbuffer_t *buffer_normal3f = NULL;
2171         r_meshbuffer_t *buffer_texcoordlightmap2f = NULL;
2172         int bufferoffset_vertex3f = 0;
2173         int bufferoffset_color4f = 0;
2174         int bufferoffset_texcoordtexture2f = 0;
2175         int bufferoffset_svector3f = 0;
2176         int bufferoffset_tvector3f = 0;
2177         int bufferoffset_normal3f = 0;
2178         int bufferoffset_texcoordlightmap2f = 0;
2179         if (color4f)
2180                 buffer_color4f            = R_BufferData_Store(numvertices * sizeof(float[4]), color4f           , R_BUFFERDATA_VERTEX, &bufferoffset_color4f           );
2181         if (vertex3f)
2182                 buffer_vertex3f           = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f          , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f          );
2183         if (svector3f)
2184                 buffer_svector3f          = R_BufferData_Store(numvertices * sizeof(float[3]), svector3f         , R_BUFFERDATA_VERTEX, &bufferoffset_svector3f         );
2185         if (tvector3f)
2186                 buffer_tvector3f          = R_BufferData_Store(numvertices * sizeof(float[3]), tvector3f         , R_BUFFERDATA_VERTEX, &bufferoffset_tvector3f         );
2187         if (normal3f)
2188                 buffer_normal3f           = R_BufferData_Store(numvertices * sizeof(float[3]), normal3f          , R_BUFFERDATA_VERTEX, &bufferoffset_normal3f          );
2189         if (texcoordtexture2f)
2190                 buffer_texcoordtexture2f  = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordtexture2f , R_BUFFERDATA_VERTEX, &bufferoffset_texcoordtexture2f );
2191         if (texcoordlightmap2f)
2192                 buffer_texcoordlightmap2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordlightmap2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoordlightmap2f);
2193         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f          , buffer_vertex3f          , bufferoffset_vertex3f          );
2194         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , color4f           , buffer_color4f           , bufferoffset_color4f           );
2195         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , texcoordtexture2f , buffer_texcoordtexture2f , bufferoffset_texcoordtexture2f );
2196         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , svector3f         , buffer_svector3f         , bufferoffset_svector3f         );
2197         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , tvector3f         , buffer_tvector3f         , bufferoffset_tvector3f         );
2198         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , normal3f          , buffer_normal3f          , bufferoffset_normal3f          );
2199         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , texcoordlightmap2f, buffer_texcoordlightmap2f, bufferoffset_texcoordlightmap2f);
2200         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
2201         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
2202         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
2203 }
2204
2205 void GL_BlendEquationSubtract(qbool negated)
2206 {
2207         CHECKGLERROR
2208         if(negated)
2209         {
2210                 switch(vid.renderpath)
2211                 {
2212                 case RENDERPATH_GL32:
2213                 case RENDERPATH_GLES2:
2214                         qglBlendEquation(GL_FUNC_REVERSE_SUBTRACT);CHECKGLERROR
2215                         break;
2216                 }
2217         }
2218         else
2219         {
2220                 switch(vid.renderpath)
2221                 {
2222                 case RENDERPATH_GL32:
2223                 case RENDERPATH_GLES2:
2224                         qglBlendEquation(GL_FUNC_ADD);CHECKGLERROR
2225                         break;
2226                 }
2227         }
2228 }