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