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