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