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