cdc4df603e951944b7d9a202c94e3315559aa402
[xonotic/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4 #include "dpsoftrast.h"
5 #ifdef SUPPORTD3D
6 #include <d3d9.h>
7 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
8 extern D3DCAPS9 vid_d3d9caps;
9 #endif
10
11 #define MAX_RENDERTARGETS 4
12
13 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
14 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
15 cvar_t gl_mesh_prefer_short_elements = {CVAR_SAVE, "gl_mesh_prefer_short_elements", "1", "use GL_UNSIGNED_SHORT element arrays instead of GL_UNSIGNED_INT"};
16 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
17 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
18
19 cvar_t r_render = {0, "r_render", "1", "enables rendering 3D views (you want this on!)"};
20 cvar_t r_renderview = {0, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
21 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
22 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
23 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
24 cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"};
25 cvar_t gl_vbo_dynamicvertex = {CVAR_SAVE, "gl_vbo_dynamicvertex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
26 cvar_t gl_vbo_dynamicindex = {CVAR_SAVE, "gl_vbo_dynamicindex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
27 cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"};
28
29 cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
30 qboolean v_flipped_state = false;
31
32 r_viewport_t gl_viewport;
33 matrix4x4_t gl_modelmatrix;
34 matrix4x4_t gl_viewmatrix;
35 matrix4x4_t gl_modelviewmatrix;
36 matrix4x4_t gl_projectionmatrix;
37 matrix4x4_t gl_modelviewprojectionmatrix;
38 float gl_modelview16f[16];
39 float gl_modelviewprojection16f[16];
40 qboolean gl_modelmatrixchanged;
41
42 int gl_maxdrawrangeelementsvertices;
43 int gl_maxdrawrangeelementsindices;
44
45 #ifdef DEBUGGL
46 int errornumber = 0;
47
48 void GL_PrintError(int errornumber, const char *filename, int linenumber)
49 {
50         switch(errornumber)
51         {
52 #ifdef GL_INVALID_ENUM
53         case GL_INVALID_ENUM:
54                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
55                 break;
56 #endif
57 #ifdef GL_INVALID_VALUE
58         case GL_INVALID_VALUE:
59                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
60                 break;
61 #endif
62 #ifdef GL_INVALID_OPERATION
63         case GL_INVALID_OPERATION:
64                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
65                 break;
66 #endif
67 #ifdef GL_STACK_OVERFLOW
68         case GL_STACK_OVERFLOW:
69                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
70                 break;
71 #endif
72 #ifdef GL_STACK_UNDERFLOW
73         case GL_STACK_UNDERFLOW:
74                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
75                 break;
76 #endif
77 #ifdef GL_OUT_OF_MEMORY
78         case GL_OUT_OF_MEMORY:
79                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
80                 break;
81 #endif
82 #ifdef GL_TABLE_TOO_LARGE
83         case GL_TABLE_TOO_LARGE:
84                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
85                 break;
86 #endif
87 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
88         case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
89                 Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber);
90                 break;
91 #endif
92         default:
93                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
94                 break;
95         }
96 }
97 #endif
98
99 #define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active");
100
101 void SCR_ScreenShot_f (void);
102
103 typedef struct gltextureunit_s
104 {
105         int pointer_texcoord_components;
106         int pointer_texcoord_gltype;
107         size_t pointer_texcoord_stride;
108         const void *pointer_texcoord_pointer;
109         const r_meshbuffer_t *pointer_texcoord_vertexbuffer;
110         size_t pointer_texcoord_offset;
111
112         rtexture_t *texture;
113         int t2d, t3d, tcubemap;
114         int arrayenabled;
115         int rgbscale, alphascale;
116         int combine;
117         int combinergb, combinealpha;
118         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
119         int texmatrixenabled;
120         matrix4x4_t matrix;
121 }
122 gltextureunit_t;
123
124 typedef struct gl_state_s
125 {
126         int cullface;
127         int cullfaceenable;
128         int blendfunc1;
129         int blendfunc2;
130         qboolean blend;
131         GLboolean depthmask;
132         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
133         int depthtest;
134         int depthfunc;
135         float depthrange[2];
136         float polygonoffset[2];
137         int alphatest;
138         int alphafunc;
139         float alphafuncvalue;
140         qboolean alphatocoverage;
141         int scissortest;
142         unsigned int unit;
143         unsigned int clientunit;
144         gltextureunit_t units[MAX_TEXTUREUNITS];
145         float color4f[4];
146         int lockrange_first;
147         int lockrange_count;
148         int vertexbufferobject;
149         int elementbufferobject;
150         int framebufferobject;
151         int defaultframebufferobject; // deal with platforms that use a non-zero default fbo
152         qboolean pointer_color_enabled;
153
154         int pointer_vertex_components;
155         int pointer_vertex_gltype;
156         size_t pointer_vertex_stride;
157         const void *pointer_vertex_pointer;
158         const r_meshbuffer_t *pointer_vertex_vertexbuffer;
159         size_t pointer_vertex_offset;
160
161         int pointer_color_components;
162         int pointer_color_gltype;
163         size_t pointer_color_stride;
164         const void *pointer_color_pointer;
165         const r_meshbuffer_t *pointer_color_vertexbuffer;
166         size_t pointer_color_offset;
167
168         void *preparevertices_tempdata;
169         size_t preparevertices_tempdatamaxsize;
170         r_meshbuffer_t *preparevertices_dynamicvertexbuffer;
171         r_vertexgeneric_t *preparevertices_vertexgeneric;
172         r_vertexmesh_t *preparevertices_vertexmesh;
173         int preparevertices_numvertices;
174
175         r_meshbuffer_t *draw_dynamicindexbuffer;
176
177         qboolean usevbo_staticvertex;
178         qboolean usevbo_staticindex;
179         qboolean usevbo_dynamicvertex;
180         qboolean usevbo_dynamicindex;
181
182         memexpandablearray_t meshbufferarray;
183
184         qboolean active;
185
186 #ifdef SUPPORTD3D
187 //      rtexture_t *d3drt_depthtexture;
188 //      rtexture_t *d3drt_colortextures[MAX_RENDERTARGETS];
189         IDirect3DSurface9 *d3drt_depthsurface;
190         IDirect3DSurface9 *d3drt_colorsurfaces[MAX_RENDERTARGETS];
191         IDirect3DSurface9 *d3drt_backbufferdepthsurface;
192         IDirect3DSurface9 *d3drt_backbuffercolorsurface;
193         void *d3dvertexbuffer;
194         void *d3dvertexdata;
195         size_t d3dvertexsize;
196 #endif
197 }
198 gl_state_t;
199
200 static gl_state_t gl_state;
201
202
203 /*
204 note: here's strip order for a terrain row:
205 0--1--2--3--4
206 |\ |\ |\ |\ |
207 | \| \| \| \|
208 A--B--C--D--E
209 clockwise
210
211 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
212
213 *elements++ = i + row;
214 *elements++ = i;
215 *elements++ = i + row + 1;
216 *elements++ = i;
217 *elements++ = i + 1;
218 *elements++ = i + row + 1;
219
220
221 for (y = 0;y < rows - 1;y++)
222 {
223         for (x = 0;x < columns - 1;x++)
224         {
225                 i = y * rows + x;
226                 *elements++ = i + columns;
227                 *elements++ = i;
228                 *elements++ = i + columns + 1;
229                 *elements++ = i;
230                 *elements++ = i + 1;
231                 *elements++ = i + columns + 1;
232         }
233 }
234
235 alternative:
236 0--1--2--3--4
237 | /| /|\ | /|
238 |/ |/ | \|/ |
239 A--B--C--D--E
240 counterclockwise
241
242 for (y = 0;y < rows - 1;y++)
243 {
244         for (x = 0;x < columns - 1;x++)
245         {
246                 i = y * rows + x;
247                 *elements++ = i;
248                 *elements++ = i + columns;
249                 *elements++ = i + columns + 1;
250                 *elements++ = i + columns;
251                 *elements++ = i + columns + 1;
252                 *elements++ = i + 1;
253         }
254 }
255 */
256
257 int polygonelement3i[(POLYGONELEMENTS_MAXPOINTS-2)*3];
258 unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3];
259 int quadelement3i[QUADELEMENTS_MAXQUADS*6];
260 unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6];
261
262 void GL_VBOStats_f(void)
263 {
264         GL_Mesh_ListVBOs(true);
265 }
266
267 static void GL_Backend_ResetState(void);
268
269 static void R_Mesh_InitVertexDeclarations(void);
270 static void R_Mesh_DestroyVertexDeclarations(void);
271
272 static void R_Mesh_SetUseVBO(void)
273 {
274         switch(vid.renderpath)
275         {
276         case RENDERPATH_GL11:
277         case RENDERPATH_GL13:
278         case RENDERPATH_GL20:
279         case RENDERPATH_GLES1:
280                 gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
281                 gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo;
282                 gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
283                 gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo;
284                 break;
285         case RENDERPATH_D3D9:
286                 gl_state.usevbo_staticvertex = gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
287                 gl_state.usevbo_dynamicvertex = gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer && gl_vbo_dynamicindex.integer) || vid.forcevbo;
288                 break;
289         case RENDERPATH_D3D10:
290                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
291                 break;
292         case RENDERPATH_D3D11:
293                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
294                 break;
295         case RENDERPATH_SOFT:
296                 gl_state.usevbo_staticvertex = false;
297                 gl_state.usevbo_staticindex = false;
298                 gl_state.usevbo_dynamicvertex = false;
299                 gl_state.usevbo_dynamicindex = false;
300                 break;
301         case RENDERPATH_GLES2:
302                 gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
303                 gl_state.usevbo_staticindex = false;
304                 gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
305                 gl_state.usevbo_dynamicindex = false;
306                 break;
307         }
308 }
309
310 static void gl_backend_start(void)
311 {
312         memset(&gl_state, 0, sizeof(gl_state));
313
314         R_Mesh_InitVertexDeclarations();
315
316         R_Mesh_SetUseVBO();
317         Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128);
318
319         Con_DPrintf("OpenGL backend started.\n");
320
321         CHECKGLERROR
322
323         GL_Backend_ResetState();
324
325         switch(vid.renderpath)
326         {
327         case RENDERPATH_GL11:
328         case RENDERPATH_GL13:
329         case RENDERPATH_GL20:
330         case RENDERPATH_GLES1:
331         case RENDERPATH_GLES2:
332                 // fetch current fbo here (default fbo is not 0 on some GLES devices)
333                 if (vid.support.ext_framebuffer_object)
334                         qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &gl_state.defaultframebufferobject);
335                 break;
336         case RENDERPATH_D3D9:
337 #ifdef SUPPORTD3D
338                 IDirect3DDevice9_GetDepthStencilSurface(vid_d3d9dev, &gl_state.d3drt_backbufferdepthsurface);
339                 IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &gl_state.d3drt_backbuffercolorsurface);
340 #endif
341                 break;
342         case RENDERPATH_D3D10:
343                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
344                 break;
345         case RENDERPATH_D3D11:
346                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
347                 break;
348         case RENDERPATH_SOFT:
349                 break;
350         }
351 }
352
353 static void gl_backend_shutdown(void)
354 {
355         Con_DPrint("OpenGL Backend shutting down\n");
356
357         switch(vid.renderpath)
358         {
359         case RENDERPATH_GL11:
360         case RENDERPATH_GL13:
361         case RENDERPATH_GL20:
362         case RENDERPATH_SOFT:
363         case RENDERPATH_GLES1:
364         case RENDERPATH_GLES2:
365                 break;
366         case RENDERPATH_D3D9:
367 #ifdef SUPPORTD3D
368                 IDirect3DSurface9_Release(gl_state.d3drt_backbufferdepthsurface);
369                 IDirect3DSurface9_Release(gl_state.d3drt_backbuffercolorsurface);
370 #endif
371                 break;
372         case RENDERPATH_D3D10:
373                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
374                 break;
375         case RENDERPATH_D3D11:
376                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
377                 break;
378         }
379
380         if (gl_state.preparevertices_tempdata)
381                 Mem_Free(gl_state.preparevertices_tempdata);
382         if (gl_state.preparevertices_dynamicvertexbuffer)
383                 R_Mesh_DestroyMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer);
384
385         Mem_ExpandableArray_FreeArray(&gl_state.meshbufferarray);
386
387         R_Mesh_DestroyVertexDeclarations();
388
389         memset(&gl_state, 0, sizeof(gl_state));
390 }
391
392 static void gl_backend_newmap(void)
393 {
394 }
395
396 static void gl_backend_devicelost(void)
397 {
398         int i, endindex;
399         r_meshbuffer_t *buffer;
400 #ifdef SUPPORTD3D
401         gl_state.d3dvertexbuffer = NULL;
402 #endif
403         switch(vid.renderpath)
404         {
405         case RENDERPATH_GL11:
406         case RENDERPATH_GL13:
407         case RENDERPATH_GL20:
408         case RENDERPATH_SOFT:
409         case RENDERPATH_GLES1:
410         case RENDERPATH_GLES2:
411                 break;
412         case RENDERPATH_D3D9:
413 #ifdef SUPPORTD3D
414                 IDirect3DSurface9_Release(gl_state.d3drt_backbufferdepthsurface);
415                 IDirect3DSurface9_Release(gl_state.d3drt_backbuffercolorsurface);
416 #endif
417                 break;
418         case RENDERPATH_D3D10:
419                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
420                 break;
421         case RENDERPATH_D3D11:
422                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
423                 break;
424         }
425         endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
426         for (i = 0;i < endindex;i++)
427         {
428                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
429                 if (!buffer || !buffer->isdynamic)
430                         continue;
431                 switch(vid.renderpath)
432                 {
433                 case RENDERPATH_GL11:
434                 case RENDERPATH_GL13:
435                 case RENDERPATH_GL20:
436                 case RENDERPATH_SOFT:
437                 case RENDERPATH_GLES1:
438                 case RENDERPATH_GLES2:
439                         break;
440                 case RENDERPATH_D3D9:
441 #ifdef SUPPORTD3D
442                         if (buffer->devicebuffer)
443                         {
444                                 if (buffer->isindexbuffer)
445                                         IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer);
446                                 else
447                                         IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer);
448                                 buffer->devicebuffer = NULL;
449                         }
450 #endif
451                         break;
452                 case RENDERPATH_D3D10:
453                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
454                         break;
455                 case RENDERPATH_D3D11:
456                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
457                         break;
458                 }
459         }
460 }
461
462 static void gl_backend_devicerestored(void)
463 {
464         switch(vid.renderpath)
465         {
466         case RENDERPATH_GL11:
467         case RENDERPATH_GL13:
468         case RENDERPATH_GL20:
469         case RENDERPATH_SOFT:
470         case RENDERPATH_GLES1:
471         case RENDERPATH_GLES2:
472                 break;
473         case RENDERPATH_D3D9:
474 #ifdef SUPPORTD3D
475                 IDirect3DDevice9_GetDepthStencilSurface(vid_d3d9dev, &gl_state.d3drt_backbufferdepthsurface);
476                 IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &gl_state.d3drt_backbuffercolorsurface);
477 #endif
478                 break;
479         case RENDERPATH_D3D10:
480                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
481                 break;
482         case RENDERPATH_D3D11:
483                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
484                 break;
485         }
486 }
487
488 void gl_backend_init(void)
489 {
490         int i;
491
492         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
493         {
494                 polygonelement3s[i * 3 + 0] = 0;
495                 polygonelement3s[i * 3 + 1] = i + 1;
496                 polygonelement3s[i * 3 + 2] = i + 2;
497         }
498         // elements for rendering a series of quads as triangles
499         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
500         {
501                 quadelement3s[i * 6 + 0] = i * 4;
502                 quadelement3s[i * 6 + 1] = i * 4 + 1;
503                 quadelement3s[i * 6 + 2] = i * 4 + 2;
504                 quadelement3s[i * 6 + 3] = i * 4;
505                 quadelement3s[i * 6 + 4] = i * 4 + 2;
506                 quadelement3s[i * 6 + 5] = i * 4 + 3;
507         }
508
509         for (i = 0;i < (POLYGONELEMENTS_MAXPOINTS - 2)*3;i++)
510                 polygonelement3i[i] = polygonelement3s[i];
511         for (i = 0;i < QUADELEMENTS_MAXQUADS*6;i++)
512                 quadelement3i[i] = quadelement3s[i];
513
514         Cvar_RegisterVariable(&r_render);
515         Cvar_RegisterVariable(&r_renderview);
516         Cvar_RegisterVariable(&r_waterwarp);
517         Cvar_RegisterVariable(&gl_polyblend);
518         Cvar_RegisterVariable(&v_flipped);
519         Cvar_RegisterVariable(&gl_dither);
520         Cvar_RegisterVariable(&gl_vbo);
521         Cvar_RegisterVariable(&gl_vbo_dynamicvertex);
522         Cvar_RegisterVariable(&gl_vbo_dynamicindex);
523         Cvar_RegisterVariable(&gl_paranoid);
524         Cvar_RegisterVariable(&gl_printcheckerror);
525
526         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
527         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
528         Cvar_RegisterVariable(&gl_mesh_prefer_short_elements);
529
530         Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them");
531
532         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap, gl_backend_devicelost, gl_backend_devicerestored);
533 }
534
535 void GL_SetMirrorState(qboolean state);
536
537 void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out)
538 {
539         vec4_t temp;
540         float iw;
541         Matrix4x4_Transform4 (&v->viewmatrix, in, temp);
542         Matrix4x4_Transform4 (&v->projectmatrix, temp, out);
543         iw = 1.0f / out[3];
544         out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f;
545
546         // for an odd reason, inverting this is wrong for R_Shadow_ScissorForBBox (we then get badly scissored lights)
547         //out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f;
548         out[1] = v->y + (out[1] * iw + 1.0f) * v->height * 0.5f;
549
550         out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f;
551 }
552
553 void GL_Finish(void)
554 {
555         switch(vid.renderpath)
556         {
557         case RENDERPATH_GL11:
558         case RENDERPATH_GL13:
559         case RENDERPATH_GL20:
560         case RENDERPATH_GLES1:
561         case RENDERPATH_GLES2:
562                 qglFinish();
563                 break;
564         case RENDERPATH_D3D9:
565                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
566                 break;
567         case RENDERPATH_D3D10:
568                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
569                 break;
570         case RENDERPATH_D3D11:
571                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
572                 break;
573         case RENDERPATH_SOFT:
574                 DPSOFTRAST_Finish();
575                 break;
576         }
577 }
578
579 static int bboxedges[12][2] =
580 {
581         // top
582         {0, 1}, // +X
583         {0, 2}, // +Y
584         {1, 3}, // Y, +X
585         {2, 3}, // X, +Y
586         // bottom
587         {4, 5}, // +X
588         {4, 6}, // +Y
589         {5, 7}, // Y, +X
590         {6, 7}, // X, +Y
591         // verticals
592         {0, 4}, // +Z
593         {1, 5}, // X, +Z
594         {2, 6}, // Y, +Z
595         {3, 7}, // XY, +Z
596 };
597
598 qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor)
599 {
600         int i, ix1, iy1, ix2, iy2;
601         float x1, y1, x2, y2;
602         vec4_t v, v2;
603         float vertex[20][3];
604         int j, k;
605         vec4_t plane4f;
606         int numvertices;
607         float corner[8][4];
608         float dist[8];
609         int sign[8];
610         float f;
611
612         scissor[0] = r_refdef.view.viewport.x;
613         scissor[1] = r_refdef.view.viewport.y;
614         scissor[2] = r_refdef.view.viewport.width;
615         scissor[3] = r_refdef.view.viewport.height;
616
617         // if view is inside the box, just say yes it's visible
618         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
619                 return false;
620
621         x1 = y1 = x2 = y2 = 0;
622
623         // transform all corners that are infront of the nearclip plane
624         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
625         plane4f[3] = r_refdef.view.frustum[4].dist;
626         numvertices = 0;
627         for (i = 0;i < 8;i++)
628         {
629                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
630                 dist[i] = DotProduct4(corner[i], plane4f);
631                 sign[i] = dist[i] > 0;
632                 if (!sign[i])
633                 {
634                         VectorCopy(corner[i], vertex[numvertices]);
635                         numvertices++;
636                 }
637         }
638         // if some points are behind the nearclip, add clipped edge points to make
639         // sure that the scissor boundary is complete
640         if (numvertices > 0 && numvertices < 8)
641         {
642                 // add clipped edge points
643                 for (i = 0;i < 12;i++)
644                 {
645                         j = bboxedges[i][0];
646                         k = bboxedges[i][1];
647                         if (sign[j] != sign[k])
648                         {
649                                 f = dist[j] / (dist[j] - dist[k]);
650                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
651                                 numvertices++;
652                         }
653                 }
654         }
655
656         // if we have no points to check, it is behind the view plane
657         if (!numvertices)
658                 return true;
659
660         // if we have some points to transform, check what screen area is covered
661         x1 = y1 = x2 = y2 = 0;
662         v[3] = 1.0f;
663         //Con_Printf("%i vertices to transform...\n", numvertices);
664         for (i = 0;i < numvertices;i++)
665         {
666                 VectorCopy(vertex[i], v);
667                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
668                 //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]);
669                 if (i)
670                 {
671                         if (x1 > v2[0]) x1 = v2[0];
672                         if (x2 < v2[0]) x2 = v2[0];
673                         if (y1 > v2[1]) y1 = v2[1];
674                         if (y2 < v2[1]) y2 = v2[1];
675                 }
676                 else
677                 {
678                         x1 = x2 = v2[0];
679                         y1 = y2 = v2[1];
680                 }
681         }
682
683         // now convert the scissor rectangle to integer screen coordinates
684         ix1 = (int)(x1 - 1.0f);
685         //iy1 = vid.height - (int)(y2 - 1.0f);
686         //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f);
687         iy1 = (int)(y1 - 1.0f);
688         ix2 = (int)(x2 + 1.0f);
689         //iy2 = vid.height - (int)(y1 + 1.0f);
690         //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f);
691         iy2 = (int)(y2 + 1.0f);
692         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
693
694         // clamp it to the screen
695         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
696         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
697         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
698         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
699
700         // if it is inside out, it's not visible
701         if (ix2 <= ix1 || iy2 <= iy1)
702                 return true;
703
704         // the light area is visible, set up the scissor rectangle
705         scissor[0] = ix1;
706         scissor[1] = iy1;
707         scissor[2] = ix2 - ix1;
708         scissor[3] = iy2 - iy1;
709
710         // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
711         switch(vid.renderpath)
712         {
713         case RENDERPATH_D3D9:
714         case RENDERPATH_D3D10:
715         case RENDERPATH_D3D11:
716                 scissor[1] = vid.height - scissor[1] - scissor[3];
717                 break;
718         case RENDERPATH_GL11:
719         case RENDERPATH_GL13:
720         case RENDERPATH_GL20:
721         case RENDERPATH_SOFT:
722         case RENDERPATH_GLES1:
723         case RENDERPATH_GLES2:
724                 break;
725         }
726
727         return false;
728 }
729
730
731 static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m, float normalx, float normaly, float normalz, float dist)
732 {
733         float q[4];
734         float d;
735         float clipPlane[4], v3[3], v4[3];
736         float normal[3];
737
738         // This is inspired by Oblique Depth Projection from http://www.terathon.com/code/oblique.php
739
740         VectorSet(normal, normalx, normaly, normalz);
741         Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane);
742         VectorScale(normal, -dist, v3);
743         Matrix4x4_Transform(&v->viewmatrix, v3, v4);
744         // FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique
745         clipPlane[3] = -DotProduct(v4, clipPlane);
746
747 #if 0
748 {
749         // testing code for comparing results
750         float clipPlane2[4];
751         VectorCopy4(clipPlane, clipPlane2);
752         R_EntityMatrix(&identitymatrix);
753         VectorSet(q, normal[0], normal[1], normal[2], -dist);
754         qglClipPlane(GL_CLIP_PLANE0, q);
755         qglGetClipPlane(GL_CLIP_PLANE0, q);
756         VectorCopy4(q, clipPlane);
757 }
758 #endif
759
760         // Calculate the clip-space corner point opposite the clipping plane
761         // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
762         // transform it into camera space by multiplying it
763         // by the inverse of the projection matrix
764         q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + m[8]) / m[0];
765         q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + m[9]) / m[5];
766         q[2] = -1.0f;
767         q[3] = (1.0f + m[10]) / m[14];
768
769         // Calculate the scaled plane vector
770         d = 2.0f / DotProduct4(clipPlane, q);
771
772         // Replace the third row of the projection matrix
773         m[2] = clipPlane[0] * d;
774         m[6] = clipPlane[1] * d;
775         m[10] = clipPlane[2] * d + 1.0f;
776         m[14] = clipPlane[3] * d;
777 }
778
779 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)
780 {
781         float left = x1, right = x2, bottom = y2, top = y1, zNear = nearclip, zFar = farclip;
782         float m[16];
783         memset(v, 0, sizeof(*v));
784         v->type = R_VIEWPORTTYPE_ORTHO;
785         v->cameramatrix = *cameramatrix;
786         v->x = x;
787         v->y = y;
788         v->z = 0;
789         v->width = width;
790         v->height = height;
791         v->depth = 1;
792         memset(m, 0, sizeof(m));
793         m[0]  = 2/(right - left);
794         m[5]  = 2/(top - bottom);
795         m[10] = -2/(zFar - zNear);
796         m[12] = - (right + left)/(right - left);
797         m[13] = - (top + bottom)/(top - bottom);
798         m[14] = - (zFar + zNear)/(zFar - zNear);
799         m[15] = 1;
800         switch(vid.renderpath)
801         {
802         case RENDERPATH_GL11:
803         case RENDERPATH_GL13:
804         case RENDERPATH_GL20:
805         case RENDERPATH_SOFT:
806         case RENDERPATH_GLES1:
807         case RENDERPATH_GLES2:
808                 break;
809         case RENDERPATH_D3D9:
810         case RENDERPATH_D3D10:
811         case RENDERPATH_D3D11:
812                 m[10] = -1/(zFar - zNear);
813                 m[14] = -zNear/(zFar-zNear);
814                 break;
815         }
816         v->screentodepth[0] = -farclip / (farclip - nearclip);
817         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
818
819         Matrix4x4_Invert_Full(&v->viewmatrix, &v->cameramatrix);
820
821         if (nearplane)
822                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
823
824         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
825
826 #if 0
827         {
828                 vec4_t test1;
829                 vec4_t test2;
830                 Vector4Set(test1, (x1+x2)*0.5f, (y1+y2)*0.5f, 0.0f, 1.0f);
831                 R_Viewport_TransformToScreen(v, test1, test2);
832                 Con_Printf("%f %f %f -> %f %f %f\n", test1[0], test1[1], test1[2], test2[0], test2[1], test2[2]);
833         }
834 #endif
835 }
836
837 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)
838 {
839         matrix4x4_t tempmatrix, basematrix;
840         float m[16];
841         memset(v, 0, sizeof(*v));
842
843         v->type = R_VIEWPORTTYPE_PERSPECTIVE;
844         v->cameramatrix = *cameramatrix;
845         v->x = x;
846         v->y = y;
847         v->z = 0;
848         v->width = width;
849         v->height = height;
850         v->depth = 1;
851         memset(m, 0, sizeof(m));
852         m[0]  = 1.0 / frustumx;
853         m[5]  = 1.0 / frustumy;
854         m[10] = -(farclip + nearclip) / (farclip - nearclip);
855         m[11] = -1;
856         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
857         v->screentodepth[0] = -farclip / (farclip - nearclip);
858         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
859
860         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
861         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
862         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
863         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
864
865         if (nearplane)
866                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
867
868         if(v_flipped.integer)
869         {
870                 m[0] = -m[0];
871                 m[4] = -m[4];
872                 m[8] = -m[8];
873                 m[12] = -m[12];
874         }
875
876         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
877 }
878
879 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)
880 {
881         matrix4x4_t tempmatrix, basematrix;
882         const float nudge = 1.0 - 1.0 / (1<<23);
883         float m[16];
884         memset(v, 0, sizeof(*v));
885
886         v->type = R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP;
887         v->cameramatrix = *cameramatrix;
888         v->x = x;
889         v->y = y;
890         v->z = 0;
891         v->width = width;
892         v->height = height;
893         v->depth = 1;
894         memset(m, 0, sizeof(m));
895         m[ 0] = 1.0 / frustumx;
896         m[ 5] = 1.0 / frustumy;
897         m[10] = -nudge;
898         m[11] = -1;
899         m[14] = -2 * nearclip * nudge;
900         v->screentodepth[0] = (m[10] + 1) * 0.5 - 1;
901         v->screentodepth[1] = m[14] * -0.5;
902
903         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
904         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
905         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
906         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
907
908         if (nearplane)
909                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
910
911         if(v_flipped.integer)
912         {
913                 m[0] = -m[0];
914                 m[4] = -m[4];
915                 m[8] = -m[8];
916                 m[12] = -m[12];
917         }
918
919         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
920 }
921
922 float cubeviewmatrix[6][16] =
923 {
924     // standard cubemap projections
925     { // +X
926          0, 0,-1, 0,
927          0,-1, 0, 0,
928         -1, 0, 0, 0,
929          0, 0, 0, 1,
930     },
931     { // -X
932          0, 0, 1, 0,
933          0,-1, 0, 0,
934          1, 0, 0, 0,
935          0, 0, 0, 1,
936     },
937     { // +Y
938          1, 0, 0, 0,
939          0, 0,-1, 0,
940          0, 1, 0, 0,
941          0, 0, 0, 1,
942     },
943     { // -Y
944          1, 0, 0, 0,
945          0, 0, 1, 0,
946          0,-1, 0, 0,
947          0, 0, 0, 1,
948     },
949     { // +Z
950          1, 0, 0, 0,
951          0,-1, 0, 0,
952          0, 0,-1, 0,
953          0, 0, 0, 1,
954     },
955     { // -Z
956         -1, 0, 0, 0,
957          0,-1, 0, 0,
958          0, 0, 1, 0,
959          0, 0, 0, 1,
960     },
961 };
962 float rectviewmatrix[6][16] =
963 {
964     // sign-preserving cubemap projections
965     { // +X
966          0, 0,-1, 0,
967          0, 1, 0, 0,
968          1, 0, 0, 0,
969          0, 0, 0, 1,
970     },
971     { // -X
972          0, 0, 1, 0,
973          0, 1, 0, 0,
974          1, 0, 0, 0,
975          0, 0, 0, 1,
976     },
977     { // +Y
978          1, 0, 0, 0,
979          0, 0,-1, 0,
980          0, 1, 0, 0,
981          0, 0, 0, 1,
982     },
983     { // -Y
984          1, 0, 0, 0,
985          0, 0, 1, 0,
986          0, 1, 0, 0,
987          0, 0, 0, 1,
988     },
989     { // +Z
990          1, 0, 0, 0,
991          0, 1, 0, 0,
992          0, 0,-1, 0,
993          0, 0, 0, 1,
994     },
995     { // -Z
996          1, 0, 0, 0,
997          0, 1, 0, 0,
998          0, 0, 1, 0,
999          0, 0, 0, 1,
1000     },
1001 };
1002
1003 void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane)
1004 {
1005         matrix4x4_t tempmatrix, basematrix;
1006         float m[16];
1007         memset(v, 0, sizeof(*v));
1008         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
1009         v->cameramatrix = *cameramatrix;
1010         v->width = size;
1011         v->height = size;
1012         v->depth = 1;
1013         memset(m, 0, sizeof(m));
1014         m[0] = m[5] = 1.0f;
1015         m[10] = -(farclip + nearclip) / (farclip - nearclip);
1016         m[11] = -1;
1017         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
1018
1019         Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]);
1020         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
1021         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
1022
1023         if (nearplane)
1024                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
1025
1026         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
1027 }
1028
1029 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)
1030 {
1031         matrix4x4_t tempmatrix, basematrix;
1032         float m[16];
1033         memset(v, 0, sizeof(*v));
1034         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
1035         v->cameramatrix = *cameramatrix;
1036         v->x = (side & 1) * size;
1037         v->y = (side >> 1) * size;
1038         v->width = size;
1039         v->height = size;
1040         v->depth = 1;
1041         memset(m, 0, sizeof(m));
1042         m[0] = m[5] = 1.0f * ((float)size - border) / size;
1043         m[10] = -(farclip + nearclip) / (farclip - nearclip);
1044         m[11] = -1;
1045         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
1046
1047         Matrix4x4_FromArrayFloatGL(&basematrix, rectviewmatrix[side]);
1048         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
1049         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
1050
1051         switch(vid.renderpath)
1052         {
1053         case RENDERPATH_GL20:
1054         case RENDERPATH_GL13:
1055         case RENDERPATH_GL11:
1056         case RENDERPATH_SOFT:
1057         case RENDERPATH_GLES1:
1058         case RENDERPATH_GLES2:
1059                 break;
1060         case RENDERPATH_D3D9:
1061                 m[5] *= -1;
1062                 break;
1063         case RENDERPATH_D3D10:
1064                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1065                 break;
1066         case RENDERPATH_D3D11:
1067                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1068                 break;
1069         }
1070
1071         if (nearplane)
1072                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
1073
1074         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
1075 }
1076
1077 void R_SetViewport(const r_viewport_t *v)
1078 {
1079         float m[16];
1080         gl_viewport = *v;
1081
1082         // FIXME: v_flipped_state is evil, this probably breaks somewhere
1083         GL_SetMirrorState(v_flipped.integer && (v->type == R_VIEWPORTTYPE_PERSPECTIVE || v->type == R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP));
1084
1085         // copy over the matrices to our state
1086         gl_viewmatrix = v->viewmatrix;
1087         gl_projectionmatrix = v->projectmatrix;
1088
1089         switch(vid.renderpath)
1090         {
1091         case RENDERPATH_GL13:
1092         case RENDERPATH_GL11:
1093         case RENDERPATH_GLES1:
1094                 CHECKGLERROR
1095                 qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
1096                 // Load the projection matrix into OpenGL
1097                 qglMatrixMode(GL_PROJECTION);CHECKGLERROR
1098                 Matrix4x4_ToArrayFloatGL(&gl_projectionmatrix, m);
1099                 qglLoadMatrixf(m);CHECKGLERROR
1100                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1101                 break;
1102         case RENDERPATH_D3D9:
1103 #ifdef SUPPORTD3D
1104                 {
1105                         D3DVIEWPORT9 d3dviewport;
1106                         d3dviewport.X = gl_viewport.x;
1107                         d3dviewport.Y = gl_viewport.y;
1108                         d3dviewport.Width = gl_viewport.width;
1109                         d3dviewport.Height = gl_viewport.height;
1110                         d3dviewport.MinZ = gl_state.depthrange[0];
1111                         d3dviewport.MaxZ = gl_state.depthrange[1];
1112                         IDirect3DDevice9_SetViewport(vid_d3d9dev, &d3dviewport);
1113                 }
1114 #endif
1115                 break;
1116         case RENDERPATH_D3D10:
1117                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1118                 break;
1119         case RENDERPATH_D3D11:
1120                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1121                 break;
1122         case RENDERPATH_SOFT:
1123                 DPSOFTRAST_Viewport(v->x, v->y, v->width, v->height);
1124                 break;
1125         case RENDERPATH_GL20:
1126         case RENDERPATH_GLES2:
1127                 CHECKGLERROR
1128                 qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
1129                 break;
1130         }
1131
1132         // force an update of the derived matrices
1133         gl_modelmatrixchanged = true;
1134         R_EntityMatrix(&gl_modelmatrix);
1135 }
1136
1137 void R_GetViewport(r_viewport_t *v)
1138 {
1139         *v = gl_viewport;
1140 }
1141
1142 static void GL_BindVBO(int bufferobject)
1143 {
1144         if (gl_state.vertexbufferobject != bufferobject)
1145         {
1146                 gl_state.vertexbufferobject = bufferobject;
1147                 CHECKGLERROR
1148                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);CHECKGLERROR
1149         }
1150 }
1151
1152 static void GL_BindEBO(int bufferobject)
1153 {
1154         if (gl_state.elementbufferobject != bufferobject)
1155         {
1156                 gl_state.elementbufferobject = bufferobject;
1157                 CHECKGLERROR
1158                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);CHECKGLERROR
1159         }
1160 }
1161
1162 int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
1163 {
1164         int temp;
1165         switch(vid.renderpath)
1166         {
1167         case RENDERPATH_GL11:
1168         case RENDERPATH_GL13:
1169         case RENDERPATH_GL20:
1170         case RENDERPATH_GLES1:
1171         case RENDERPATH_GLES2:
1172                 if (!vid.support.ext_framebuffer_object)
1173                         return 0;
1174                 qglGenFramebuffersEXT(1, (GLuint*)&temp);CHECKGLERROR
1175                 R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
1176                 if (depthtexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, depthtexture->gltexturetypeenum, R_GetTexture(depthtexture), 0);CHECKGLERROR
1177                 if (colortexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, colortexture->gltexturetypeenum, R_GetTexture(colortexture), 0);CHECKGLERROR
1178                 if (colortexture2) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, colortexture2->gltexturetypeenum, R_GetTexture(colortexture2), 0);CHECKGLERROR
1179                 if (colortexture3) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, colortexture3->gltexturetypeenum, R_GetTexture(colortexture3), 0);CHECKGLERROR
1180                 if (colortexture4) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, colortexture4->gltexturetypeenum, R_GetTexture(colortexture4), 0);CHECKGLERROR
1181                 return temp;
1182         case RENDERPATH_D3D9:
1183         case RENDERPATH_D3D10:
1184         case RENDERPATH_D3D11:
1185                 return 1;
1186         case RENDERPATH_SOFT:
1187                 return 1;
1188         }
1189         return 0;
1190 }
1191
1192 void R_Mesh_DestroyFramebufferObject(int fbo)
1193 {
1194         switch(vid.renderpath)
1195         {
1196         case RENDERPATH_GL11:
1197         case RENDERPATH_GL13:
1198         case RENDERPATH_GL20:
1199         case RENDERPATH_GLES1:
1200         case RENDERPATH_GLES2:
1201                 if (fbo)
1202                         qglDeleteFramebuffersEXT(1, (GLuint*)&fbo);
1203                 break;
1204         case RENDERPATH_D3D9:
1205         case RENDERPATH_D3D10:
1206         case RENDERPATH_D3D11:
1207                 break;
1208         case RENDERPATH_SOFT:
1209                 break;
1210         }
1211 }
1212
1213 #ifdef SUPPORTD3D
1214 void R_Mesh_SetRenderTargetsD3D9(IDirect3DSurface9 *depthsurface, IDirect3DSurface9 *colorsurface0, IDirect3DSurface9 *colorsurface1, IDirect3DSurface9 *colorsurface2, IDirect3DSurface9 *colorsurface3)
1215 {
1216 // LordHavoc: for some weird reason the redundant SetDepthStencilSurface calls are necessary (otherwise the lights fail depth test, as if they were using the shadowmap depth surface and render target still)
1217         if (gl_state.d3drt_depthsurface == depthsurface && gl_state.d3drt_colorsurfaces[0] == colorsurface0 && gl_state.d3drt_colorsurfaces[1] == colorsurface1 && gl_state.d3drt_colorsurfaces[2] == colorsurface2 && gl_state.d3drt_colorsurfaces[3] == colorsurface3)
1218                 return;
1219
1220         gl_state.framebufferobject = depthsurface != gl_state.d3drt_backbufferdepthsurface || colorsurface0 != gl_state.d3drt_backbuffercolorsurface;
1221         if (gl_state.d3drt_depthsurface != depthsurface)
1222         {
1223                 gl_state.d3drt_depthsurface = depthsurface;
1224                 IDirect3DDevice9_SetDepthStencilSurface(vid_d3d9dev, gl_state.d3drt_depthsurface);
1225         }
1226         if (gl_state.d3drt_colorsurfaces[0] != colorsurface0)
1227         {
1228                 gl_state.d3drt_colorsurfaces[0] = colorsurface0;
1229                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 0, gl_state.d3drt_colorsurfaces[0]);
1230         }
1231         if (gl_state.d3drt_colorsurfaces[1] != colorsurface1)
1232         {
1233                 gl_state.d3drt_colorsurfaces[1] = colorsurface1;
1234                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 1, gl_state.d3drt_colorsurfaces[1]);
1235         }
1236         if (gl_state.d3drt_colorsurfaces[2] != colorsurface2)
1237         {
1238                 gl_state.d3drt_colorsurfaces[2] = colorsurface2;
1239                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 2, gl_state.d3drt_colorsurfaces[2]);
1240         }
1241         if (gl_state.d3drt_colorsurfaces[3] != colorsurface3)
1242         {
1243                 gl_state.d3drt_colorsurfaces[3] = colorsurface3;
1244                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 3, gl_state.d3drt_colorsurfaces[3]);
1245         }
1246 }
1247 #endif
1248
1249 void R_Mesh_ResetRenderTargets(void)
1250 {
1251         switch(vid.renderpath)
1252         {
1253         case RENDERPATH_GL11:
1254         case RENDERPATH_GL13:
1255         case RENDERPATH_GL20:
1256         case RENDERPATH_GLES1:
1257         case RENDERPATH_GLES2:
1258                 if (gl_state.framebufferobject)
1259                 {
1260                         gl_state.framebufferobject = 0;
1261                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.defaultframebufferobject);
1262                 }
1263                 break;
1264         case RENDERPATH_D3D9:
1265 #ifdef SUPPORTD3D
1266                 R_Mesh_SetRenderTargetsD3D9(gl_state.d3drt_backbufferdepthsurface, gl_state.d3drt_backbuffercolorsurface, NULL, NULL, NULL);
1267 #endif
1268                 break;
1269         case RENDERPATH_D3D10:
1270                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1271                 break;
1272         case RENDERPATH_D3D11:
1273                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1274                 break;
1275         case RENDERPATH_SOFT:
1276                 DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
1277                 break;
1278         }
1279 }
1280
1281 void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
1282 {
1283         unsigned int i;
1284         unsigned int j;
1285         rtexture_t *textures[5];
1286         Vector4Set(textures, colortexture, colortexture2, colortexture3, colortexture4);
1287         textures[4] = depthtexture;
1288         // unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target
1289         for (j = 0;j < 5;j++)
1290                 if (textures[j])
1291                         for (i = 0;i < vid.teximageunits;i++)
1292                                 if (gl_state.units[i].texture == textures[j])
1293                                         R_Mesh_TexBind(i, NULL);
1294         // set up framebuffer object or render targets for the active rendering API
1295         switch(vid.renderpath)
1296         {
1297         case RENDERPATH_GL11:
1298         case RENDERPATH_GL13:
1299         case RENDERPATH_GL20:
1300         case RENDERPATH_GLES1:
1301         case RENDERPATH_GLES2:
1302                 if (gl_state.framebufferobject != fbo)
1303                 {
1304                         gl_state.framebufferobject = fbo;
1305                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);
1306                 }
1307                 break;
1308         case RENDERPATH_D3D9:
1309 #ifdef SUPPORTD3D
1310                 // set up the new render targets, a NULL depthtexture intentionally binds nothing
1311                 // TODO: optimize: keep surface pointer around in rtexture_t until texture is freed or lost
1312                 if (fbo)
1313                 {
1314                         IDirect3DSurface9 *colorsurfaces[4];
1315                         for (i = 0;i < 4;i++)
1316                         {
1317                                 colorsurfaces[i] = NULL;
1318                                 if (textures[i])
1319                                         IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9 *)textures[i]->d3dtexture, 0, &colorsurfaces[i]);
1320                         }
1321                         // set the render targets for real
1322                         R_Mesh_SetRenderTargetsD3D9(depthtexture ? (IDirect3DSurface9 *)depthtexture->d3dtexture : NULL, colorsurfaces[0], colorsurfaces[1], colorsurfaces[2], colorsurfaces[3]);
1323                         // release the texture surface levels (they won't be lost while bound...)
1324                         for (i = 0;i < 4;i++)
1325                                 if (textures[i])
1326                                         IDirect3DSurface9_Release(colorsurfaces[i]);
1327                 }
1328                 else
1329                         R_Mesh_SetRenderTargetsD3D9(gl_state.d3drt_backbufferdepthsurface, gl_state.d3drt_backbuffercolorsurface, NULL, NULL, NULL);
1330 #endif
1331                 break;
1332         case RENDERPATH_D3D10:
1333                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1334                 break;
1335         case RENDERPATH_D3D11:
1336                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1337                 break;
1338         case RENDERPATH_SOFT:
1339                 if (fbo)
1340                 {
1341                         int width, height;
1342                         unsigned int *pointers[5];
1343                         memset(pointers, 0, sizeof(pointers));
1344                         for (i = 0;i < 5;i++)
1345                                 pointers[i] = textures[i] ? (unsigned int *)DPSOFTRAST_Texture_GetPixelPointer(textures[i]->texnum, 0) : NULL;
1346                         width = DPSOFTRAST_Texture_GetWidth(textures[0] ? textures[0]->texnum : textures[4]->texnum, 0);
1347                         height = DPSOFTRAST_Texture_GetHeight(textures[0] ? textures[0]->texnum : textures[4]->texnum, 0);
1348                         DPSOFTRAST_SetRenderTargets(width, height, pointers[4], pointers[0], pointers[1], pointers[2], pointers[3]);
1349                 }
1350                 else
1351                         DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
1352                 break;
1353         }
1354 }
1355
1356 #ifdef SUPPORTD3D
1357 static int d3dcmpforglfunc(int f)
1358 {
1359         switch(f)
1360         {
1361         case GL_NEVER: return D3DCMP_NEVER;
1362         case GL_LESS: return D3DCMP_LESS;
1363         case GL_EQUAL: return D3DCMP_EQUAL;
1364         case GL_LEQUAL: return D3DCMP_LESSEQUAL;
1365         case GL_GREATER: return D3DCMP_GREATER;
1366         case GL_NOTEQUAL: return D3DCMP_NOTEQUAL;
1367         case GL_GEQUAL: return D3DCMP_GREATEREQUAL;
1368         case GL_ALWAYS: return D3DCMP_ALWAYS;
1369         default: Con_DPrintf("Unknown GL_DepthFunc\n");return D3DCMP_ALWAYS;
1370         }
1371 }
1372
1373 static int d3dstencilopforglfunc(int f)
1374 {
1375         switch(f)
1376         {
1377         case GL_KEEP: return D3DSTENCILOP_KEEP;
1378         case GL_INCR: return D3DSTENCILOP_INCR; // note: GL_INCR is clamped, D3DSTENCILOP_INCR wraps
1379         case GL_DECR: return D3DSTENCILOP_DECR; // note: GL_DECR is clamped, D3DSTENCILOP_DECR wraps
1380         default: Con_DPrintf("Unknown GL_StencilFunc\n");return D3DSTENCILOP_KEEP;
1381         }
1382 }
1383 #endif
1384
1385 extern cvar_t r_transparent_alphatocoverage;
1386
1387 static void GL_Backend_ResetState(void)
1388 {
1389         unsigned int i;
1390         gl_state.active = true;
1391         gl_state.depthtest = true;
1392         gl_state.alphatest = false;
1393         gl_state.alphafunc = GL_GEQUAL;
1394         gl_state.alphafuncvalue = 0.5f;
1395         gl_state.alphatocoverage = false;
1396         gl_state.blendfunc1 = GL_ONE;
1397         gl_state.blendfunc2 = GL_ZERO;
1398         gl_state.blend = false;
1399         gl_state.depthmask = GL_TRUE;
1400         gl_state.colormask = 15;
1401         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
1402         gl_state.lockrange_first = 0;
1403         gl_state.lockrange_count = 0;
1404         gl_state.cullface = GL_FRONT;
1405         gl_state.cullfaceenable = false;
1406         gl_state.polygonoffset[0] = 0;
1407         gl_state.polygonoffset[1] = 0;
1408         gl_state.framebufferobject = 0;
1409         gl_state.depthfunc = GL_LEQUAL;
1410
1411         switch(vid.renderpath)
1412         {
1413         case RENDERPATH_D3D9:
1414 #ifdef SUPPORTD3D
1415                 {
1416                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, gl_state.colormask);
1417                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_NONE);
1418                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZFUNC, d3dcmpforglfunc(gl_state.depthfunc));
1419                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZENABLE, gl_state.depthtest);
1420                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZWRITEENABLE, gl_state.depthmask);
1421                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SLOPESCALEDEPTHBIAS, gl_state.polygonoffset[0]);
1422                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DEPTHBIAS, gl_state.polygonoffset[1] * (1.0f / 16777216.0f));
1423                 }
1424 #endif
1425                 break;
1426         case RENDERPATH_D3D10:
1427                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1428                 break;
1429         case RENDERPATH_D3D11:
1430                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1431                 break;
1432         case RENDERPATH_GL11:
1433         case RENDERPATH_GL13:
1434         case RENDERPATH_GLES1:
1435                 CHECKGLERROR
1436
1437                 qglColorMask(1, 1, 1, 1);CHECKGLERROR
1438                 qglAlphaFunc(gl_state.alphafunc, gl_state.alphafuncvalue);CHECKGLERROR
1439                 qglDisable(GL_ALPHA_TEST);CHECKGLERROR
1440                 qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1441                 qglDisable(GL_BLEND);CHECKGLERROR
1442                 qglCullFace(gl_state.cullface);CHECKGLERROR
1443                 qglDisable(GL_CULL_FACE);CHECKGLERROR
1444                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1445                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1446                 qglDepthMask(gl_state.depthmask);CHECKGLERROR
1447                 qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1448
1449                 if (vid.support.arb_vertex_buffer_object)
1450                 {
1451                         qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1452                         qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1453                 }
1454
1455                 if (vid.support.ext_framebuffer_object)
1456                 {
1457                         //qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
1458                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1459                 }
1460
1461                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
1462                 qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1463
1464                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
1465                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1466                 qglColor4f(1, 1, 1, 1);CHECKGLERROR
1467
1468                 if (vid.support.ext_framebuffer_object)
1469                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.framebufferobject);
1470
1471                 gl_state.unit = MAX_TEXTUREUNITS;
1472                 gl_state.clientunit = MAX_TEXTUREUNITS;
1473                 for (i = 0;i < vid.texunits;i++)
1474                 {
1475                         GL_ActiveTexture(i);
1476                         GL_ClientActiveTexture(i);
1477                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1478                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1479                         if (vid.support.ext_texture_3d)
1480                         {
1481                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1482                                 qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1483                         }
1484                         if (vid.support.arb_texture_cube_map)
1485                         {
1486                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1487                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1488                         }
1489                         GL_BindVBO(0);
1490                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
1491                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1492                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1493                         qglLoadIdentity();CHECKGLERROR
1494                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1495                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1496                 }
1497                 CHECKGLERROR
1498                 break;
1499         case RENDERPATH_SOFT:
1500                 DPSOFTRAST_ColorMask(1,1,1,1);
1501                 DPSOFTRAST_BlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);
1502                 DPSOFTRAST_CullFace(gl_state.cullface);
1503                 DPSOFTRAST_DepthFunc(gl_state.depthfunc);
1504                 DPSOFTRAST_DepthMask(gl_state.depthmask);
1505                 DPSOFTRAST_PolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1506                 DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
1507                 DPSOFTRAST_Viewport(0, 0, vid.width, vid.height);
1508                 break;
1509         case RENDERPATH_GL20:
1510         case RENDERPATH_GLES2:
1511                 CHECKGLERROR
1512                 qglColorMask(1, 1, 1, 1);CHECKGLERROR
1513                 qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1514                 qglDisable(GL_BLEND);CHECKGLERROR
1515                 qglCullFace(gl_state.cullface);CHECKGLERROR
1516                 qglDisable(GL_CULL_FACE);CHECKGLERROR
1517                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1518                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1519                 qglDepthMask(gl_state.depthmask);CHECKGLERROR
1520                 qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1521                 if (vid.support.arb_vertex_buffer_object)
1522                 {
1523                         qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1524                         qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1525                 }
1526                 if (vid.support.ext_framebuffer_object)
1527                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.defaultframebufferobject);
1528                 qglEnableVertexAttribArray(GLSLATTRIB_POSITION);
1529                 qglVertexAttribPointer(GLSLATTRIB_POSITION, 3, GL_FLOAT, false, sizeof(float[3]), NULL);CHECKGLERROR
1530                 qglDisableVertexAttribArray(GLSLATTRIB_COLOR);
1531                 qglVertexAttribPointer(GLSLATTRIB_COLOR, 4, GL_FLOAT, false, sizeof(float[4]), NULL);CHECKGLERROR
1532                 qglVertexAttrib4f(GLSLATTRIB_COLOR, 1, 1, 1, 1);
1533                 gl_state.unit = MAX_TEXTUREUNITS;
1534                 gl_state.clientunit = MAX_TEXTUREUNITS;
1535                 for (i = 0;i < vid.teximageunits;i++)
1536                 {
1537                         GL_ActiveTexture(i);
1538                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1539                         if (vid.support.ext_texture_3d)
1540                         {
1541                                 qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1542                         }
1543                         if (vid.support.arb_texture_cube_map)
1544                         {
1545                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1546                         }
1547                 }
1548                 for (i = 0;i < vid.texarrayunits;i++)
1549                 {
1550                         GL_BindVBO(0);
1551                         qglVertexAttribPointer(i+GLSLATTRIB_TEXCOORD0, 2, GL_FLOAT, false, sizeof(float[2]), NULL);CHECKGLERROR
1552                         qglDisableVertexAttribArray(i+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
1553                 }
1554                 CHECKGLERROR
1555                 break;
1556         }
1557 }
1558
1559 void GL_ActiveTexture(unsigned int num)
1560 {
1561         if (gl_state.unit != num)
1562         {
1563                 gl_state.unit = num;
1564                 switch(vid.renderpath)
1565                 {
1566                 case RENDERPATH_GL11:
1567                 case RENDERPATH_GL13:
1568                 case RENDERPATH_GL20:
1569                 case RENDERPATH_GLES1:
1570                 case RENDERPATH_GLES2:
1571                         if (qglActiveTexture)
1572                         {
1573                                 CHECKGLERROR
1574                                 qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
1575                                 CHECKGLERROR
1576                         }
1577                         break;
1578                 case RENDERPATH_D3D9:
1579                 case RENDERPATH_D3D10:
1580                 case RENDERPATH_D3D11:
1581                         break;
1582                 case RENDERPATH_SOFT:
1583                         break;
1584                 }
1585         }
1586 }
1587
1588 void GL_ClientActiveTexture(unsigned int num)
1589 {
1590         if (gl_state.clientunit != num)
1591         {
1592                 gl_state.clientunit = num;
1593                 switch(vid.renderpath)
1594                 {
1595                 case RENDERPATH_GL11:
1596                 case RENDERPATH_GL13:
1597                 case RENDERPATH_GLES1:
1598                         if (qglActiveTexture)
1599                         {
1600                                 CHECKGLERROR
1601                                 qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
1602                                 CHECKGLERROR
1603                         }
1604                         break;
1605                 case RENDERPATH_D3D9:
1606                 case RENDERPATH_D3D10:
1607                 case RENDERPATH_D3D11:
1608                         break;
1609                 case RENDERPATH_SOFT:
1610                         break;
1611                 case RENDERPATH_GL20:
1612                 case RENDERPATH_GLES2:
1613                         break;
1614                 }
1615         }
1616 }
1617
1618 void GL_BlendFunc(int blendfunc1, int blendfunc2)
1619 {
1620         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
1621         {
1622                 qboolean blendenable;
1623                 gl_state.blendfunc1 = blendfunc1;
1624                 gl_state.blendfunc2 = blendfunc2;
1625                 blendenable = (gl_state.blendfunc1 != GL_ONE || gl_state.blendfunc2 != GL_ZERO);
1626                 switch(vid.renderpath)
1627                 {
1628                 case RENDERPATH_GL11:
1629                 case RENDERPATH_GL13:
1630                 case RENDERPATH_GL20:
1631                 case RENDERPATH_GLES1:
1632                 case RENDERPATH_GLES2:
1633                         CHECKGLERROR
1634                         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1635                         if (gl_state.blend != blendenable)
1636                         {
1637                                 gl_state.blend = blendenable;
1638                                 if (!gl_state.blend)
1639                                 {
1640                                         qglDisable(GL_BLEND);CHECKGLERROR
1641                                 }
1642                                 else
1643                                 {
1644                                         qglEnable(GL_BLEND);CHECKGLERROR
1645                                 }
1646                         }
1647                         break;
1648                 case RENDERPATH_D3D9:
1649 #ifdef SUPPORTD3D
1650                         {
1651                                 int i;
1652                                 int glblendfunc[2];
1653                                 D3DBLEND d3dblendfunc[2];
1654                                 glblendfunc[0] = gl_state.blendfunc1;
1655                                 glblendfunc[1] = gl_state.blendfunc2;
1656                                 for (i = 0;i < 2;i++)
1657                                 {
1658                                         switch(glblendfunc[i])
1659                                         {
1660                                         case GL_ZERO: d3dblendfunc[i] = D3DBLEND_ZERO;break;
1661                                         case GL_ONE: d3dblendfunc[i] = D3DBLEND_ONE;break;
1662                                         case GL_SRC_COLOR: d3dblendfunc[i] = D3DBLEND_SRCCOLOR;break;
1663                                         case GL_ONE_MINUS_SRC_COLOR: d3dblendfunc[i] = D3DBLEND_INVSRCCOLOR;break;
1664                                         case GL_SRC_ALPHA: d3dblendfunc[i] = D3DBLEND_SRCALPHA;break;
1665                                         case GL_ONE_MINUS_SRC_ALPHA: d3dblendfunc[i] = D3DBLEND_INVSRCALPHA;break;
1666                                         case GL_DST_ALPHA: d3dblendfunc[i] = D3DBLEND_DESTALPHA;break;
1667                                         case GL_ONE_MINUS_DST_ALPHA: d3dblendfunc[i] = D3DBLEND_INVDESTALPHA;break;
1668                                         case GL_DST_COLOR: d3dblendfunc[i] = D3DBLEND_DESTCOLOR;break;
1669                                         case GL_ONE_MINUS_DST_COLOR: d3dblendfunc[i] = D3DBLEND_INVDESTCOLOR;break;
1670                                         }
1671                                 }
1672                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SRCBLEND, d3dblendfunc[0]);
1673                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DESTBLEND, d3dblendfunc[1]);
1674                                 if (gl_state.blend != blendenable)
1675                                 {
1676                                         gl_state.blend = blendenable;
1677                                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHABLENDENABLE, gl_state.blend);
1678                                 }
1679                         }
1680 #endif
1681                         break;
1682                 case RENDERPATH_D3D10:
1683                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1684                         break;
1685                 case RENDERPATH_D3D11:
1686                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1687                         break;
1688                 case RENDERPATH_SOFT:
1689                         DPSOFTRAST_BlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);
1690                         break;
1691                 }
1692         }
1693 }
1694
1695 void GL_DepthMask(int state)
1696 {
1697         if (gl_state.depthmask != state)
1698         {
1699                 gl_state.depthmask = state;
1700                 switch(vid.renderpath)
1701                 {
1702                 case RENDERPATH_GL11:
1703                 case RENDERPATH_GL13:
1704                 case RENDERPATH_GL20:
1705                 case RENDERPATH_GLES1:
1706                 case RENDERPATH_GLES2:
1707                         CHECKGLERROR
1708                         qglDepthMask(gl_state.depthmask);CHECKGLERROR
1709                         break;
1710                 case RENDERPATH_D3D9:
1711 #ifdef SUPPORTD3D
1712                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZWRITEENABLE, gl_state.depthmask);
1713 #endif
1714                         break;
1715                 case RENDERPATH_D3D10:
1716                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1717                         break;
1718                 case RENDERPATH_D3D11:
1719                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1720                         break;
1721                 case RENDERPATH_SOFT:
1722                         DPSOFTRAST_DepthMask(gl_state.depthmask);
1723                         break;
1724                 }
1725         }
1726 }
1727
1728 void GL_DepthTest(int state)
1729 {
1730         if (gl_state.depthtest != state)
1731         {
1732                 gl_state.depthtest = state;
1733                 switch(vid.renderpath)
1734                 {
1735                 case RENDERPATH_GL11:
1736                 case RENDERPATH_GL13:
1737                 case RENDERPATH_GL20:
1738                 case RENDERPATH_GLES1:
1739                 case RENDERPATH_GLES2:
1740                         CHECKGLERROR
1741                         if (gl_state.depthtest)
1742                         {
1743                                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1744                         }
1745                         else
1746                         {
1747                                 qglDisable(GL_DEPTH_TEST);CHECKGLERROR
1748                         }
1749                         break;
1750                 case RENDERPATH_D3D9:
1751 #ifdef SUPPORTD3D
1752                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZENABLE, gl_state.depthtest);
1753 #endif
1754                         break;
1755                 case RENDERPATH_D3D10:
1756                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1757                         break;
1758                 case RENDERPATH_D3D11:
1759                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1760                         break;
1761                 case RENDERPATH_SOFT:
1762                         DPSOFTRAST_DepthTest(gl_state.depthtest);
1763                         break;
1764                 }
1765         }
1766 }
1767
1768 void GL_DepthFunc(int state)
1769 {
1770         if (gl_state.depthfunc != state)
1771         {
1772                 gl_state.depthfunc = state;
1773                 switch(vid.renderpath)
1774                 {
1775                 case RENDERPATH_GL11:
1776                 case RENDERPATH_GL13:
1777                 case RENDERPATH_GL20:
1778                 case RENDERPATH_GLES1:
1779                 case RENDERPATH_GLES2:
1780                         CHECKGLERROR
1781                         qglDepthFunc(gl_state.depthfunc);CHECKGLERROR
1782                         break;
1783                 case RENDERPATH_D3D9:
1784 #ifdef SUPPORTD3D
1785                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZFUNC, d3dcmpforglfunc(gl_state.depthfunc));
1786 #endif
1787                         break;
1788                 case RENDERPATH_D3D10:
1789                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1790                         break;
1791                 case RENDERPATH_D3D11:
1792                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1793                         break;
1794                 case RENDERPATH_SOFT:
1795                         DPSOFTRAST_DepthFunc(gl_state.depthfunc);
1796                         break;
1797                 }
1798         }
1799 }
1800
1801 void GL_DepthRange(float nearfrac, float farfrac)
1802 {
1803         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
1804         {
1805                 gl_state.depthrange[0] = nearfrac;
1806                 gl_state.depthrange[1] = farfrac;
1807                 switch(vid.renderpath)
1808                 {
1809                 case RENDERPATH_GL11:
1810                 case RENDERPATH_GL13:
1811                 case RENDERPATH_GL20:
1812                 case RENDERPATH_GLES1:
1813                 case RENDERPATH_GLES2:
1814                         qglDepthRange(gl_state.depthrange[0], gl_state.depthrange[1]);
1815                         break;
1816                 case RENDERPATH_D3D9:
1817 #ifdef SUPPORTD3D
1818                         {
1819                                 D3DVIEWPORT9 d3dviewport;
1820                                 d3dviewport.X = gl_viewport.x;
1821                                 d3dviewport.Y = gl_viewport.y;
1822                                 d3dviewport.Width = gl_viewport.width;
1823                                 d3dviewport.Height = gl_viewport.height;
1824                                 d3dviewport.MinZ = gl_state.depthrange[0];
1825                                 d3dviewport.MaxZ = gl_state.depthrange[1];
1826                                 IDirect3DDevice9_SetViewport(vid_d3d9dev, &d3dviewport);
1827                         }
1828 #endif
1829                         break;
1830                 case RENDERPATH_D3D10:
1831                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1832                         break;
1833                 case RENDERPATH_D3D11:
1834                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1835                         break;
1836                 case RENDERPATH_SOFT:
1837                         DPSOFTRAST_DepthRange(gl_state.depthrange[0], gl_state.depthrange[1]);
1838                         break;
1839                 }
1840         }
1841 }
1842
1843 void R_SetStencilSeparate(qboolean enable, int writemask, int frontfail, int frontzfail, int frontzpass, int backfail, int backzfail, int backzpass, int frontcompare, int backcompare, int comparereference, int comparemask)
1844 {
1845         switch (vid.renderpath)
1846         {
1847         case RENDERPATH_GL11:
1848         case RENDERPATH_GL13:
1849         case RENDERPATH_GL20:
1850         case RENDERPATH_GLES1:
1851         case RENDERPATH_GLES2:
1852                 CHECKGLERROR
1853                 if (enable)
1854                 {
1855                         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1856                 }
1857                 else
1858                 {
1859                         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1860                 }
1861                 if (vid.support.ati_separate_stencil)
1862                 {
1863                         qglStencilMask(writemask);CHECKGLERROR
1864                         qglStencilOpSeparate(GL_FRONT, frontfail, frontzfail, frontzpass);CHECKGLERROR
1865                         qglStencilOpSeparate(GL_BACK, backfail, backzfail, backzpass);CHECKGLERROR
1866                         qglStencilFuncSeparate(frontcompare, backcompare, comparereference, comparereference);CHECKGLERROR
1867                 }
1868                 else if (vid.support.ext_stencil_two_side)
1869                 {
1870                         qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1871                         qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR
1872                         qglStencilMask(writemask);CHECKGLERROR
1873                         qglStencilOp(frontfail, frontzfail, frontzpass);CHECKGLERROR
1874                         qglStencilFunc(frontcompare, comparereference, comparemask);CHECKGLERROR
1875                         qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR
1876                         qglStencilMask(writemask);CHECKGLERROR
1877                         qglStencilOp(backfail, backzfail, backzpass);CHECKGLERROR
1878                         qglStencilFunc(backcompare, comparereference, comparemask);CHECKGLERROR
1879                 }
1880                 break;
1881         case RENDERPATH_D3D9:
1882 #ifdef SUPPORTD3D
1883                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_TWOSIDEDSTENCILMODE, true);
1884                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILENABLE, enable);
1885                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILWRITEMASK, writemask);
1886                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFAIL, d3dstencilopforglfunc(frontfail));
1887                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILZFAIL, d3dstencilopforglfunc(frontzfail));
1888                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILPASS, d3dstencilopforglfunc(frontzpass));
1889                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFUNC, d3dcmpforglfunc(frontcompare));
1890                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILFAIL, d3dstencilopforglfunc(backfail));
1891                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILZFAIL, d3dstencilopforglfunc(backzfail));
1892                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILPASS, d3dstencilopforglfunc(backzpass));
1893                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILFUNC, d3dcmpforglfunc(backcompare));
1894                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILREF, comparereference);
1895                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILMASK, comparemask);
1896 #endif
1897                 break;
1898         case RENDERPATH_D3D10:
1899                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1900                 break;
1901         case RENDERPATH_D3D11:
1902                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1903                 break;
1904         case RENDERPATH_SOFT:
1905                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1906                 break;
1907         }
1908 }
1909
1910 void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass, int compare, int comparereference, int comparemask)
1911 {
1912         switch (vid.renderpath)
1913         {
1914         case RENDERPATH_GL11:
1915         case RENDERPATH_GL13:
1916         case RENDERPATH_GL20:
1917         case RENDERPATH_GLES1:
1918         case RENDERPATH_GLES2:
1919                 CHECKGLERROR
1920                 if (enable)
1921                 {
1922                         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1923                 }
1924                 else
1925                 {
1926                         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1927                 }
1928                 if (vid.support.ext_stencil_two_side)
1929                 {
1930                         qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1931                 }
1932                 qglStencilMask(writemask);CHECKGLERROR
1933                 qglStencilOp(fail, zfail, zpass);CHECKGLERROR
1934                 qglStencilFunc(compare, comparereference, comparemask);CHECKGLERROR
1935                 CHECKGLERROR
1936                 break;
1937         case RENDERPATH_D3D9:
1938 #ifdef SUPPORTD3D
1939                 if (vid.support.ati_separate_stencil)
1940                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_TWOSIDEDSTENCILMODE, true);
1941                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILENABLE, enable);
1942                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILWRITEMASK, writemask);
1943                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFAIL, d3dstencilopforglfunc(fail));
1944                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILZFAIL, d3dstencilopforglfunc(zfail));
1945                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILPASS, d3dstencilopforglfunc(zpass));
1946                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFUNC, d3dcmpforglfunc(compare));
1947                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILREF, comparereference);
1948                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILMASK, comparemask);
1949 #endif
1950                 break;
1951         case RENDERPATH_D3D10:
1952                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1953                 break;
1954         case RENDERPATH_D3D11:
1955                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1956                 break;
1957         case RENDERPATH_SOFT:
1958                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1959                 break;
1960         }
1961 }
1962
1963 void GL_PolygonOffset(float planeoffset, float depthoffset)
1964 {
1965         if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset)
1966         {
1967                 gl_state.polygonoffset[0] = planeoffset;
1968                 gl_state.polygonoffset[1] = depthoffset;
1969                 switch(vid.renderpath)
1970                 {
1971                 case RENDERPATH_GL11:
1972                 case RENDERPATH_GL13:
1973                 case RENDERPATH_GL20:
1974                 case RENDERPATH_GLES1:
1975                 case RENDERPATH_GLES2:
1976                         qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1977                         break;
1978                 case RENDERPATH_D3D9:
1979 #ifdef SUPPORTD3D
1980                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SLOPESCALEDEPTHBIAS, gl_state.polygonoffset[0]);
1981                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DEPTHBIAS, gl_state.polygonoffset[1] * (1.0f / 16777216.0f));
1982 #endif
1983                         break;
1984                 case RENDERPATH_D3D10:
1985                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1986                         break;
1987                 case RENDERPATH_D3D11:
1988                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1989                         break;
1990                 case RENDERPATH_SOFT:
1991                         DPSOFTRAST_PolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1992                         break;
1993                 }
1994         }
1995 }
1996
1997 void GL_SetMirrorState(qboolean state)
1998 {
1999         if (v_flipped_state != state)
2000         {
2001                 v_flipped_state = state;
2002                 if (gl_state.cullface == GL_BACK)
2003                         gl_state.cullface = GL_FRONT;
2004                 else if (gl_state.cullface == GL_FRONT)
2005                         gl_state.cullface = GL_BACK;
2006                 else
2007                         return;
2008                 switch(vid.renderpath)
2009                 {
2010                 case RENDERPATH_GL11:
2011                 case RENDERPATH_GL13:
2012                 case RENDERPATH_GL20:
2013                 case RENDERPATH_GLES1:
2014                 case RENDERPATH_GLES2:
2015                         qglCullFace(gl_state.cullface);CHECKGLERROR
2016                         break;
2017                 case RENDERPATH_D3D9:
2018 #ifdef SUPPORTD3D
2019                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, gl_state.cullface == GL_FRONT ? D3DCULL_CCW : D3DCULL_CW);
2020 #endif
2021                         break;
2022                 case RENDERPATH_D3D10:
2023                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2024                         break;
2025                 case RENDERPATH_D3D11:
2026                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2027                         break;
2028                 case RENDERPATH_SOFT:
2029                         DPSOFTRAST_CullFace(gl_state.cullface);
2030                         break;
2031                 }
2032         }
2033 }
2034
2035 void GL_CullFace(int state)
2036 {
2037         if(v_flipped_state)
2038         {
2039                 if(state == GL_FRONT)
2040                         state = GL_BACK;
2041                 else if(state == GL_BACK)
2042                         state = GL_FRONT;
2043         }
2044
2045         switch(vid.renderpath)
2046         {
2047         case RENDERPATH_GL11:
2048         case RENDERPATH_GL13:
2049         case RENDERPATH_GL20:
2050         case RENDERPATH_GLES1:
2051         case RENDERPATH_GLES2:
2052                 CHECKGLERROR
2053
2054                 if (state != GL_NONE)
2055                 {
2056                         if (!gl_state.cullfaceenable)
2057                         {
2058                                 gl_state.cullfaceenable = true;
2059                                 qglEnable(GL_CULL_FACE);CHECKGLERROR
2060                         }
2061                         if (gl_state.cullface != state)
2062                         {
2063                                 gl_state.cullface = state;
2064                                 qglCullFace(gl_state.cullface);CHECKGLERROR
2065                         }
2066                 }
2067                 else
2068                 {
2069                         if (gl_state.cullfaceenable)
2070                         {
2071                                 gl_state.cullfaceenable = false;
2072                                 qglDisable(GL_CULL_FACE);CHECKGLERROR
2073                         }
2074                 }
2075                 break;
2076         case RENDERPATH_D3D9:
2077 #ifdef SUPPORTD3D
2078                 if (gl_state.cullface != state)
2079                 {
2080                         gl_state.cullface = state;
2081                         switch(gl_state.cullface)
2082                         {
2083                         case GL_NONE:
2084                                 gl_state.cullfaceenable = false;
2085                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_NONE);
2086                                 break;
2087                         case GL_FRONT:
2088                                 gl_state.cullfaceenable = true;
2089                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_CCW);
2090                                 break;
2091                         case GL_BACK:
2092                                 gl_state.cullfaceenable = true;
2093                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_CW);
2094                                 break;
2095                         }
2096                 }
2097 #endif
2098                 break;
2099         case RENDERPATH_D3D10:
2100                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2101                 break;
2102         case RENDERPATH_D3D11:
2103                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2104                 break;
2105         case RENDERPATH_SOFT:
2106                 if (gl_state.cullface != state)
2107                 {
2108                         gl_state.cullface = state;
2109                         gl_state.cullfaceenable = state != GL_NONE ? true : false;
2110                         DPSOFTRAST_CullFace(gl_state.cullface);
2111                 }
2112                 break;
2113         }
2114 }
2115
2116 void GL_MultiSampling(qboolean state)
2117 {
2118         switch(vid.renderpath)
2119         {
2120                 case RENDERPATH_GL11:
2121                 case RENDERPATH_GL13:
2122                 case RENDERPATH_GLES1:
2123                 case RENDERPATH_GL20:
2124                 case RENDERPATH_GLES2:
2125                         if (vid.support.arb_multisample && vid.mode.samples > 1)
2126                         {
2127                                 if (state)
2128                                         qglEnable(GL_MULTISAMPLE_ARB);
2129                                 else
2130                                         qglDisable(GL_MULTISAMPLE_ARB);
2131                                 CHECKGLERROR
2132                         }
2133                         break;
2134                 case RENDERPATH_D3D9:
2135                         break;
2136                 case RENDERPATH_D3D10:
2137                         break;
2138                 case RENDERPATH_D3D11:
2139                         break;
2140                 case RENDERPATH_SOFT:
2141                         break;
2142         }
2143 }
2144
2145 void GL_AlphaTest(int state)
2146 {
2147         if (gl_state.alphatest != state)
2148         {
2149                 gl_state.alphatest = state;
2150                 switch(vid.renderpath)
2151                 {
2152                 case RENDERPATH_GL11:
2153                 case RENDERPATH_GL13:
2154                 case RENDERPATH_GLES1:
2155                         // only fixed function uses alpha test, other paths use pixel kill capability in shaders
2156                         CHECKGLERROR
2157                         if (gl_state.alphatest)
2158                         {
2159                                 qglEnable(GL_ALPHA_TEST);CHECKGLERROR
2160                         }
2161                         else
2162                         {
2163                                 qglDisable(GL_ALPHA_TEST);CHECKGLERROR
2164                         }
2165                         break;
2166                 case RENDERPATH_D3D9:
2167                 case RENDERPATH_D3D10:
2168                 case RENDERPATH_D3D11:
2169                 case RENDERPATH_SOFT:
2170                 case RENDERPATH_GL20:
2171                 case RENDERPATH_GLES2:
2172                         break;
2173                 }
2174         }
2175 }
2176
2177 void GL_AlphaToCoverage(qboolean state)
2178 {
2179         if (gl_state.alphatocoverage != state)
2180         {
2181                 gl_state.alphatocoverage = state;
2182                 switch(vid.renderpath)
2183                 {
2184                 case RENDERPATH_GL11:
2185                 case RENDERPATH_GL13:
2186                 case RENDERPATH_GLES1:
2187                 case RENDERPATH_GLES2:
2188                 case RENDERPATH_D3D9:
2189                 case RENDERPATH_D3D10:
2190                 case RENDERPATH_D3D11:
2191                 case RENDERPATH_SOFT:
2192                         break;
2193                 case RENDERPATH_GL20:
2194                         // alpha to coverage turns the alpha value of the pixel into 0%, 25%, 50%, 75% or 100% by masking the multisample fragments accordingly
2195                         if (vid.support.arb_multisample && vid.mode.samples > 1)
2196                         {
2197                                 CHECKGLERROR
2198                                 if (gl_state.alphatocoverage)
2199                                 {
2200                                         qglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR
2201                                         qglEnable(GL_MULTISAMPLE_ARB);CHECKGLERROR
2202                                 }
2203                                 else
2204                                 {
2205                                         qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR
2206                                         qglDisable(GL_MULTISAMPLE_ARB);CHECKGLERROR
2207                                 }
2208                         }
2209                         break;
2210                 }
2211         }
2212 }
2213
2214 void GL_ColorMask(int r, int g, int b, int a)
2215 {
2216         // NOTE: this matches D3DCOLORWRITEENABLE_RED, GREEN, BLUE, ALPHA
2217         int state = (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0) | (a ? 8 : 0);
2218         if (gl_state.colormask != state)
2219         {
2220                 gl_state.colormask = state;
2221                 switch(vid.renderpath)
2222                 {
2223                 case RENDERPATH_GL11:
2224                 case RENDERPATH_GL13:
2225                 case RENDERPATH_GL20:
2226                 case RENDERPATH_GLES1:
2227                 case RENDERPATH_GLES2:
2228                         CHECKGLERROR
2229                         qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
2230                         break;
2231                 case RENDERPATH_D3D9:
2232 #ifdef SUPPORTD3D
2233                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, state);
2234 #endif
2235                         break;
2236                 case RENDERPATH_D3D10:
2237                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2238                         break;
2239                 case RENDERPATH_D3D11:
2240                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2241                         break;
2242                 case RENDERPATH_SOFT:
2243                         DPSOFTRAST_ColorMask(r, g, b, a);
2244                         break;
2245                 }
2246         }
2247 }
2248
2249 void GL_Color(float cr, float cg, float cb, float ca)
2250 {
2251         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)
2252         {
2253                 gl_state.color4f[0] = cr;
2254                 gl_state.color4f[1] = cg;
2255                 gl_state.color4f[2] = cb;
2256                 gl_state.color4f[3] = ca;
2257                 switch(vid.renderpath)
2258                 {
2259                 case RENDERPATH_GL11:
2260                 case RENDERPATH_GL13:
2261                 case RENDERPATH_GLES1:
2262                         CHECKGLERROR
2263                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
2264                         CHECKGLERROR
2265                         break;
2266                 case RENDERPATH_D3D9:
2267                 case RENDERPATH_D3D10:
2268                 case RENDERPATH_D3D11:
2269                         // no equivalent in D3D
2270                         break;
2271                 case RENDERPATH_SOFT:
2272                         DPSOFTRAST_Color4f(cr, cg, cb, ca);
2273                         break;
2274                 case RENDERPATH_GL20:
2275                 case RENDERPATH_GLES2:
2276                         qglVertexAttrib4f(GLSLATTRIB_COLOR, cr, cg, cb, ca);
2277                         break;
2278                 }
2279         }
2280 }
2281
2282 void GL_Scissor (int x, int y, int width, int height)
2283 {
2284         switch(vid.renderpath)
2285         {
2286         case RENDERPATH_GL11:
2287         case RENDERPATH_GL13:
2288         case RENDERPATH_GL20:
2289         case RENDERPATH_GLES1:
2290         case RENDERPATH_GLES2:
2291                 CHECKGLERROR
2292                 qglScissor(x, y,width,height);
2293                 CHECKGLERROR
2294                 break;
2295         case RENDERPATH_D3D9:
2296 #ifdef SUPPORTD3D
2297                 {
2298                         RECT d3drect;
2299                         d3drect.left = x;
2300                         d3drect.top = y;
2301                         d3drect.right = x + width;
2302                         d3drect.bottom = y + height;
2303                         IDirect3DDevice9_SetScissorRect(vid_d3d9dev, &d3drect);
2304                 }
2305 #endif
2306                 break;
2307         case RENDERPATH_D3D10:
2308                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2309                 break;
2310         case RENDERPATH_D3D11:
2311                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2312                 break;
2313         case RENDERPATH_SOFT:
2314                 DPSOFTRAST_Scissor(x, y, width, height);
2315                 break;
2316         }
2317 }
2318
2319 void GL_ScissorTest(int state)
2320 {
2321         if (gl_state.scissortest != state)
2322         {
2323                 gl_state.scissortest = state;
2324                 switch(vid.renderpath)
2325                 {
2326                 case RENDERPATH_GL11:
2327                 case RENDERPATH_GL13:
2328                 case RENDERPATH_GL20:
2329                 case RENDERPATH_GLES1:
2330                 case RENDERPATH_GLES2:
2331                         CHECKGLERROR
2332                         if(gl_state.scissortest)
2333                                 qglEnable(GL_SCISSOR_TEST);
2334                         else
2335                                 qglDisable(GL_SCISSOR_TEST);
2336                         CHECKGLERROR
2337                         break;
2338                 case RENDERPATH_D3D9:
2339 #ifdef SUPPORTD3D
2340                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SCISSORTESTENABLE, gl_state.scissortest);
2341 #endif
2342                         break;
2343                 case RENDERPATH_D3D10:
2344                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2345                         break;
2346                 case RENDERPATH_D3D11:
2347                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2348                         break;
2349                 case RENDERPATH_SOFT:
2350                         DPSOFTRAST_ScissorTest(gl_state.scissortest);
2351                         break;
2352                 }
2353         }
2354 }
2355
2356 void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilvalue)
2357 {
2358         static const float blackcolor[4] = {0, 0, 0, 0};
2359         // prevent warnings when trying to clear a buffer that does not exist
2360         if (!colorvalue)
2361                 colorvalue = blackcolor;
2362         if (!vid.stencil)
2363         {
2364                 mask &= ~GL_STENCIL_BUFFER_BIT;
2365                 stencilvalue = 0;
2366         }
2367         switch(vid.renderpath)
2368         {
2369         case RENDERPATH_GL11:
2370         case RENDERPATH_GL13:
2371         case RENDERPATH_GL20:
2372         case RENDERPATH_GLES1:
2373         case RENDERPATH_GLES2:
2374                 CHECKGLERROR
2375                 if (mask & GL_COLOR_BUFFER_BIT)
2376                 {
2377                         qglClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);CHECKGLERROR
2378                 }
2379                 if (mask & GL_DEPTH_BUFFER_BIT)
2380                 {
2381                         qglClearDepth(depthvalue);CHECKGLERROR
2382                 }
2383                 if (mask & GL_STENCIL_BUFFER_BIT)
2384                 {
2385                         qglClearStencil(stencilvalue);CHECKGLERROR
2386                 }
2387                 qglClear(mask);CHECKGLERROR
2388                 break;
2389         case RENDERPATH_D3D9:
2390 #ifdef SUPPORTD3D
2391                 IDirect3DDevice9_Clear(vid_d3d9dev, 0, NULL, ((mask & GL_COLOR_BUFFER_BIT) ? D3DCLEAR_TARGET : 0) | ((mask & GL_STENCIL_BUFFER_BIT) ? D3DCLEAR_STENCIL : 0) | ((mask & GL_DEPTH_BUFFER_BIT) ? D3DCLEAR_ZBUFFER : 0), D3DCOLOR_COLORVALUE(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]), depthvalue, stencilvalue);
2392 #endif
2393                 break;
2394         case RENDERPATH_D3D10:
2395                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2396                 break;
2397         case RENDERPATH_D3D11:
2398                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2399                 break;
2400         case RENDERPATH_SOFT:
2401                 if (mask & GL_COLOR_BUFFER_BIT)
2402                         DPSOFTRAST_ClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);
2403                 if (mask & GL_DEPTH_BUFFER_BIT)
2404                         DPSOFTRAST_ClearDepth(depthvalue);
2405                 break;
2406         }
2407 }
2408
2409 void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels)
2410 {
2411         switch(vid.renderpath)
2412         {
2413         case RENDERPATH_GL11:
2414         case RENDERPATH_GL13:
2415         case RENDERPATH_GL20:
2416         case RENDERPATH_GLES1:
2417         case RENDERPATH_GLES2:
2418                 CHECKGLERROR
2419                 qglReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, outpixels);CHECKGLERROR
2420                 break;
2421         case RENDERPATH_D3D9:
2422 #ifdef SUPPORTD3D
2423                 {
2424                         // LordHavoc: we can't directly download the backbuffer because it may be
2425                         // multisampled, and it may not be lockable, so we blit it to a lockable
2426                         // surface of the same dimensions (but without multisample) to resolve the
2427                         // multisample buffer to a normal image, and then lock that...
2428                         IDirect3DSurface9 *stretchsurface = NULL;
2429                         if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &stretchsurface, NULL)))
2430                         {
2431                                 D3DLOCKED_RECT lockedrect;
2432                                 if (!FAILED(IDirect3DDevice9_StretchRect(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, NULL, stretchsurface, NULL, D3DTEXF_POINT)))
2433                                 {
2434                                         if (!FAILED(IDirect3DSurface9_LockRect(stretchsurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2435                                         {
2436                                                 int line;
2437                                                 unsigned char *row = (unsigned char *)lockedrect.pBits + x * 4 + lockedrect.Pitch * (vid.height - 1 - y);
2438                                                 for (line = 0;line < height;line++, row -= lockedrect.Pitch)
2439                                                         memcpy(outpixels + line * width * 4, row, width * 4);
2440                                                 IDirect3DSurface9_UnlockRect(stretchsurface);
2441                                         }
2442                                 }
2443                                 IDirect3DSurface9_Release(stretchsurface);
2444                         }
2445                         // code scraps
2446                         //IDirect3DSurface9 *syssurface = NULL;
2447                         //if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &stretchsurface, NULL)))
2448                         //if (!FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &syssurface, NULL)))
2449                         //IDirect3DDevice9_GetRenderTargetData(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, syssurface);
2450                         //if (!FAILED(IDirect3DDevice9_GetFrontBufferData(vid_d3d9dev, 0, syssurface)))
2451                         //if (!FAILED(IDirect3DSurface9_LockRect(syssurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2452                         //IDirect3DSurface9_UnlockRect(syssurface);
2453                         //IDirect3DSurface9_Release(syssurface);
2454                 }
2455 #endif
2456                 break;
2457         case RENDERPATH_D3D10:
2458                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2459                 break;
2460         case RENDERPATH_D3D11:
2461                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2462                 break;
2463         case RENDERPATH_SOFT:
2464                 DPSOFTRAST_GetPixelsBGRA(x, y, width, height, outpixels);
2465                 break;
2466         }
2467 }
2468
2469 // called at beginning of frame
2470 void R_Mesh_Start(void)
2471 {
2472         BACKENDACTIVECHECK
2473         R_Mesh_ResetRenderTargets();
2474         R_Mesh_SetUseVBO();
2475         if (gl_printcheckerror.integer && !gl_paranoid.integer)
2476         {
2477                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
2478                 Cvar_SetValueQuick(&gl_paranoid, 1);
2479         }
2480 }
2481
2482 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
2483 {
2484         int shaderobject;
2485         int shadercompiled;
2486         char compilelog[MAX_INPUTLINE];
2487         shaderobject = qglCreateShader(shadertypeenum);CHECKGLERROR
2488         if (!shaderobject)
2489                 return false;
2490         qglShaderSource(shaderobject, numstrings, strings, NULL);CHECKGLERROR
2491         qglCompileShader(shaderobject);CHECKGLERROR
2492         qglGetShaderiv(shaderobject, GL_COMPILE_STATUS, &shadercompiled);CHECKGLERROR
2493         qglGetShaderInfoLog(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
2494         if (compilelog[0] && (strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error") || strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")))
2495         {
2496                 int i, j, pretextlines = 0;
2497                 for (i = 0;i < numstrings - 1;i++)
2498                         for (j = 0;strings[i][j];j++)
2499                                 if (strings[i][j] == '\n')
2500                                         pretextlines++;
2501                 Con_Printf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
2502         }
2503         if (!shadercompiled)
2504         {
2505                 qglDeleteShader(shaderobject);CHECKGLERROR
2506                 return false;
2507         }
2508         qglAttachShader(programobject, shaderobject);CHECKGLERROR
2509         qglDeleteShader(shaderobject);CHECKGLERROR
2510         return true;
2511 }
2512
2513 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)
2514 {
2515         GLint programlinked;
2516         GLuint programobject = 0;
2517         char linklog[MAX_INPUTLINE];
2518         CHECKGLERROR
2519
2520         programobject = qglCreateProgram();CHECKGLERROR
2521         if (!programobject)
2522                 return 0;
2523
2524         qglBindAttribLocation(programobject, GLSLATTRIB_POSITION , "Attrib_Position" );
2525         qglBindAttribLocation(programobject, GLSLATTRIB_COLOR    , "Attrib_Color"    );
2526         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD0, "Attrib_TexCoord0");
2527         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD1, "Attrib_TexCoord1");
2528         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD2, "Attrib_TexCoord2");
2529         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD3, "Attrib_TexCoord3");
2530         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD4, "Attrib_TexCoord4");
2531         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD5, "Attrib_TexCoord5");
2532         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD6, "Attrib_TexCoord6");
2533         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD7, "Attrib_TexCoord7");
2534         if(vid.support.gl20shaders130)
2535                 qglBindFragDataLocation(programobject, 0, "dp_FragColor");
2536
2537         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER, "vertex", vertexstrings_count, vertexstrings_list))
2538                 goto cleanup;
2539
2540 #ifdef GL_GEOMETRY_SHADER
2541         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER, "geometry", geometrystrings_count, geometrystrings_list))
2542                 goto cleanup;
2543 #endif
2544
2545         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER, "fragment", fragmentstrings_count, fragmentstrings_list))
2546                 goto cleanup;
2547
2548         qglLinkProgram(programobject);CHECKGLERROR
2549         qglGetProgramiv(programobject, GL_LINK_STATUS, &programlinked);CHECKGLERROR
2550         qglGetProgramInfoLog(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
2551         if (linklog[0])
2552         {
2553                 if (strstr(linklog, "error") || strstr(linklog, "ERROR") || strstr(linklog, "Error") || strstr(linklog, "WARNING") || strstr(linklog, "warning") || strstr(linklog, "Warning"))
2554                         Con_DPrintf("program link log:\n%s\n", linklog);
2555                 // software vertex shader is ok but software fragment shader is WAY
2556                 // too slow, fail program if so.
2557                 // NOTE: this string might be ATI specific, but that's ok because the
2558                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
2559                 // software fragment shader due to low instruction and dependent
2560                 // texture limits.
2561                 if (strstr(linklog, "fragment shader will run in software"))
2562                         programlinked = false;
2563         }
2564         if (!programlinked)
2565                 goto cleanup;
2566         return programobject;
2567 cleanup:
2568         qglDeleteProgram(programobject);CHECKGLERROR
2569         return 0;
2570 }
2571
2572 void GL_Backend_FreeProgram(unsigned int prog)
2573 {
2574         CHECKGLERROR
2575         qglDeleteProgram(prog);
2576         CHECKGLERROR
2577 }
2578
2579 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
2580 {
2581         int i;
2582         if (offset)
2583         {
2584                 for (i = 0;i < count;i++)
2585                         *out++ = *in++ + offset;
2586         }
2587         else
2588                 memcpy(out, in, sizeof(*out) * count);
2589 }
2590
2591 // renders triangles using vertices from the active arrays
2592 int paranoidblah = 0;
2593 void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, size_t element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, size_t element3s_bufferoffset)
2594 {
2595         unsigned int numelements = numtriangles * 3;
2596         int bufferobject3i;
2597         size_t bufferoffset3i;
2598         int bufferobject3s;
2599         size_t bufferoffset3s;
2600         if (numvertices < 3 || numtriangles < 1)
2601         {
2602                 if (numvertices < 0 || numtriangles < 0 || developer_extra.integer)
2603                         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);
2604                 return;
2605         }
2606         if (!gl_mesh_prefer_short_elements.integer)
2607         {
2608                 if (element3i)
2609                         element3s = NULL;
2610                 if (element3i_indexbuffer)
2611                         element3i_indexbuffer = NULL;
2612         }
2613         // adjust the pointers for firsttriangle
2614         if (element3i)
2615                 element3i += firsttriangle * 3;
2616         if (element3i_indexbuffer)
2617                 element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i);
2618         if (element3s)
2619                 element3s += firsttriangle * 3;
2620         if (element3s_indexbuffer)
2621                 element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
2622         switch(vid.renderpath)
2623         {
2624         case RENDERPATH_GL11:
2625         case RENDERPATH_GL13:
2626         case RENDERPATH_GL20:
2627         case RENDERPATH_GLES1:
2628         case RENDERPATH_GLES2:
2629                 // check if the user specified to ignore static index buffers
2630                 if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset)))
2631                 {
2632                         element3i_indexbuffer = NULL;
2633                         element3s_indexbuffer = NULL;
2634                 }
2635                 break;
2636         case RENDERPATH_D3D9:
2637         case RENDERPATH_D3D10:
2638         case RENDERPATH_D3D11:
2639                 break;
2640         case RENDERPATH_SOFT:
2641                 break;
2642         }
2643         // upload a dynamic index buffer if needed
2644         if (element3s)
2645         {
2646                 if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex)
2647                 {
2648                         if (gl_state.draw_dynamicindexbuffer)
2649                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3s, numelements * sizeof(*element3s));
2650                         else
2651                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3s, numelements * sizeof(*element3s), "temporary", true, true, true);
2652                         element3s_indexbuffer = gl_state.draw_dynamicindexbuffer;
2653                         element3s_bufferoffset = 0;
2654                 }
2655         }
2656         else if (element3i)
2657         {
2658                 if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex)
2659                 {
2660                         if (gl_state.draw_dynamicindexbuffer)
2661                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3i, numelements * sizeof(*element3i));
2662                         else
2663                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3i, numelements * sizeof(*element3i), "temporary", true, true, false);
2664                         element3i_indexbuffer = gl_state.draw_dynamicindexbuffer;
2665                         element3i_bufferoffset = 0;
2666                 }
2667         }
2668         bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
2669         bufferoffset3i = element3i_bufferoffset;
2670         bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0;
2671         bufferoffset3s = element3s_bufferoffset;
2672         r_refdef.stats.draws++;
2673         r_refdef.stats.draws_vertices += numvertices;
2674         r_refdef.stats.draws_elements += numelements;
2675         if (gl_paranoid.integer)
2676         {
2677                 unsigned int i;
2678                 // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
2679 #if 0
2680                 unsigned int j, size;
2681                 const int *p;
2682                 // note: there's no validation done here on buffer objects because it
2683                 // is somewhat difficult to get at the data, and gl_paranoid can be
2684                 // used without buffer objects if the need arises
2685                 // (the data could be gotten using glMapBuffer but it would be very
2686                 //  slow due to uncachable video memory reads)
2687                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
2688                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
2689                 CHECKGLERROR
2690                 if (gl_state.pointer_vertex_pointer)
2691                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
2692                                 paranoidblah += *p;
2693                 if (gl_state.pointer_color_enabled)
2694                 {
2695                         if (!qglIsEnabled(GL_COLOR_ARRAY))
2696                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
2697                         CHECKGLERROR
2698                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
2699                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
2700                                         paranoidblah += *p;
2701                 }
2702                 for (i = 0;i < vid.texarrayunits;i++)
2703                 {
2704                         if (gl_state.units[i].arrayenabled)
2705                         {
2706                                 GL_ClientActiveTexture(i);
2707                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
2708                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
2709                                 CHECKGLERROR
2710                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
2711                                         for (j = 0, size = numvertices * gl_state.units[i].arraycomponents, p = (int *)((float *)gl_state.units[i].pointer_texcoord + firstvertex * gl_state.units[i].arraycomponents);j < size;j++, p++)
2712                                                 paranoidblah += *p;
2713                         }
2714                 }
2715 #endif
2716                 if (element3i)
2717                 {
2718                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2719                         {
2720                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
2721                                 {
2722                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
2723                                         return;
2724                                 }
2725                         }
2726                 }
2727                 if (element3s)
2728                 {
2729                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2730                         {
2731                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
2732                                 {
2733                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
2734                                         return;
2735                                 }
2736                         }
2737                 }
2738         }
2739         if (r_render.integer || r_refdef.draw2dstage)
2740         {
2741                 switch(vid.renderpath)
2742                 {
2743                 case RENDERPATH_GL11:
2744                 case RENDERPATH_GL13:
2745                 case RENDERPATH_GL20:
2746                         CHECKGLERROR
2747                         if (gl_mesh_testmanualfeeding.integer)
2748                         {
2749                                 unsigned int i, j, element;
2750                                 const GLfloat *p;
2751                                 qglBegin(GL_TRIANGLES);
2752                                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2753                                 {
2754                                         if (element3i)
2755                                                 element = element3i[i];
2756                                         else if (element3s)
2757                                                 element = element3s[i];
2758                                         else
2759                                                 element = firstvertex + i;
2760                                         for (j = 0;j < vid.texarrayunits;j++)
2761                                         {
2762                                                 if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
2763                                                 {
2764                                                         if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
2765                                                         {
2766                                                                 p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2767                                                                 if (vid.texarrayunits > 1)
2768                                                                 {
2769                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2770                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
2771                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2772                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
2773                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2774                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
2775                                                                         else
2776                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
2777                                                                 }
2778                                                                 else
2779                                                                 {
2780                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2781                                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
2782                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2783                                                                                 qglTexCoord3f(p[0], p[1], p[2]);
2784                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2785                                                                                 qglTexCoord2f(p[0], p[1]);
2786                                                                         else
2787                                                                                 qglTexCoord1f(p[0]);
2788                                                                 }
2789                                                         }
2790                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
2791                                                         {
2792                                                                 const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2793                                                                 if (vid.texarrayunits > 1)
2794                                                                 {
2795                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2796                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
2797                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2798                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]);
2799                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2800                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
2801                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2802                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
2803                                                                 }
2804                                                                 else
2805                                                                 {
2806                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2807                                                                                 qglTexCoord4f(s[0], s[1], s[2], s[3]);
2808                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2809                                                                                 qglTexCoord3f(s[0], s[1], s[2]);
2810                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2811                                                                                 qglTexCoord2f(s[0], s[1]);
2812                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2813                                                                                 qglTexCoord1f(s[0]);
2814                                                                 }
2815                                                         }
2816                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
2817                                                         {
2818                                                                 const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2819                                                                 if (vid.texarrayunits > 1)
2820                                                                 {
2821                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2822                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
2823                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2824                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]);
2825                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2826                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
2827                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2828                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
2829                                                                 }
2830                                                                 else
2831                                                                 {
2832                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2833                                                                                 qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
2834                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2835                                                                                 qglTexCoord3f(sb[0], sb[1], sb[2]);
2836                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2837                                                                                 qglTexCoord2f(sb[0], sb[1]);
2838                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2839                                                                                 qglTexCoord1f(sb[0]);
2840                                                                 }
2841                                                         }
2842                                                 }
2843                                         }
2844                                         if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
2845                                         {
2846                                                 if (gl_state.pointer_color_gltype == GL_FLOAT)
2847                                                 {
2848                                                         p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2849                                                         qglColor4f(p[0], p[1], p[2], p[3]);
2850                                                 }
2851                                                 else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
2852                                                 {
2853                                                         const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2854                                                         qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
2855                                                 }
2856                                         }
2857                                         if (gl_state.pointer_vertex_gltype == GL_FLOAT)
2858                                         {
2859                                                 p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
2860                                                 if (gl_state.pointer_vertex_components == 4)
2861                                                         qglVertex4f(p[0], p[1], p[2], p[3]);
2862                                                 else if (gl_state.pointer_vertex_components == 3)
2863                                                         qglVertex3f(p[0], p[1], p[2]);
2864                                                 else
2865                                                         qglVertex2f(p[0], p[1]);
2866                                         }
2867                                 }
2868                                 qglEnd();
2869                                 CHECKGLERROR
2870                         }
2871                         else if (bufferobject3s)
2872                         {
2873                                 GL_BindEBO(bufferobject3s);
2874                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2875                                 {
2876                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
2877                                         CHECKGLERROR
2878                                 }
2879                                 else
2880                                 {
2881                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
2882                                         CHECKGLERROR
2883                                 }
2884                         }
2885                         else if (bufferobject3i)
2886                         {
2887                                 GL_BindEBO(bufferobject3i);
2888                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2889                                 {
2890                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
2891                                         CHECKGLERROR
2892                                 }
2893                                 else
2894                                 {
2895                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
2896                                         CHECKGLERROR
2897                                 }
2898                         }
2899                         else if (element3s)
2900                         {
2901                                 GL_BindEBO(0);
2902                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2903                                 {
2904                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
2905                                         CHECKGLERROR
2906                                 }
2907                                 else
2908                                 {
2909                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
2910                                         CHECKGLERROR
2911                                 }
2912                         }
2913                         else if (element3i)
2914                         {
2915                                 GL_BindEBO(0);
2916                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2917                                 {
2918                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
2919                                         CHECKGLERROR
2920                                 }
2921                                 else
2922                                 {
2923                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
2924                                         CHECKGLERROR
2925                                 }
2926                         }
2927                         else
2928                         {
2929                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
2930                                 CHECKGLERROR
2931                         }
2932                         break;
2933                 case RENDERPATH_D3D9:
2934 #ifdef SUPPORTD3D
2935                         if (gl_state.d3dvertexbuffer && ((element3s && element3s_indexbuffer) || (element3i && element3i_indexbuffer)))
2936                         {
2937                                 if (element3s_indexbuffer)
2938                                 {
2939                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3s_indexbuffer->devicebuffer);
2940                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3s_bufferoffset>>1, numtriangles);
2941                                 }
2942                                 else if (element3i_indexbuffer)
2943                                 {
2944                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3i_indexbuffer->devicebuffer);
2945                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3i_bufferoffset>>2, numtriangles);
2946                                 }
2947                                 else
2948                                         IDirect3DDevice9_DrawPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices);
2949                         }
2950                         else
2951                         {
2952                                 if (element3s)
2953                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3s, D3DFMT_INDEX16, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2954                                 else if (element3i)
2955                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3i, D3DFMT_INDEX32, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2956                                 else
2957                                         IDirect3DDevice9_DrawPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, numvertices, (void *)gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2958                         }
2959 #endif
2960                         break;
2961                 case RENDERPATH_D3D10:
2962                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2963                         break;
2964                 case RENDERPATH_D3D11:
2965                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2966                         break;
2967                 case RENDERPATH_SOFT:
2968                         DPSOFTRAST_DrawTriangles(firstvertex, numvertices, numtriangles, element3i, element3s);
2969                         break;
2970                 case RENDERPATH_GLES1:
2971                 case RENDERPATH_GLES2:
2972                         // GLES does not have glDrawRangeElements, and generally
2973                         // underperforms with index buffers, so this code path is
2974                         // relatively straightforward...
2975 #if 0
2976                         if (gl_paranoid.integer)
2977                         {
2978                                 int r, prog, enabled, i;
2979                                 GLsizei         attriblength;
2980                                 GLint           attribsize;
2981                                 GLenum          attribtype;
2982                                 GLchar          attribname[1024];
2983                                 r = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2984                                 if (r != GL_FRAMEBUFFER_COMPLETE_EXT)
2985                                         Con_DPrintf("fbo %i not complete (default %i)\n", gl_state.framebufferobject, gl_state.defaultframebufferobject);
2986 #ifndef GL_CURRENT_PROGRAM
2987 #define GL_CURRENT_PROGRAM 0x8B8D
2988 #endif
2989                                 qglGetIntegerv(GL_CURRENT_PROGRAM, &r);CHECKGLERROR
2990                                 if (r < 0 || r > 10000)
2991                                         Con_DPrintf("GL_CURRENT_PROGRAM = %i\n", r);
2992                                 prog = r;
2993                                 for (i = 0;i < 8;i++)
2994                                 {
2995                                         qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &r);CHECKGLERROR
2996                                         if (!r)
2997                                                 continue;
2998                                         qglGetActiveAttrib(prog, i, sizeof(attribname), &attriblength, &attribsize, &attribtype, attribname);CHECKGLERROR
2999                                         Con_DPrintf("prog %i position %i length %i size %04X type %i name \"%s\"\n", prog, i, (int)attriblength, (int)attribsize, (int)attribtype, (char *)attribname);
3000                                 }
3001                         }
3002 #endif
3003                         if (element3s)
3004                         {
3005                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
3006                                 CHECKGLERROR
3007                         }
3008                         else if (element3i)
3009                         {
3010                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
3011                                 CHECKGLERROR
3012                         }
3013                         else
3014                         {
3015                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
3016                                 CHECKGLERROR
3017                         }
3018                         break;
3019                 }
3020         }
3021 }
3022
3023 // restores backend state, used when done with 3D rendering
3024 void R_Mesh_Finish(void)
3025 {
3026         R_Mesh_ResetRenderTargets();
3027 }
3028
3029 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic, qboolean isindex16)
3030 {
3031         r_meshbuffer_t *buffer;
3032         if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex)))
3033                 return NULL;
3034         buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
3035         memset(buffer, 0, sizeof(*buffer));
3036         buffer->bufferobject = 0;
3037         buffer->devicebuffer = NULL;
3038         buffer->size = 0;
3039         buffer->isindexbuffer = isindexbuffer;
3040         buffer->isdynamic = isdynamic;
3041         buffer->isindex16 = isindex16;
3042         strlcpy(buffer->name, name, sizeof(buffer->name));
3043         R_Mesh_UpdateMeshBuffer(buffer, data, size);
3044         return buffer;
3045 }
3046
3047 void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size)
3048 {
3049         if (!buffer)
3050                 return;
3051         if (buffer->isindexbuffer)
3052         {
3053                 r_refdef.stats.indexbufferuploadcount++;
3054                 r_refdef.stats.indexbufferuploadsize += size;
3055         }
3056         else
3057         {
3058                 r_refdef.stats.vertexbufferuploadcount++;
3059                 r_refdef.stats.vertexbufferuploadsize += size;
3060         }
3061         switch(vid.renderpath)
3062         {
3063         case RENDERPATH_GL11:
3064         case RENDERPATH_GL13:
3065         case RENDERPATH_GL20:
3066         case RENDERPATH_GLES1:
3067         case RENDERPATH_GLES2:
3068                 if (!buffer->bufferobject)
3069                         qglGenBuffersARB(1, (GLuint *)&buffer->bufferobject);
3070                 if (buffer->isindexbuffer)
3071                         GL_BindEBO(buffer->bufferobject);
3072                 else
3073                         GL_BindVBO(buffer->bufferobject);
3074                 qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
3075                 break;
3076         case RENDERPATH_D3D9:
3077 #ifdef SUPPORTD3D
3078                 {
3079                         int result;
3080                         void *datapointer = NULL;
3081                         if (buffer->isindexbuffer)
3082                         {
3083                                 IDirect3DIndexBuffer9 *d3d9indexbuffer = (IDirect3DIndexBuffer9 *)buffer->devicebuffer;
3084                                 if (size > buffer->size || !buffer->devicebuffer)
3085                                 {
3086                                         if (buffer->devicebuffer)
3087                                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer);
3088                                         buffer->devicebuffer = NULL;
3089                                         if (FAILED(result = IDirect3DDevice9_CreateIndexBuffer(vid_d3d9dev, size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, buffer->isindex16 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9indexbuffer, NULL)))
3090                                                 Sys_Error("IDirect3DDevice9_CreateIndexBuffer(%p, %d, %x, %x, %x, %p, NULL) returned %x\n", vid_d3d9dev, (int)size, buffer->isdynamic ? (int)D3DUSAGE_DYNAMIC : 0, buffer->isindex16 ? (int)D3DFMT_INDEX16 : (int)D3DFMT_INDEX32, buffer->isdynamic ? (int)D3DPOOL_DEFAULT : (int)D3DPOOL_MANAGED, &d3d9indexbuffer, (int)result);
3091                                         buffer->devicebuffer = (void *)d3d9indexbuffer;
3092                                         buffer->size = size;
3093                                 }
3094                                 if (!FAILED(IDirect3DIndexBuffer9_Lock(d3d9indexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
3095                                 {
3096                                         if (data)
3097                                                 memcpy(datapointer, data, size);
3098                                         else
3099                                                 memset(datapointer, 0, size);
3100                                         IDirect3DIndexBuffer9_Unlock(d3d9indexbuffer);
3101                                 }
3102                         }
3103                         else
3104                         {
3105                                 IDirect3DVertexBuffer9 *d3d9vertexbuffer = (IDirect3DVertexBuffer9 *)buffer->devicebuffer;
3106                                 if (size > buffer->size || !buffer->devicebuffer)
3107                                 {
3108                                         if (buffer->devicebuffer)
3109                                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer);
3110                                         buffer->devicebuffer = NULL;
3111                                         if (FAILED(result = IDirect3DDevice9_CreateVertexBuffer(vid_d3d9dev, size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9vertexbuffer, NULL)))
3112                                                 Sys_Error("IDirect3DDevice9_CreateVertexBuffer(%p, %d, %x, %x, %x, %p, NULL) returned %x\n", vid_d3d9dev, (int)size, buffer->isdynamic ? (int)D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? (int)D3DPOOL_DEFAULT : (int)D3DPOOL_MANAGED, &d3d9vertexbuffer, (int)result);
3113                                         buffer->devicebuffer = (void *)d3d9vertexbuffer;
3114                                         buffer->size = size;
3115                                 }
3116                                 if (!FAILED(IDirect3DVertexBuffer9_Lock(d3d9vertexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
3117                                 {
3118                                         if (data)
3119                                                 memcpy(datapointer, data, size);
3120                                         else
3121                                                 memset(datapointer, 0, size);
3122                                         IDirect3DVertexBuffer9_Unlock(d3d9vertexbuffer);
3123                                 }
3124                         }
3125                 }
3126 #endif
3127                 break;
3128         case RENDERPATH_D3D10:
3129                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3130                 break;
3131         case RENDERPATH_D3D11:
3132                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3133                 break;
3134         case RENDERPATH_SOFT:
3135                 break;
3136         }
3137 }
3138
3139 void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
3140 {
3141         if (!buffer)
3142                 return;
3143         switch(vid.renderpath)
3144         {
3145         case RENDERPATH_GL11:
3146         case RENDERPATH_GL13:
3147         case RENDERPATH_GL20:
3148         case RENDERPATH_GLES1:
3149         case RENDERPATH_GLES2:
3150                 qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject);
3151                 break;
3152         case RENDERPATH_D3D9:
3153 #ifdef SUPPORTD3D
3154                 if (gl_state.d3dvertexbuffer == (void *)buffer)
3155                         gl_state.d3dvertexbuffer = NULL;
3156                 if (buffer->devicebuffer)
3157                 {
3158                         if (buffer->isindexbuffer)
3159                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9 *)buffer->devicebuffer);
3160                         else
3161                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9 *)buffer->devicebuffer);
3162                         buffer->devicebuffer = NULL;
3163                 }
3164 #endif
3165                 break;
3166         case RENDERPATH_D3D10:
3167                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3168                 break;
3169         case RENDERPATH_D3D11:
3170                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3171                 break;
3172         case RENDERPATH_SOFT:
3173                 break;
3174         }
3175         Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
3176 }
3177
3178 void GL_Mesh_ListVBOs(qboolean printeach)
3179 {
3180         int i, endindex;
3181         size_t ebocount = 0, ebomemory = 0;
3182         size_t vbocount = 0, vbomemory = 0;
3183         r_meshbuffer_t *buffer;
3184         endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
3185         for (i = 0;i < endindex;i++)
3186         {
3187                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
3188                 if (!buffer)
3189                         continue;
3190                 if (buffer->isindexbuffer) {ebocount++;ebomemory += buffer->size;if (printeach) Con_Printf("indexbuffer #%i %s = %i bytes%s\n", i, buffer->name, (int)buffer->size, buffer->isdynamic ? " (dynamic)" : " (static)");}
3191                 else                       {vbocount++;vbomemory += buffer->size;if (printeach) Con_Printf("vertexbuffer #%i %s = %i bytes%s\n", i, buffer->name, (int)buffer->size, buffer->isdynamic ? " (dynamic)" : " (static)");}
3192         }
3193         Con_Printf("vertex buffers: %i indexbuffers totalling %i bytes (%.3f MB), %i vertexbuffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0);
3194 }
3195
3196
3197
3198 void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
3199 {
3200         switch(vid.renderpath)
3201         {
3202         case RENDERPATH_GL11:
3203         case RENDERPATH_GL13:
3204         case RENDERPATH_GLES1:
3205                 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)
3206                 {
3207                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3208                         gl_state.pointer_vertex_components = components;
3209                         gl_state.pointer_vertex_gltype = gltype;
3210                         gl_state.pointer_vertex_stride = stride;
3211                         gl_state.pointer_vertex_pointer = pointer;
3212                         gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
3213                         gl_state.pointer_vertex_offset = bufferoffset;
3214                         CHECKGLERROR
3215                         GL_BindVBO(bufferobject);
3216                         qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3217                 }
3218                 break;
3219         case RENDERPATH_GL20:
3220         case RENDERPATH_GLES2:
3221                 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)
3222                 {
3223                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3224                         gl_state.pointer_vertex_components = components;
3225                         gl_state.pointer_vertex_gltype = gltype;
3226                         gl_state.pointer_vertex_stride = stride;
3227                         gl_state.pointer_vertex_pointer = pointer;
3228                         gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
3229                         gl_state.pointer_vertex_offset = bufferoffset;
3230                         CHECKGLERROR
3231                         GL_BindVBO(bufferobject);
3232                         qglVertexAttribPointer(GLSLATTRIB_POSITION, components, gltype, false, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3233                 }
3234                 break;
3235         case RENDERPATH_D3D9:
3236         case RENDERPATH_D3D10:
3237         case RENDERPATH_D3D11:
3238         case RENDERPATH_SOFT:
3239                 break;
3240         }
3241 }
3242
3243 void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
3244 {
3245         // note: vertexbuffer may be non-NULL even if pointer is NULL, so check
3246         // the pointer only.
3247         switch(vid.renderpath)
3248         {
3249         case RENDERPATH_GL11:
3250         case RENDERPATH_GL13:
3251         case RENDERPATH_GLES1:
3252                 CHECKGLERROR
3253                 if (pointer)
3254                 {
3255                         // caller wants color array enabled
3256                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3257                         if (!gl_state.pointer_color_enabled)
3258                         {
3259                                 gl_state.pointer_color_enabled = true;
3260                                 CHECKGLERROR
3261                                 qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
3262                         }
3263                         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)
3264                         {
3265                                 gl_state.pointer_color_components = components;
3266                                 gl_state.pointer_color_gltype = gltype;
3267                                 gl_state.pointer_color_stride = stride;
3268                                 gl_state.pointer_color_pointer = pointer;
3269                                 gl_state.pointer_color_vertexbuffer = vertexbuffer;
3270                                 gl_state.pointer_color_offset = bufferoffset;
3271                                 CHECKGLERROR
3272                                 GL_BindVBO(bufferobject);
3273                                 qglColorPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3274                         }
3275                 }
3276                 else
3277                 {
3278                         // caller wants color array disabled
3279                         if (gl_state.pointer_color_enabled)
3280                         {
3281                                 gl_state.pointer_color_enabled = false;
3282                                 CHECKGLERROR
3283                                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
3284                                 // when color array is on the glColor gets trashed, set it again
3285                                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
3286                         }
3287                 }
3288                 break;
3289         case RENDERPATH_GL20:
3290         case RENDERPATH_GLES2:
3291                 CHECKGLERROR
3292                 if (pointer)
3293                 {
3294                         // caller wants color array enabled
3295                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3296                         if (!gl_state.pointer_color_enabled)
3297                         {
3298                                 gl_state.pointer_color_enabled = true;
3299                                 CHECKGLERROR
3300                                 qglEnableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR
3301                         }
3302                         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)
3303                         {
3304                                 gl_state.pointer_color_components = components;
3305                                 gl_state.pointer_color_gltype = gltype;
3306                                 gl_state.pointer_color_stride = stride;
3307                                 gl_state.pointer_color_pointer = pointer;
3308                                 gl_state.pointer_color_vertexbuffer = vertexbuffer;
3309                                 gl_state.pointer_color_offset = bufferoffset;
3310                                 CHECKGLERROR
3311                                 GL_BindVBO(bufferobject);
3312                                 qglVertexAttribPointer(GLSLATTRIB_COLOR, components, gltype, false, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3313                         }
3314                 }
3315                 else
3316                 {
3317                         // caller wants color array disabled
3318                         if (gl_state.pointer_color_enabled)
3319                         {
3320                                 gl_state.pointer_color_enabled = false;
3321                                 CHECKGLERROR
3322                                 qglDisableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR
3323                                 // when color array is on the glColor gets trashed, set it again
3324                                 qglVertexAttrib4f(GLSLATTRIB_COLOR, gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
3325                         }
3326                 }
3327                 break;
3328         case RENDERPATH_D3D9:
3329         case RENDERPATH_D3D10:
3330         case RENDERPATH_D3D11:
3331         case RENDERPATH_SOFT:
3332                 break;
3333         }
3334 }
3335
3336 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)
3337 {
3338         gltextureunit_t *unit = gl_state.units + unitnum;
3339         // update array settings
3340         // note: there is no need to check bufferobject here because all cases
3341         // that involve a valid bufferobject also supply a texcoord array
3342         switch(vid.renderpath)
3343         {
3344         case RENDERPATH_GL11:
3345         case RENDERPATH_GL13:
3346         case RENDERPATH_GLES1:
3347                 CHECKGLERROR
3348                 if (pointer)
3349                 {
3350                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3351                         // texture array unit is enabled, enable the array
3352                         if (!unit->arrayenabled)
3353                         {
3354                                 unit->arrayenabled = true;
3355                                 GL_ClientActiveTexture(unitnum);
3356                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
3357                         }
3358                         // texcoord array
3359                         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)
3360                         {
3361                                 unit->pointer_texcoord_components = components;
3362                                 unit->pointer_texcoord_gltype = gltype;
3363                                 unit->pointer_texcoord_stride = stride;
3364                                 unit->pointer_texcoord_pointer = pointer;
3365                                 unit->pointer_texcoord_vertexbuffer = vertexbuffer;
3366                                 unit->pointer_texcoord_offset = bufferoffset;
3367                                 GL_ClientActiveTexture(unitnum);
3368                                 GL_BindVBO(bufferobject);
3369                                 qglTexCoordPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3370                         }
3371                 }
3372                 else
3373                 {
3374                         // texture array unit is disabled, disable the array
3375                         if (unit->arrayenabled)
3376                         {
3377                                 unit->arrayenabled = false;
3378                                 GL_ClientActiveTexture(unitnum);
3379                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
3380                         }
3381                 }
3382                 break;
3383         case RENDERPATH_GL20:
3384         case RENDERPATH_GLES2:
3385                 CHECKGLERROR
3386                 if (pointer)
3387                 {
3388                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3389                         // texture array unit is enabled, enable the array
3390                         if (!unit->arrayenabled)
3391                         {
3392                                 unit->arrayenabled = true;
3393                                 qglEnableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
3394                         }
3395                         // texcoord array
3396                         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)
3397                         {
3398                                 unit->pointer_texcoord_components = components;
3399                                 unit->pointer_texcoord_gltype = gltype;
3400                                 unit->pointer_texcoord_stride = stride;
3401                                 unit->pointer_texcoord_pointer = pointer;
3402                                 unit->pointer_texcoord_vertexbuffer = vertexbuffer;
3403                                 unit->pointer_texcoord_offset = bufferoffset;
3404                                 GL_BindVBO(bufferobject);
3405                                 qglVertexAttribPointer(unitnum+GLSLATTRIB_TEXCOORD0, components, gltype, false, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3406                         }
3407                 }
3408                 else
3409                 {
3410                         // texture array unit is disabled, disable the array
3411                         if (unit->arrayenabled)
3412                         {
3413                                 unit->arrayenabled = false;
3414                                 qglDisableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
3415                         }
3416                 }
3417                 break;
3418         case RENDERPATH_D3D9:
3419         case RENDERPATH_D3D10:
3420         case RENDERPATH_D3D11:
3421         case RENDERPATH_SOFT:
3422                 break;
3423         }
3424 }
3425
3426 int R_Mesh_TexBound(unsigned int unitnum, int id)
3427 {
3428         gltextureunit_t *unit = gl_state.units + unitnum;
3429         if (unitnum >= vid.teximageunits)
3430                 return 0;
3431         if (id == GL_TEXTURE_2D)
3432                 return unit->t2d;
3433         if (id == GL_TEXTURE_3D)
3434                 return unit->t3d;
3435         if (id == GL_TEXTURE_CUBE_MAP_ARB)
3436                 return unit->tcubemap;
3437         return 0;
3438 }
3439
3440 void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int width, int height)
3441 {
3442         switch(vid.renderpath)
3443         {
3444         case RENDERPATH_GL11:
3445         case RENDERPATH_GL13:
3446         case RENDERPATH_GL20:
3447         case RENDERPATH_GLES1:
3448         case RENDERPATH_GLES2:
3449                 R_Mesh_TexBind(0, tex);
3450                 GL_ActiveTexture(0);CHECKGLERROR
3451                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, sx, sy, width, height);CHECKGLERROR
3452                 break;
3453         case RENDERPATH_D3D9:
3454 #ifdef SUPPORTD3D
3455                 {
3456                         IDirect3DSurface9 *currentsurface = NULL;
3457                         IDirect3DSurface9 *texturesurface = NULL;
3458                         RECT sourcerect;
3459                         RECT destrect;
3460                         sourcerect.left = sx;
3461                         sourcerect.top = sy;
3462                         sourcerect.right = sx + width;
3463                         sourcerect.bottom = sy + height;
3464                         destrect.left = tx;
3465                         destrect.top = ty;
3466                         destrect.right = tx + width;
3467                         destrect.bottom = ty + height;
3468                         if (!FAILED(IDirect3DTexture9_GetSurfaceLevel(((IDirect3DTexture9 *)tex->d3dtexture), 0, &texturesurface)))
3469                         {
3470                                 if (!FAILED(IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &currentsurface)))
3471                                 {
3472                                         IDirect3DDevice9_StretchRect(vid_d3d9dev, currentsurface, &sourcerect, texturesurface, &destrect, D3DTEXF_NONE);
3473                                         IDirect3DSurface9_Release(currentsurface);
3474                                 }
3475                                 IDirect3DSurface9_Release(texturesurface);
3476                         }
3477                 }
3478 #endif
3479                 break;
3480         case RENDERPATH_D3D10:
3481                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3482                 break;
3483         case RENDERPATH_D3D11:
3484                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3485                 break;
3486         case RENDERPATH_SOFT:
3487                 DPSOFTRAST_CopyRectangleToTexture(tex->texnum, 0, tx, ty, sx, sy, width, height);
3488                 break;
3489         }
3490 }
3491
3492 #ifdef SUPPORTD3D
3493 int d3drswrap[16] = {D3DRS_WRAP0