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