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