]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
26fe7c2522c371170b79babdb701dfa73abfe7aa
[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_ClearBindingsForTexture(int texnum)
3375 {
3376         gltextureunit_t *unit;
3377         unsigned int unitnum;
3378         // this doesn't really unbind the texture, but it does prevent a mistaken "do nothing" behavior on the next time this same texnum is bound on the same unit as the same type (this mainly affects r_shadow_bouncegrid because 3D textures are so rarely used)
3379         for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
3380         {
3381                 unit = gl_state.units + unitnum;
3382                 if (unit->t2d == texnum)
3383                         unit->t2d = -1;
3384                 if (unit->t3d == texnum)
3385                         unit->t3d = -1;
3386                 if (unit->tcubemap == texnum)
3387                         unit->tcubemap = -1;
3388         }
3389 }
3390
3391 void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
3392 {
3393         gltextureunit_t *unit = gl_state.units + unitnum;
3394         int tex2d, tex3d, texcubemap, texnum;
3395         if (unitnum >= vid.teximageunits)
3396                 return;
3397 //      if (unit->texture == tex)
3398 //              return;
3399         switch(vid.renderpath)
3400         {
3401         case RENDERPATH_GL20:
3402         case RENDERPATH_GLES2:
3403                 if (!tex)
3404                 {
3405                         tex = r_texture_white;
3406                         // not initialized enough yet...
3407                         if (!tex)
3408                                 return;
3409                 }
3410                 unit->texture = tex;
3411                 texnum = R_GetTexture(tex);
3412                 switch(tex->gltexturetypeenum)
3413                 {
3414                 case GL_TEXTURE_2D: if (unit->t2d != texnum) {GL_ActiveTexture(unitnum);unit->t2d = texnum;qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR}break;
3415                 case GL_TEXTURE_3D: if (unit->t3d != texnum) {GL_ActiveTexture(unitnum);unit->t3d = texnum;qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR}break;
3416                 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;
3417                 }
3418                 break;
3419         case RENDERPATH_GL13:
3420         case RENDERPATH_GL11:
3421                 unit->texture = tex;
3422                 tex2d = 0;
3423                 tex3d = 0;
3424                 texcubemap = 0;
3425                 if (tex)
3426                 {
3427                         texnum = R_GetTexture(tex);
3428                         switch(tex->gltexturetypeenum)
3429                         {
3430                         case GL_TEXTURE_2D:
3431                                 tex2d = texnum;
3432                                 break;
3433                         case GL_TEXTURE_3D:
3434                                 tex3d = texnum;
3435                                 break;
3436                         case GL_TEXTURE_CUBE_MAP_ARB:
3437                                 texcubemap = texnum;
3438                                 break;
3439                         }
3440                 }
3441                 // update 2d texture binding
3442                 if (unit->t2d != tex2d)
3443                 {
3444                         GL_ActiveTexture(unitnum);
3445                         if (tex2d)
3446                         {
3447                                 if (unit->t2d == 0)
3448                                 {
3449                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
3450                                 }
3451                         }
3452                         else
3453                         {
3454                                 if (unit->t2d)
3455                                 {
3456                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
3457                                 }
3458                         }
3459                         unit->t2d = tex2d;
3460                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
3461                 }
3462                 // update 3d texture binding
3463                 if (unit->t3d != tex3d)
3464                 {
3465                         GL_ActiveTexture(unitnum);
3466                         if (tex3d)
3467                         {
3468                                 if (unit->t3d == 0)
3469                                 {
3470                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
3471                                 }
3472                         }
3473                         else
3474                         {
3475                                 if (unit->t3d)
3476                                 {
3477                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
3478                                 }
3479                         }
3480                         unit->t3d = tex3d;
3481                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
3482                 }
3483                 // update cubemap texture binding
3484                 if (unit->tcubemap != texcubemap)
3485                 {
3486                         GL_ActiveTexture(unitnum);
3487                         if (texcubemap)
3488                         {
3489                                 if (unit->tcubemap == 0)
3490                                 {
3491                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
3492                                 }
3493                         }
3494                         else
3495                         {
3496                                 if (unit->tcubemap)
3497                                 {
3498                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
3499                                 }
3500                         }
3501                         unit->tcubemap = texcubemap;
3502                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
3503                 }
3504                 break;
3505         case RENDERPATH_D3D9:
3506 #ifdef SUPPORTD3D
3507                 {
3508                         extern cvar_t gl_texture_anisotropy;
3509                         if (!tex)
3510                         {
3511                                 tex = r_texture_white;
3512                                 // not initialized enough yet...
3513                                 if (!tex)
3514                                         return;
3515                         }
3516                         // upload texture if needed
3517                         R_GetTexture(tex);
3518                         if (unit->texture == tex)
3519                                 return;
3520                         unit->texture = tex;
3521                         IDirect3DDevice9_SetTexture(vid_d3d9dev, unitnum, (IDirect3DBaseTexture9*)tex->d3dtexture);
3522                         //IDirect3DDevice9_SetRenderState(vid_d3d9dev, d3drswrap[unitnum], (tex->flags & TEXF_CLAMP) ? (D3DWRAPCOORD_0 | D3DWRAPCOORD_1 | D3DWRAPCOORD_2) : 0);
3523                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSU, tex->d3daddressu);
3524                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSV, tex->d3daddressv);
3525                         if (tex->d3daddressw)
3526                                 IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSW,  tex->d3daddressw);
3527                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAGFILTER, tex->d3dmagfilter);
3528                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MINFILTER, tex->d3dminfilter);
3529                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MIPFILTER, tex->d3dmipfilter);
3530                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MIPMAPLODBIAS, tex->d3dmipmaplodbias);
3531                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAXMIPLEVEL, tex->d3dmaxmiplevelfilter);
3532                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAXANISOTROPY, gl_texture_anisotropy.integer);
3533                 }
3534 #endif
3535                 break;
3536         case RENDERPATH_D3D10:
3537                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3538                 break;
3539         case RENDERPATH_D3D11:
3540                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3541                 break;
3542         case RENDERPATH_SOFT:
3543                 if (!tex)
3544                 {
3545                         tex = r_texture_white;
3546                         // not initialized enough yet...
3547                         if (!tex)
3548                                 return;
3549                 }
3550                 texnum = R_GetTexture(tex);
3551                 if (unit->texture == tex)
3552                         return;
3553                 unit->texture = tex;
3554                 DPSOFTRAST_SetTexture(unitnum, texnum);
3555                 break;
3556         }
3557 }
3558
3559 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
3560 {
3561         gltextureunit_t *unit = gl_state.units + unitnum;
3562         switch(vid.renderpath)
3563         {
3564         case RENDERPATH_GL11:
3565         case RENDERPATH_GL13:
3566         case RENDERPATH_GL20:
3567         case RENDERPATH_GLES2:
3568                 if (matrix && matrix->m[3][3])
3569                 {
3570                         // texmatrix specified, check if it is different
3571                         if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
3572                         {
3573                                 float glmatrix[16];
3574                                 unit->texmatrixenabled = true;
3575                                 unit->matrix = *matrix;
3576                                 CHECKGLERROR
3577                                 Matrix4x4_ToArrayFloatGL(&unit->matrix, glmatrix);
3578                                 GL_ActiveTexture(unitnum);
3579                                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
3580                                 qglLoadMatrixf(glmatrix);CHECKGLERROR
3581                                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
3582                         }
3583                 }
3584                 else
3585                 {
3586                         // no texmatrix specified, revert to identity
3587                         if (unit->texmatrixenabled)
3588                         {
3589                                 unit->texmatrixenabled = false;
3590                                 unit->matrix = identitymatrix;
3591                                 CHECKGLERROR
3592                                 GL_ActiveTexture(unitnum);
3593                                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
3594                                 qglLoadIdentity();CHECKGLERROR
3595                                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
3596                         }
3597                 }
3598                 break;
3599         case RENDERPATH_D3D9:
3600         case RENDERPATH_D3D10:
3601         case RENDERPATH_D3D11:
3602                 break;
3603         case RENDERPATH_SOFT:
3604                 break;
3605         }
3606 }
3607
3608 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
3609 {
3610         gltextureunit_t *unit = gl_state.units + unitnum;
3611         CHECKGLERROR
3612         switch(vid.renderpath)
3613         {
3614         case RENDERPATH_GL20:
3615         case RENDERPATH_GLES2:
3616                 // do nothing
3617                 break;
3618         case RENDERPATH_GL13:
3619                 // GL_ARB_texture_env_combine
3620                 if (!combinergb)
3621                         combinergb = GL_MODULATE;
3622                 if (!combinealpha)
3623                         combinealpha = GL_MODULATE;
3624                 if (!rgbscale)
3625                         rgbscale = 1;
3626                 if (!alphascale)
3627                         alphascale = 1;
3628                 if (combinergb != combinealpha || rgbscale != 1 || alphascale != 1)
3629                 {
3630                         if (combinergb == GL_DECAL)
3631                                 combinergb = GL_INTERPOLATE_ARB;
3632                         if (unit->combine != GL_COMBINE_ARB)
3633                         {
3634                                 unit->combine = GL_COMBINE_ARB;
3635                                 GL_ActiveTexture(unitnum);
3636                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
3637                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
3638                         }
3639                         if (unit->combinergb != combinergb)
3640                         {
3641                                 unit->combinergb = combinergb;
3642                                 GL_ActiveTexture(unitnum);
3643                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
3644                         }
3645                         if (unit->combinealpha != combinealpha)
3646                         {
3647                                 unit->combinealpha = combinealpha;
3648                                 GL_ActiveTexture(unitnum);
3649                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
3650                         }
3651                         if (unit->rgbscale != rgbscale)
3652                         {
3653                                 unit->rgbscale = rgbscale;
3654                                 GL_ActiveTexture(unitnum);
3655                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, unit->rgbscale);CHECKGLERROR
3656                         }
3657                         if (unit->alphascale != alphascale)
3658                         {
3659                                 unit->alphascale = alphascale;
3660                                 GL_ActiveTexture(unitnum);
3661                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, unit->alphascale);CHECKGLERROR
3662                         }
3663                 }
3664                 else
3665                 {
3666                         if (unit->combine != combinergb)
3667                         {
3668                                 unit->combine = combinergb;
3669                                 GL_ActiveTexture(unitnum);
3670                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
3671                         }
3672                 }
3673                 break;
3674         case RENDERPATH_GL11:
3675                 // normal GL texenv
3676                 if (!combinergb)
3677                         combinergb = GL_MODULATE;
3678                 if (unit->combine != combinergb)
3679                 {
3680                         unit->combine = combinergb;
3681                         GL_ActiveTexture(unitnum);
3682                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
3683                 }
3684                 break;
3685         case RENDERPATH_D3D9:
3686         case RENDERPATH_D3D10:
3687         case RENDERPATH_D3D11:
3688                 break;
3689         case RENDERPATH_SOFT:
3690                 break;
3691         }
3692 }
3693
3694 void R_Mesh_ResetTextureState(void)
3695 {
3696         unsigned int unitnum;
3697
3698         BACKENDACTIVECHECK
3699
3700         for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
3701                 R_Mesh_TexBind(unitnum, NULL);
3702         for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++)
3703                 R_Mesh_TexCoordPointer(unitnum, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3704         switch(vid.renderpath)
3705         {
3706         case RENDERPATH_GL20:
3707         case RENDERPATH_GLES2:
3708         case RENDERPATH_D3D9:
3709         case RENDERPATH_D3D10:
3710         case RENDERPATH_D3D11:
3711         case RENDERPATH_SOFT:
3712                 break;
3713         case RENDERPATH_GL13:
3714         case RENDERPATH_GL11:
3715                 for (unitnum = 0;unitnum < vid.texunits;unitnum++)
3716                 {
3717                         R_Mesh_TexCombine(unitnum, GL_MODULATE, GL_MODULATE, 1, 1);
3718                         R_Mesh_TexMatrix(unitnum, NULL);
3719                 }
3720                 break;
3721         }
3722 }
3723
3724
3725
3726 #ifdef SUPPORTD3D
3727 //#define r_vertex3f_d3d9fvf (D3DFVF_XYZ)
3728 //#define r_vertexgeneric_d3d9fvf (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
3729 //#define r_vertexmesh_d3d9fvf (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX5 | D3DFVF_TEXCOORDSIZE1(3) | D3DFVF_TEXCOORDSIZE2(3) | D3DFVF_TEXCOORDSIZE3(3))
3730
3731 D3DVERTEXELEMENT9 r_vertex3f_d3d9elements[] =
3732 {
3733         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3734         D3DDECL_END()
3735 };
3736
3737 D3DVERTEXELEMENT9 r_vertexgeneric_d3d9elements[] =
3738 {
3739         {0, (int)((size_t)&((r_vertexgeneric_t *)0)->vertex3f  ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3740         {0, (int)((size_t)&((r_vertexgeneric_t *)0)->color4f   ), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
3741         {0, (int)((size_t)&((r_vertexgeneric_t *)0)->texcoord2f), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
3742         D3DDECL_END()
3743 };
3744
3745 D3DVERTEXELEMENT9 r_vertexmesh_d3d9elements[] =
3746 {
3747         {0, (int)((size_t)&((r_vertexmesh_t *)0)->vertex3f          ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3748         {0, (int)((size_t)&((r_vertexmesh_t *)0)->color4f           ), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
3749         {0, (int)((size_t)&((r_vertexmesh_t *)0)->texcoordtexture2f ), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
3750         {0, (int)((size_t)&((r_vertexmesh_t *)0)->svector3f         ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
3751         {0, (int)((size_t)&((r_vertexmesh_t *)0)->tvector3f         ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2},
3752         {0, (int)((size_t)&((r_vertexmesh_t *)0)->normal3f          ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3},
3753         {0, (int)((size_t)&((r_vertexmesh_t *)0)->texcoordlightmap2f), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4},
3754         D3DDECL_END()
3755 };
3756
3757 IDirect3DVertexDeclaration9 *r_vertex3f_d3d9decl;
3758 IDirect3DVertexDeclaration9 *r_vertexgeneric_d3d9decl;
3759 IDirect3DVertexDeclaration9 *r_vertexmesh_d3d9decl;
3760 #endif
3761
3762 static void R_Mesh_InitVertexDeclarations(void)
3763 {
3764 #ifdef SUPPORTD3D
3765         r_vertex3f_d3d9decl = NULL;
3766         r_vertexgeneric_d3d9decl = NULL;
3767         r_vertexmesh_d3d9decl = NULL;
3768         switch(vid.renderpath)
3769         {
3770         case RENDERPATH_GL20:
3771         case RENDERPATH_GL13:
3772         case RENDERPATH_GL11:
3773         case RENDERPATH_GLES2:
3774                 break;
3775         case RENDERPATH_D3D9:
3776                 IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertex3f_d3d9elements, &r_vertex3f_d3d9decl);
3777                 IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexgeneric_d3d9elements, &r_vertexgeneric_d3d9decl);
3778                 IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexmesh_d3d9elements, &r_vertexmesh_d3d9decl);
3779                 break;
3780         case RENDERPATH_D3D10:
3781                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3782                 break;
3783         case RENDERPATH_D3D11:
3784                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3785                 break;
3786         case RENDERPATH_SOFT:
3787                 break;
3788         }
3789 #endif
3790 }
3791
3792 static void R_Mesh_DestroyVertexDeclarations(void)
3793 {
3794 #ifdef SUPPORTD3D
3795         if (r_vertex3f_d3d9decl)
3796                 IDirect3DVertexDeclaration9_Release(r_vertex3f_d3d9decl);
3797         r_vertex3f_d3d9decl = NULL;
3798         if (r_vertexgeneric_d3d9decl)
3799                 IDirect3DVertexDeclaration9_Release(r_vertexgeneric_d3d9decl);
3800         r_vertexgeneric_d3d9decl = NULL;
3801         if (r_vertexmesh_d3d9decl)
3802                 IDirect3DVertexDeclaration9_Release(r_vertexmesh_d3d9decl);
3803         r_vertexmesh_d3d9decl = NULL;
3804 #endif
3805 }
3806
3807 void R_Mesh_PrepareVertices_Vertex3f(int numvertices, const float *vertex3f, const r_meshbuffer_t *vertexbuffer)
3808 {
3809         // upload temporary vertexbuffer for this rendering
3810         if (!gl_state.usevbo_staticvertex)
3811                 vertexbuffer = NULL;
3812         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
3813         {
3814                 if (gl_state.preparevertices_dynamicvertexbuffer)
3815                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex3f, numvertices * sizeof(float[3]));
3816                 else
3817                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex3f, numvertices * sizeof(float[3]), "temporary", false, true, false);
3818                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
3819         }
3820         switch(vid.renderpath)
3821         {
3822         case RENDERPATH_GL20:
3823         case RENDERPATH_GLES2:
3824                 if (vertexbuffer)
3825                 {
3826                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3827                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3828                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3829                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3830                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3831                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3832                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3833                 }
3834                 else
3835                 {
3836                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3837                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3838                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3839                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3840                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3841                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3842                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3843                 }
3844                 break;
3845         case RENDERPATH_GL13:
3846                 if (vertexbuffer)
3847                 {
3848                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3849                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3850                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3851                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3852                 }
3853                 else
3854                 {
3855                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3856                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3857                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3858                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3859                 }
3860                 break;
3861         case RENDERPATH_GL11:
3862                 if (vertexbuffer)
3863                 {
3864                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3865                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3866                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3867                 }
3868                 else
3869                 {
3870                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3871                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3872                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3873                 }
3874                 break;
3875         case RENDERPATH_D3D9:
3876 #ifdef SUPPORTD3D
3877                 IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertex3f_d3d9decl);
3878                 if (vertexbuffer)
3879                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, 0, sizeof(float[3]));
3880                 else
3881                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0);
3882                 gl_state.d3dvertexbuffer = (void *)vertexbuffer;
3883                 gl_state.d3dvertexdata = (void *)vertex3f;
3884                 gl_state.d3dvertexsize = sizeof(float[3]);
3885 #endif
3886                 break;
3887         case RENDERPATH_D3D10:
3888                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3889                 break;
3890         case RENDERPATH_D3D11:
3891                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3892                 break;
3893         case RENDERPATH_SOFT:
3894                 DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3]));
3895                 DPSOFTRAST_SetColorPointer(NULL, 0);
3896                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), NULL);
3897                 DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(float[2]), NULL);
3898                 DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(float[2]), NULL);
3899                 DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(float[2]), NULL);
3900                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), NULL);
3901                 break;
3902         }
3903 }
3904
3905
3906
3907 r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices)
3908 {
3909         size_t size;
3910         size = sizeof(r_vertexgeneric_t) * numvertices;
3911         if (gl_state.preparevertices_tempdatamaxsize < size)
3912         {
3913                 gl_state.preparevertices_tempdatamaxsize = size;
3914                 gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
3915         }
3916         gl_state.preparevertices_vertexgeneric = (r_vertexgeneric_t *)gl_state.preparevertices_tempdata;
3917         gl_state.preparevertices_numvertices = numvertices;
3918         return gl_state.preparevertices_vertexgeneric;
3919 }
3920
3921 qboolean R_Mesh_PrepareVertices_Generic_Unlock(void)
3922 {
3923         R_Mesh_PrepareVertices_Generic(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexgeneric, NULL);
3924         gl_state.preparevertices_vertexgeneric = NULL;
3925         gl_state.preparevertices_numvertices = 0;
3926         return true;
3927 }
3928
3929 void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f)
3930 {
3931         int i;
3932         r_vertexgeneric_t *vertex;
3933         switch(vid.renderpath)
3934         {
3935         case RENDERPATH_GL20:
3936         case RENDERPATH_GLES2:
3937                 if (!vid.useinterleavedarrays)
3938                 {
3939                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
3940                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
3941                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
3942                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3943                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3944                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3945                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3946                         return;
3947                 }
3948                 break;
3949         case RENDERPATH_GL13:
3950         case RENDERPATH_GL11:
3951                 if (!vid.useinterleavedarrays)
3952                 {
3953                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
3954                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
3955                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
3956                         if (vid.texunits >= 2)
3957                                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3958                         if (vid.texunits >= 3)
3959                                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3960                         return;
3961                 }
3962                 break;
3963         case RENDERPATH_D3D9:
3964         case RENDERPATH_D3D10:
3965         case RENDERPATH_D3D11:
3966                 break;
3967         case RENDERPATH_SOFT:
3968                 DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3]));
3969                 DPSOFTRAST_SetColorPointer(color4f, sizeof(float[4]));
3970                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), texcoord2f);
3971                 DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(float[2]), NULL);
3972                 DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(float[2]), NULL);
3973                 DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(float[2]), NULL);
3974                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), NULL);
3975                 return;
3976         }
3977
3978         // no quick path for this case, convert to vertex structs
3979         vertex = R_Mesh_PrepareVertices_Generic_Lock(numvertices);
3980         for (i = 0;i < numvertices;i++)
3981                 VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
3982         if (color4f)
3983         {
3984                 for (i = 0;i < numvertices;i++)
3985                         Vector4Copy(color4f + 4*i, vertex[i].color4f);
3986         }
3987         else
3988         {
3989                 for (i = 0;i < numvertices;i++)
3990                         Vector4Copy(gl_state.color4f, vertex[i].color4f);
3991         }
3992         if (texcoord2f)
3993                 for (i = 0;i < numvertices;i++)
3994                         Vector2Copy(texcoord2f + 2*i, vertex[i].texcoord2f);
3995         R_Mesh_PrepareVertices_Generic_Unlock();
3996         R_Mesh_PrepareVertices_Generic(numvertices, vertex, NULL);
3997 }
3998
3999 void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer)
4000 {
4001         // upload temporary vertexbuffer for this rendering
4002         if (!gl_state.usevbo_staticvertex)
4003                 vertexbuffer = NULL;
4004         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
4005         {
4006                 if (gl_state.preparevertices_dynamicvertexbuffer)
4007                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
4008                 else
4009                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true, false);
4010                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
4011         }
4012         switch(vid.renderpath)
4013         {
4014         case RENDERPATH_GL20:
4015         case RENDERPATH_GLES2:
4016                 if (vertexbuffer)
4017                 {
4018                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4019                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4020                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
4021                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4022                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4023                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4024                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4025                 }
4026                 else
4027                 {
4028                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4029                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4030                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
4031                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4032                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4033                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4034                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4035                 }
4036                 break;
4037         case RENDERPATH_GL13:
4038                 if (vertexbuffer)
4039                 {
4040                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4041                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4042                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
4043                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4044                 }
4045                 else
4046                 {
4047                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4048                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4049                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
4050                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4051                 }
4052                 break;
4053         case RENDERPATH_GL11:
4054                 if (vertexbuffer)
4055                 {
4056                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4057                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4058                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
4059                 }
4060                 else
4061                 {
4062                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4063                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4064                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
4065                 }
4066                 break;
4067         case RENDERPATH_D3D9:
4068 #ifdef SUPPORTD3D
4069                 IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertexgeneric_d3d9decl);
4070                 if (vertexbuffer)
4071                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, 0, sizeof(*vertex));
4072                 else
4073                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0);
4074                 gl_state.d3dvertexbuffer = (void *)vertexbuffer;
4075                 gl_state.d3dvertexdata = (void *)vertex;
4076                 gl_state.d3dvertexsize = sizeof(*vertex);
4077 #endif
4078                 break;
4079         case RENDERPATH_D3D10:
4080                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4081                 break;
4082         case RENDERPATH_D3D11:
4083                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4084                 break;
4085         case RENDERPATH_SOFT:
4086                 DPSOFTRAST_SetVertexPointer(vertex->vertex3f, sizeof(*vertex));
4087                 DPSOFTRAST_SetColorPointer(vertex->color4f, sizeof(*vertex));
4088                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(*vertex), vertex->texcoord2f);
4089                 DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(*vertex), NULL);
4090                 DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(*vertex), NULL);
4091                 DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(*vertex), NULL);
4092                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(*vertex), NULL);
4093                 break;
4094         }
4095 }
4096
4097
4098
4099 r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices)
4100 {
4101         size_t size;
4102         size = sizeof(r_vertexmesh_t) * numvertices;
4103         if (gl_state.preparevertices_tempdatamaxsize < size)
4104         {
4105                 gl_state.preparevertices_tempdatamaxsize = size;
4106                 gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
4107         }
4108         gl_state.preparevertices_vertexmesh = (r_vertexmesh_t *)gl_state.preparevertices_tempdata;
4109         gl_state.preparevertices_numvertices = numvertices;
4110         return gl_state.preparevertices_vertexmesh;
4111 }
4112
4113 qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void)
4114 {
4115         R_Mesh_PrepareVertices_Mesh(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexmesh, NULL);
4116         gl_state.preparevertices_vertexmesh = NULL;
4117         gl_state.preparevertices_numvertices = 0;
4118         return true;
4119 }
4120
4121 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)
4122 {
4123         int i;
4124         r_vertexmesh_t *vertex;
4125         switch(vid.renderpath)
4126         {
4127         case RENDERPATH_GL20:
4128         case RENDERPATH_GLES2:
4129                 if (!vid.useinterleavedarrays)
4130                 {
4131                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
4132                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
4133                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
4134                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), svector3f, NULL, 0);
4135                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), tvector3f, NULL, 0);
4136                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), normal3f, NULL, 0);
4137                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
4138                         return;
4139                 }
4140                 break;
4141         case RENDERPATH_GL13:
4142         case RENDERPATH_GL11:
4143                 if (!vid.useinterleavedarrays)
4144                 {
4145                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
4146                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
4147                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
4148                         if (vid.texunits >= 2)
4149                                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
4150                         if (vid.texunits >= 3)
4151                                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4152                         return;
4153                 }
4154                 break;
4155         case RENDERPATH_D3D9:
4156         case RENDERPATH_D3D10:
4157         case RENDERPATH_D3D11:
4158                 break;
4159         case RENDERPATH_SOFT:
4160                 DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3]));
4161                 DPSOFTRAST_SetColorPointer(color4f, sizeof(float[4]));
4162                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), texcoordtexture2f);
4163                 DPSOFTRAST_SetTexCoordPointer(1, 3, sizeof(float[3]), svector3f);
4164                 DPSOFTRAST_SetTexCoordPointer(2, 3, sizeof(float[3]), tvector3f);
4165                 DPSOFTRAST_SetTexCoordPointer(3, 3, sizeof(float[3]), normal3f);
4166                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), texcoordlightmap2f);
4167                 return;
4168         }
4169
4170         vertex = R_Mesh_PrepareVertices_Mesh_Lock(numvertices);
4171         for (i = 0;i < numvertices;i++)
4172                 VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
4173         if (svector3f)
4174                 for (i = 0;i < numvertices;i++)
4175                         VectorCopy(svector3f + 3*i, vertex[i].svector3f);
4176         if (tvector3f)
4177                 for (i = 0;i < numvertices;i++)
4178                         VectorCopy(tvector3f + 3*i, vertex[i].tvector3f);
4179         if (normal3f)
4180                 for (i = 0;i < numvertices;i++)
4181                         VectorCopy(normal3f + 3*i, vertex[i].normal3f);
4182         if (color4f)
4183         {
4184                 for (i = 0;i < numvertices;i++)
4185                         Vector4Copy(color4f + 4*i, vertex[i].color4f);
4186         }
4187         else
4188         {
4189                 for (i = 0;i < numvertices;i++)
4190                         Vector4Copy(gl_state.color4f, vertex[i].color4f);
4191         }
4192         if (texcoordtexture2f)
4193                 for (i = 0;i < numvertices;i++)
4194                         Vector2Copy(texcoordtexture2f + 2*i, vertex[i].texcoordtexture2f);
4195         if (texcoordlightmap2f)
4196                 for (i = 0;i < numvertices;i++)
4197                         Vector2Copy(texcoordlightmap2f + 2*i, vertex[i].texcoordlightmap2f);
4198         R_Mesh_PrepareVertices_Mesh_Unlock();
4199         R_Mesh_PrepareVertices_Mesh(numvertices, vertex, NULL);
4200 }
4201
4202 void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *vertexbuffer)
4203 {
4204         // upload temporary vertexbuffer for this rendering
4205         if (!gl_state.usevbo_staticvertex)
4206                 vertexbuffer = NULL;
4207         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
4208         {
4209                 if (gl_state.preparevertices_dynamicvertexbuffer)
4210                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
4211                 else
4212                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true, false);
4213                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
4214         }
4215         switch(vid.renderpath)
4216         {
4217         case RENDERPATH_GL20:
4218         case RENDERPATH_GLES2:
4219                 if (vertexbuffer)
4220                 {
4221                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4222                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4223                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
4224                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , vertexbuffer, (int)((unsigned char *)vertex->svector3f          - (unsigned char *)vertex));
4225                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , vertexbuffer, (int)((unsigned char *)vertex->tvector3f          - (unsigned char *)vertex));
4226                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , vertexbuffer, (int)((unsigned char *)vertex->normal3f           - (unsigned char *)vertex));
4227                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
4228                 }
4229                 else
4230                 {
4231                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4232                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4233                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
4234                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , NULL, 0);
4235                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , NULL, 0);
4236                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , NULL, 0);
4237                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
4238                 }
4239                 break;
4240         case RENDERPATH_GL13:
4241                 if (vertexbuffer)
4242                 {
4243                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4244                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4245                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
4246                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
4247                 }
4248                 else
4249                 {
4250                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4251                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4252                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
4253                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
4254                 }
4255                 break;
4256         case RENDERPATH_GL11:
4257                 if (vertexbuffer)
4258                 {
4259                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4260                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4261                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
4262                 }
4263                 else
4264                 {
4265                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4266                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4267                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
4268                 }
4269                 break;
4270         case RENDERPATH_D3D9:
4271 #ifdef SUPPORTD3D
4272                 IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertexmesh_d3d9decl);
4273                 if (vertexbuffer)
4274                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, 0, sizeof(*vertex));
4275                 else
4276                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0);
4277                 gl_state.d3dvertexbuffer = (void *)vertexbuffer;
4278                 gl_state.d3dvertexdata = (void *)vertex;
4279                 gl_state.d3dvertexsize = sizeof(*vertex);
4280 #endif
4281                 break;
4282         case RENDERPATH_D3D10:
4283                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4284                 break;
4285         case RENDERPATH_D3D11:
4286                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4287                 break;
4288         case RENDERPATH_SOFT:
4289                 DPSOFTRAST_SetVertexPointer(vertex->vertex3f, sizeof(*vertex));
4290                 DPSOFTRAST_SetColorPointer(vertex->color4f, sizeof(*vertex));
4291                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(*vertex), vertex->texcoordtexture2f);
4292                 DPSOFTRAST_SetTexCoordPointer(1, 3, sizeof(*vertex), vertex->svector3f);
4293                 DPSOFTRAST_SetTexCoordPointer(2, 3, sizeof(*vertex), vertex->tvector3f);
4294                 DPSOFTRAST_SetTexCoordPointer(3, 3, sizeof(*vertex), vertex->normal3f);
4295                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(*vertex), vertex->texcoordlightmap2f);
4296                 break;
4297         }
4298 }