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