]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
OpenGL 2.0 path: Make handling of Alpha-To-Coverage same as AlphaTest (enabling befor...
[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((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((r_transparent_alphatocoverage.integer) ? GL_SAMPLE_ALPHA_TO_COVERAGE_ARB : GL_ALPHA_TEST);CHECKGLERROR
2138                         }
2139                         else
2140                         {
2141                                 qglDisable((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                         if (vid_multisampling.integer)
2159                         {
2160                                 if (gl_state.alphatest && r_transparent_alphatocoverage.integer)
2161                                         qglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
2162                                 else
2163                                         qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
2164                                 CHECKGLERROR
2165                         }
2166                         break;
2167                 }
2168         }
2169 }
2170
2171 void GL_ColorMask(int r, int g, int b, int a)
2172 {
2173         // NOTE: this matches D3DCOLORWRITEENABLE_RED, GREEN, BLUE, ALPHA
2174         int state = (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0) | (a ? 8 : 0);
2175         if (gl_state.colormask != state)
2176         {
2177                 gl_state.colormask = state;
2178                 switch(vid.renderpath)
2179                 {
2180                 case RENDERPATH_GL11:
2181                 case RENDERPATH_GL13:
2182                 case RENDERPATH_GL20:
2183                 case RENDERPATH_GLES1:
2184                 case RENDERPATH_GLES2:
2185                         CHECKGLERROR
2186                         qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
2187                         break;
2188                 case RENDERPATH_D3D9:
2189 #ifdef SUPPORTD3D
2190                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, state);
2191 #endif
2192                         break;
2193                 case RENDERPATH_D3D10:
2194                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2195                         break;
2196                 case RENDERPATH_D3D11:
2197                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2198                         break;
2199                 case RENDERPATH_SOFT:
2200                         DPSOFTRAST_ColorMask(r, g, b, a);
2201                         break;
2202                 }
2203         }
2204 }
2205
2206 void GL_Color(float cr, float cg, float cb, float ca)
2207 {
2208         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)
2209         {
2210                 gl_state.color4f[0] = cr;
2211                 gl_state.color4f[1] = cg;
2212                 gl_state.color4f[2] = cb;
2213                 gl_state.color4f[3] = ca;
2214                 switch(vid.renderpath)
2215                 {
2216                 case RENDERPATH_GL11:
2217                 case RENDERPATH_GL13:
2218                 case RENDERPATH_GLES1:
2219                         CHECKGLERROR
2220                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
2221                         CHECKGLERROR
2222                         break;
2223                 case RENDERPATH_D3D9:
2224                 case RENDERPATH_D3D10:
2225                 case RENDERPATH_D3D11:
2226                         // no equivalent in D3D
2227                         break;
2228                 case RENDERPATH_SOFT:
2229                         DPSOFTRAST_Color4f(cr, cg, cb, ca);
2230                         break;
2231                 case RENDERPATH_GL20:
2232                 case RENDERPATH_GLES2:
2233                         qglVertexAttrib4f(GLSLATTRIB_COLOR, cr, cg, cb, ca);
2234                         break;
2235                 }
2236         }
2237 }
2238
2239 void GL_Scissor (int x, int y, int width, int height)
2240 {
2241         switch(vid.renderpath)
2242         {
2243         case RENDERPATH_GL11:
2244         case RENDERPATH_GL13:
2245         case RENDERPATH_GL20:
2246         case RENDERPATH_GLES1:
2247         case RENDERPATH_GLES2:
2248                 CHECKGLERROR
2249                 qglScissor(x, y,width,height);
2250                 CHECKGLERROR
2251                 break;
2252         case RENDERPATH_D3D9:
2253 #ifdef SUPPORTD3D
2254                 {
2255                         RECT d3drect;
2256                         d3drect.left = x;
2257                         d3drect.top = y;
2258                         d3drect.right = x + width;
2259                         d3drect.bottom = y + height;
2260                         IDirect3DDevice9_SetScissorRect(vid_d3d9dev, &d3drect);
2261                 }
2262 #endif
2263                 break;
2264         case RENDERPATH_D3D10:
2265                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2266                 break;
2267         case RENDERPATH_D3D11:
2268                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2269                 break;
2270         case RENDERPATH_SOFT:
2271                 DPSOFTRAST_Scissor(x, y, width, height);
2272                 break;
2273         }
2274 }
2275
2276 void GL_ScissorTest(int state)
2277 {
2278         if (gl_state.scissortest != state)
2279         {
2280                 gl_state.scissortest = state;
2281                 switch(vid.renderpath)
2282                 {
2283                 case RENDERPATH_GL11:
2284                 case RENDERPATH_GL13:
2285                 case RENDERPATH_GL20:
2286                 case RENDERPATH_GLES1:
2287                 case RENDERPATH_GLES2:
2288                         CHECKGLERROR
2289                         if(gl_state.scissortest)
2290                                 qglEnable(GL_SCISSOR_TEST);
2291                         else
2292                                 qglDisable(GL_SCISSOR_TEST);
2293                         CHECKGLERROR
2294                         break;
2295                 case RENDERPATH_D3D9:
2296 #ifdef SUPPORTD3D
2297                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SCISSORTESTENABLE, gl_state.scissortest);
2298 #endif
2299                         break;
2300                 case RENDERPATH_D3D10:
2301                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2302                         break;
2303                 case RENDERPATH_D3D11:
2304                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2305                         break;
2306                 case RENDERPATH_SOFT:
2307                         DPSOFTRAST_ScissorTest(gl_state.scissortest);
2308                         break;
2309                 }
2310         }
2311 }
2312
2313 void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilvalue)
2314 {
2315         static const float blackcolor[4] = {0, 0, 0, 0};
2316         // prevent warnings when trying to clear a buffer that does not exist
2317         if (!colorvalue)
2318                 colorvalue = blackcolor;
2319         if (!vid.stencil)
2320         {
2321                 mask &= ~GL_STENCIL_BUFFER_BIT;
2322                 stencilvalue = 0;
2323         }
2324         switch(vid.renderpath)
2325         {
2326         case RENDERPATH_GL11:
2327         case RENDERPATH_GL13:
2328         case RENDERPATH_GL20:
2329         case RENDERPATH_GLES1:
2330         case RENDERPATH_GLES2:
2331                 CHECKGLERROR
2332                 if (mask & GL_COLOR_BUFFER_BIT)
2333                 {
2334                         qglClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);CHECKGLERROR
2335                 }
2336                 if (mask & GL_DEPTH_BUFFER_BIT)
2337                 {
2338                         qglClearDepth(depthvalue);CHECKGLERROR
2339                 }
2340                 if (mask & GL_STENCIL_BUFFER_BIT)
2341                 {
2342                         qglClearStencil(stencilvalue);CHECKGLERROR
2343                 }
2344                 qglClear(mask);CHECKGLERROR
2345                 break;
2346         case RENDERPATH_D3D9:
2347 #ifdef SUPPORTD3D
2348                 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);
2349 #endif
2350                 break;
2351         case RENDERPATH_D3D10:
2352                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2353                 break;
2354         case RENDERPATH_D3D11:
2355                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2356                 break;
2357         case RENDERPATH_SOFT:
2358                 if (mask & GL_COLOR_BUFFER_BIT)
2359                         DPSOFTRAST_ClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);
2360                 if (mask & GL_DEPTH_BUFFER_BIT)
2361                         DPSOFTRAST_ClearDepth(depthvalue);
2362                 break;
2363         }
2364 }
2365
2366 void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels)
2367 {
2368         switch(vid.renderpath)
2369         {
2370         case RENDERPATH_GL11:
2371         case RENDERPATH_GL13:
2372         case RENDERPATH_GL20:
2373         case RENDERPATH_GLES1:
2374         case RENDERPATH_GLES2:
2375                 CHECKGLERROR
2376                 qglReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, outpixels);CHECKGLERROR
2377                 break;
2378         case RENDERPATH_D3D9:
2379 #ifdef SUPPORTD3D
2380                 {
2381                         // LordHavoc: we can't directly download the backbuffer because it may be
2382                         // multisampled, and it may not be lockable, so we blit it to a lockable
2383                         // surface of the same dimensions (but without multisample) to resolve the
2384                         // multisample buffer to a normal image, and then lock that...
2385                         IDirect3DSurface9 *stretchsurface = NULL;
2386                         if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &stretchsurface, NULL)))
2387                         {
2388                                 D3DLOCKED_RECT lockedrect;
2389                                 if (!FAILED(IDirect3DDevice9_StretchRect(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, NULL, stretchsurface, NULL, D3DTEXF_POINT)))
2390                                 {
2391                                         if (!FAILED(IDirect3DSurface9_LockRect(stretchsurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2392                                         {
2393                                                 int line;
2394                                                 unsigned char *row = (unsigned char *)lockedrect.pBits + x * 4 + lockedrect.Pitch * (vid.height - 1 - y);
2395                                                 for (line = 0;line < height;line++, row -= lockedrect.Pitch)
2396                                                         memcpy(outpixels + line * width * 4, row, width * 4);
2397                                                 IDirect3DSurface9_UnlockRect(stretchsurface);
2398                                         }
2399                                 }
2400                                 IDirect3DSurface9_Release(stretchsurface);
2401                         }
2402                         // code scraps
2403                         //IDirect3DSurface9 *syssurface = NULL;
2404                         //if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &stretchsurface, NULL)))
2405                         //if (!FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &syssurface, NULL)))
2406                         //IDirect3DDevice9_GetRenderTargetData(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, syssurface);
2407                         //if (!FAILED(IDirect3DDevice9_GetFrontBufferData(vid_d3d9dev, 0, syssurface)))
2408                         //if (!FAILED(IDirect3DSurface9_LockRect(syssurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2409                         //IDirect3DSurface9_UnlockRect(syssurface);
2410                         //IDirect3DSurface9_Release(syssurface);
2411                 }
2412 #endif
2413                 break;
2414         case RENDERPATH_D3D10:
2415                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2416                 break;
2417         case RENDERPATH_D3D11:
2418                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2419                 break;
2420         case RENDERPATH_SOFT:
2421                 DPSOFTRAST_GetPixelsBGRA(x, y, width, height, outpixels);
2422                 break;
2423         }
2424 }
2425
2426 // called at beginning of frame
2427 void R_Mesh_Start(void)
2428 {
2429         BACKENDACTIVECHECK
2430         R_Mesh_ResetRenderTargets();
2431         R_Mesh_SetUseVBO();
2432         if (gl_printcheckerror.integer && !gl_paranoid.integer)
2433         {
2434                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
2435                 Cvar_SetValueQuick(&gl_paranoid, 1);
2436         }
2437 }
2438
2439 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
2440 {
2441         int shaderobject;
2442         int shadercompiled;
2443         char compilelog[MAX_INPUTLINE];
2444         shaderobject = qglCreateShader(shadertypeenum);CHECKGLERROR
2445         if (!shaderobject)
2446                 return false;
2447         qglShaderSource(shaderobject, numstrings, strings, NULL);CHECKGLERROR
2448         qglCompileShader(shaderobject);CHECKGLERROR
2449         qglGetShaderiv(shaderobject, GL_COMPILE_STATUS, &shadercompiled);CHECKGLERROR
2450         qglGetShaderInfoLog(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
2451         if (compilelog[0] && (strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error") || strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")))
2452         {
2453                 int i, j, pretextlines = 0;
2454                 for (i = 0;i < numstrings - 1;i++)
2455                         for (j = 0;strings[i][j];j++)
2456                                 if (strings[i][j] == '\n')
2457                                         pretextlines++;
2458                 Con_Printf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
2459         }
2460         if (!shadercompiled)
2461         {
2462                 qglDeleteShader(shaderobject);CHECKGLERROR
2463                 return false;
2464         }
2465         qglAttachShader(programobject, shaderobject);CHECKGLERROR
2466         qglDeleteShader(shaderobject);CHECKGLERROR
2467         return true;
2468 }
2469
2470 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)
2471 {
2472         GLint programlinked;
2473         GLuint programobject = 0;
2474         char linklog[MAX_INPUTLINE];
2475         CHECKGLERROR
2476
2477         programobject = qglCreateProgram();CHECKGLERROR
2478         if (!programobject)
2479                 return 0;
2480
2481         qglBindAttribLocation(programobject, GLSLATTRIB_POSITION , "Attrib_Position" );
2482         qglBindAttribLocation(programobject, GLSLATTRIB_COLOR    , "Attrib_Color"    );
2483         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD0, "Attrib_TexCoord0");
2484         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD1, "Attrib_TexCoord1");
2485         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD2, "Attrib_TexCoord2");
2486         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD3, "Attrib_TexCoord3");
2487         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD4, "Attrib_TexCoord4");
2488         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD5, "Attrib_TexCoord5");
2489         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD6, "Attrib_TexCoord6");
2490         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD7, "Attrib_TexCoord7");
2491         if(vid.support.gl20shaders130)
2492                 qglBindFragDataLocation(programobject, 0, "dp_FragColor");
2493
2494         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER, "vertex", vertexstrings_count, vertexstrings_list))
2495                 goto cleanup;
2496
2497 #ifdef GL_GEOMETRY_SHADER
2498         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER, "geometry", geometrystrings_count, geometrystrings_list))
2499                 goto cleanup;
2500 #endif
2501
2502         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER, "fragment", fragmentstrings_count, fragmentstrings_list))
2503                 goto cleanup;
2504
2505         qglLinkProgram(programobject);CHECKGLERROR
2506         qglGetProgramiv(programobject, GL_LINK_STATUS, &programlinked);CHECKGLERROR
2507         qglGetProgramInfoLog(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
2508         if (linklog[0])
2509         {
2510                 if (strstr(linklog, "error") || strstr(linklog, "ERROR") || strstr(linklog, "Error") || strstr(linklog, "WARNING") || strstr(linklog, "warning") || strstr(linklog, "Warning"))
2511                         Con_DPrintf("program link log:\n%s\n", linklog);
2512                 // software vertex shader is ok but software fragment shader is WAY
2513                 // too slow, fail program if so.
2514                 // NOTE: this string might be ATI specific, but that's ok because the
2515                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
2516                 // software fragment shader due to low instruction and dependent
2517                 // texture limits.
2518                 if (strstr(linklog, "fragment shader will run in software"))
2519                         programlinked = false;
2520         }
2521         if (!programlinked)
2522                 goto cleanup;
2523         return programobject;
2524 cleanup:
2525         qglDeleteProgram(programobject);CHECKGLERROR
2526         return 0;
2527 }
2528
2529 void GL_Backend_FreeProgram(unsigned int prog)
2530 {
2531         CHECKGLERROR
2532         qglDeleteProgram(prog);
2533         CHECKGLERROR
2534 }
2535
2536 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
2537 {
2538         int i;
2539         if (offset)
2540         {
2541                 for (i = 0;i < count;i++)
2542                         *out++ = *in++ + offset;
2543         }
2544         else
2545                 memcpy(out, in, sizeof(*out) * count);
2546 }
2547
2548 // renders triangles using vertices from the active arrays
2549 int paranoidblah = 0;
2550 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)
2551 {
2552         unsigned int numelements = numtriangles * 3;
2553         int bufferobject3i;
2554         size_t bufferoffset3i;
2555         int bufferobject3s;
2556         size_t bufferoffset3s;
2557         if (numvertices < 3 || numtriangles < 1)
2558         {
2559                 if (numvertices < 0 || numtriangles < 0 || developer_extra.integer)
2560                         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);
2561                 return;
2562         }
2563         if (!gl_mesh_prefer_short_elements.integer)
2564         {
2565                 if (element3i)
2566                         element3s = NULL;
2567                 if (element3i_indexbuffer)
2568                         element3i_indexbuffer = NULL;
2569         }
2570         // adjust the pointers for firsttriangle
2571         if (element3i)
2572                 element3i += firsttriangle * 3;
2573         if (element3i_indexbuffer)
2574                 element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i);
2575         if (element3s)
2576                 element3s += firsttriangle * 3;
2577         if (element3s_indexbuffer)
2578                 element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
2579         switch(vid.renderpath)
2580         {
2581         case RENDERPATH_GL11:
2582         case RENDERPATH_GL13:
2583         case RENDERPATH_GL20:
2584         case RENDERPATH_GLES1:
2585         case RENDERPATH_GLES2:
2586                 // check if the user specified to ignore static index buffers
2587                 if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset)))
2588                 {
2589                         element3i_indexbuffer = NULL;
2590                         element3s_indexbuffer = NULL;
2591                 }
2592                 break;
2593         case RENDERPATH_D3D9:
2594         case RENDERPATH_D3D10:
2595         case RENDERPATH_D3D11:
2596                 break;
2597         case RENDERPATH_SOFT:
2598                 break;
2599         }
2600         // upload a dynamic index buffer if needed
2601         if (element3s)
2602         {
2603                 if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex)
2604                 {
2605                         if (gl_state.draw_dynamicindexbuffer)
2606                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3s, numelements * sizeof(*element3s));
2607                         else
2608                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3s, numelements * sizeof(*element3s), "temporary", true, true, true);
2609                         element3s_indexbuffer = gl_state.draw_dynamicindexbuffer;
2610                         element3s_bufferoffset = 0;
2611                 }
2612         }
2613         else if (element3i)
2614         {
2615                 if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex)
2616                 {
2617                         if (gl_state.draw_dynamicindexbuffer)
2618                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3i, numelements * sizeof(*element3i));
2619                         else
2620                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3i, numelements * sizeof(*element3i), "temporary", true, true, false);
2621                         element3i_indexbuffer = gl_state.draw_dynamicindexbuffer;
2622                         element3i_bufferoffset = 0;
2623                 }
2624         }
2625         bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
2626         bufferoffset3i = element3i_bufferoffset;
2627         bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0;
2628         bufferoffset3s = element3s_bufferoffset;
2629         r_refdef.stats.draws++;
2630         r_refdef.stats.draws_vertices += numvertices;
2631         r_refdef.stats.draws_elements += numelements;
2632         if (gl_paranoid.integer)
2633         {
2634                 unsigned int i;
2635                 // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
2636 #if 0
2637                 unsigned int j, size;
2638                 const int *p;
2639                 // note: there's no validation done here on buffer objects because it
2640                 // is somewhat difficult to get at the data, and gl_paranoid can be
2641                 // used without buffer objects if the need arises
2642                 // (the data could be gotten using glMapBuffer but it would be very
2643                 //  slow due to uncachable video memory reads)
2644                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
2645                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
2646                 CHECKGLERROR
2647                 if (gl_state.pointer_vertex_pointer)
2648                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
2649                                 paranoidblah += *p;
2650                 if (gl_state.pointer_color_enabled)
2651                 {
2652                         if (!qglIsEnabled(GL_COLOR_ARRAY))
2653                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
2654                         CHECKGLERROR
2655                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
2656                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
2657                                         paranoidblah += *p;
2658                 }
2659                 for (i = 0;i < vid.texarrayunits;i++)
2660                 {
2661                         if (gl_state.units[i].arrayenabled)
2662                         {
2663                                 GL_ClientActiveTexture(i);
2664                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
2665                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
2666                                 CHECKGLERROR
2667                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
2668                                         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++)
2669                                                 paranoidblah += *p;
2670                         }
2671                 }
2672 #endif
2673                 if (element3i)
2674                 {
2675                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2676                         {
2677                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
2678                                 {
2679                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
2680                                         return;
2681                                 }
2682                         }
2683                 }
2684                 if (element3s)
2685                 {
2686                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2687                         {
2688                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
2689                                 {
2690                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
2691                                         return;
2692                                 }
2693                         }
2694                 }
2695         }
2696         if (r_render.integer || r_refdef.draw2dstage)
2697         {
2698                 switch(vid.renderpath)
2699                 {
2700                 case RENDERPATH_GL11:
2701                 case RENDERPATH_GL13:
2702                 case RENDERPATH_GL20:
2703                         CHECKGLERROR
2704                         if (gl_mesh_testmanualfeeding.integer)
2705                         {
2706                                 unsigned int i, j, element;
2707                                 const GLfloat *p;
2708                                 qglBegin(GL_TRIANGLES);
2709                                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2710                                 {
2711                                         if (element3i)
2712                                                 element = element3i[i];
2713                                         else if (element3s)
2714                                                 element = element3s[i];
2715                                         else
2716                                                 element = firstvertex + i;
2717                                         for (j = 0;j < vid.texarrayunits;j++)
2718                                         {
2719                                                 if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
2720                                                 {
2721                                                         if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
2722                                                         {
2723                                                                 p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2724                                                                 if (vid.texarrayunits > 1)
2725                                                                 {
2726                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2727                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
2728                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2729                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
2730                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2731                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
2732                                                                         else
2733                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
2734                                                                 }
2735                                                                 else
2736                                                                 {
2737                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2738                                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
2739                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2740                                                                                 qglTexCoord3f(p[0], p[1], p[2]);
2741                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2742                                                                                 qglTexCoord2f(p[0], p[1]);
2743                                                                         else
2744                                                                                 qglTexCoord1f(p[0]);
2745                                                                 }
2746                                                         }
2747                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
2748                                                         {
2749                                                                 const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2750                                                                 if (vid.texarrayunits > 1)
2751                                                                 {
2752                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2753                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
2754                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2755                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]);
2756                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2757                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
2758                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2759                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
2760                                                                 }
2761                                                                 else
2762                                                                 {
2763                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2764                                                                                 qglTexCoord4f(s[0], s[1], s[2], s[3]);
2765                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2766                                                                                 qglTexCoord3f(s[0], s[1], s[2]);
2767                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2768                                                                                 qglTexCoord2f(s[0], s[1]);
2769                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2770                                                                                 qglTexCoord1f(s[0]);
2771                                                                 }
2772                                                         }
2773                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
2774                                                         {
2775                                                                 const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2776                                                                 if (vid.texarrayunits > 1)
2777                                                                 {
2778                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2779                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
2780                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2781                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]);
2782                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2783                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
2784                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2785                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
2786                                                                 }
2787                                                                 else
2788                                                                 {
2789                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2790                                                                                 qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
2791                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2792                                                                                 qglTexCoord3f(sb[0], sb[1], sb[2]);
2793                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2794                                                                                 qglTexCoord2f(sb[0], sb[1]);
2795                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2796                                                                                 qglTexCoord1f(sb[0]);
2797                                                                 }
2798                                                         }
2799                                                 }
2800                                         }
2801                                         if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
2802                                         {
2803                                                 if (gl_state.pointer_color_gltype == GL_FLOAT)
2804                                                 {
2805                                                         p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2806                                                         qglColor4f(p[0], p[1], p[2], p[3]);
2807                                                 }
2808                                                 else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
2809                                                 {
2810                                                         const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2811                                                         qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
2812                                                 }
2813                                         }
2814                                         if (gl_state.pointer_vertex_gltype == GL_FLOAT)
2815                                         {
2816                                                 p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
2817                                                 if (gl_state.pointer_vertex_components == 4)
2818                                                         qglVertex4f(p[0], p[1], p[2], p[3]);
2819                                                 else if (gl_state.pointer_vertex_components == 3)
2820                                                         qglVertex3f(p[0], p[1], p[2]);
2821                                                 else
2822                                                         qglVertex2f(p[0], p[1]);
2823                                         }
2824                                 }
2825                                 qglEnd();
2826                                 CHECKGLERROR
2827                         }
2828                         else if (bufferobject3s)
2829                         {
2830                                 GL_BindEBO(bufferobject3s);
2831                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2832                                 {
2833                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
2834                                         CHECKGLERROR
2835                                 }
2836                                 else
2837                                 {
2838                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
2839                                         CHECKGLERROR
2840                                 }
2841                         }
2842                         else if (bufferobject3i)
2843                         {
2844                                 GL_BindEBO(bufferobject3i);
2845                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2846                                 {
2847                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
2848                                         CHECKGLERROR
2849                                 }
2850                                 else
2851                                 {
2852                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
2853                                         CHECKGLERROR
2854                                 }
2855                         }
2856                         else if (element3s)
2857                         {
2858                                 GL_BindEBO(0);
2859                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2860                                 {
2861                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
2862                                         CHECKGLERROR
2863                                 }
2864                                 else
2865                                 {
2866                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
2867                                         CHECKGLERROR
2868                                 }
2869                         }
2870                         else if (element3i)
2871                         {
2872                                 GL_BindEBO(0);
2873                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2874                                 {
2875                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
2876                                         CHECKGLERROR
2877                                 }
2878                                 else
2879                                 {
2880                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
2881                                         CHECKGLERROR
2882                                 }
2883                         }
2884                         else
2885                         {
2886                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
2887                                 CHECKGLERROR
2888                         }
2889                         break;
2890                 case RENDERPATH_D3D9:
2891 #ifdef SUPPORTD3D
2892                         if (gl_state.d3dvertexbuffer && ((element3s && element3s_indexbuffer) || (element3i && element3i_indexbuffer)))
2893                         {
2894                                 if (element3s_indexbuffer)
2895                                 {
2896                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3s_indexbuffer->devicebuffer);
2897                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3s_bufferoffset>>1, numtriangles);
2898                                 }
2899                                 else if (element3i_indexbuffer)
2900                                 {
2901                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3i_indexbuffer->devicebuffer);
2902                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3i_bufferoffset>>2, numtriangles);
2903                                 }
2904                                 else
2905                                         IDirect3DDevice9_DrawPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices);
2906                         }
2907                         else
2908                         {
2909                                 if (element3s)
2910                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3s, D3DFMT_INDEX16, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2911                                 else if (element3i)
2912                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3i, D3DFMT_INDEX32, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2913                                 else
2914                                         IDirect3DDevice9_DrawPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, numvertices, (void *)gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2915                         }
2916 #endif
2917                         break;
2918                 case RENDERPATH_D3D10:
2919                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2920                         break;
2921                 case RENDERPATH_D3D11:
2922                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2923                         break;
2924                 case RENDERPATH_SOFT:
2925                         DPSOFTRAST_DrawTriangles(firstvertex, numvertices, numtriangles, element3i, element3s);
2926                         break;
2927                 case RENDERPATH_GLES1:
2928                 case RENDERPATH_GLES2:
2929                         // GLES does not have glDrawRangeElements, and generally
2930                         // underperforms with index buffers, so this code path is
2931                         // relatively straightforward...
2932 #if 0
2933                         if (gl_paranoid.integer)
2934                         {
2935                                 int r, prog, enabled, i;
2936                                 GLsizei         attriblength;
2937                                 GLint           attribsize;
2938                                 GLenum          attribtype;
2939                                 GLchar          attribname[1024];
2940                                 r = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2941                                 if (r != GL_FRAMEBUFFER_COMPLETE_EXT)
2942                                         Con_DPrintf("fbo %i not complete (default %i)\n", gl_state.framebufferobject, gl_state.defaultframebufferobject);
2943 #ifndef GL_CURRENT_PROGRAM
2944 #define GL_CURRENT_PROGRAM 0x8B8D
2945 #endif
2946                                 qglGetIntegerv(GL_CURRENT_PROGRAM, &r);CHECKGLERROR
2947                                 if (r < 0 || r > 10000)
2948                                         Con_DPrintf("GL_CURRENT_PROGRAM = %i\n", r);
2949                                 prog = r;
2950                                 for (i = 0;i < 8;i++)
2951                                 {
2952                                         qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &r);CHECKGLERROR
2953                                         if (!r)
2954                                                 continue;
2955                                         qglGetActiveAttrib(prog, i, sizeof(attribname), &attriblength, &attribsize, &attribtype, attribname);CHECKGLERROR
2956                                         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);
2957                                 }
2958                         }
2959 #endif
2960                         if (element3s)
2961                         {
2962                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
2963                                 CHECKGLERROR
2964                         }
2965                         else if (element3i)
2966                         {
2967                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
2968                                 CHECKGLERROR
2969                         }
2970                         else
2971                         {
2972                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
2973                                 CHECKGLERROR
2974                         }
2975                         break;
2976                 }
2977         }
2978 }
2979
2980 // restores backend state, used when done with 3D rendering
2981 void R_Mesh_Finish(void)
2982 {
2983         R_Mesh_ResetRenderTargets();
2984 }
2985
2986 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic, qboolean isindex16)
2987 {
2988         r_meshbuffer_t *buffer;
2989         if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex)))
2990                 return NULL;
2991         buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
2992         memset(buffer, 0, sizeof(*buffer));
2993         buffer->bufferobject = 0;
2994         buffer->devicebuffer = NULL;
2995         buffer->size = 0;
2996         buffer->isindexbuffer = isindexbuffer;
2997         buffer->isdynamic = isdynamic;
2998         buffer->isindex16 = isindex16;
2999         strlcpy(buffer->name, name, sizeof(buffer->name));
3000         R_Mesh_UpdateMeshBuffer(buffer, data, size);
3001         return buffer;
3002 }
3003
3004 void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size)
3005 {
3006         if (!buffer)
3007                 return;
3008         if (buffer->isindexbuffer)
3009         {
3010                 r_refdef.stats.indexbufferuploadcount++;
3011                 r_refdef.stats.indexbufferuploadsize += size;
3012         }
3013         else
3014         {
3015                 r_refdef.stats.vertexbufferuploadcount++;
3016                 r_refdef.stats.vertexbufferuploadsize += size;
3017         }
3018         switch(vid.renderpath)
3019         {
3020         case RENDERPATH_GL11:
3021         case RENDERPATH_GL13:
3022         case RENDERPATH_GL20:
3023         case RENDERPATH_GLES1:
3024         case RENDERPATH_GLES2:
3025                 if (!buffer->bufferobject)
3026                         qglGenBuffersARB(1, (GLuint *)&buffer->bufferobject);
3027                 if (buffer->isindexbuffer)
3028                         GL_BindEBO(buffer->bufferobject);
3029                 else
3030                         GL_BindVBO(buffer->bufferobject);
3031                 qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
3032                 break;
3033         case RENDERPATH_D3D9:
3034 #ifdef SUPPORTD3D
3035                 {
3036                         int result;
3037                         void *datapointer = NULL;
3038                         if (buffer->isindexbuffer)
3039                         {
3040                                 IDirect3DIndexBuffer9 *d3d9indexbuffer = (IDirect3DIndexBuffer9 *)buffer->devicebuffer;
3041                                 if (size > buffer->size || !buffer->devicebuffer)
3042                                 {
3043                                         if (buffer->devicebuffer)
3044                                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer);
3045                                         buffer->devicebuffer = NULL;
3046                                         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)))
3047                                                 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);
3048                                         buffer->devicebuffer = (void *)d3d9indexbuffer;
3049                                         buffer->size = size;
3050                                 }
3051                                 if (!FAILED(IDirect3DIndexBuffer9_Lock(d3d9indexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
3052                                 {
3053                                         if (data)
3054                                                 memcpy(datapointer, data, size);
3055                                         else
3056                                                 memset(datapointer, 0, size);
3057                                         IDirect3DIndexBuffer9_Unlock(d3d9indexbuffer);
3058                                 }
3059                         }
3060                         else
3061                         {
3062                                 IDirect3DVertexBuffer9 *d3d9vertexbuffer = (IDirect3DVertexBuffer9 *)buffer->devicebuffer;
3063                                 if (size > buffer->size || !buffer->devicebuffer)
3064                                 {
3065                                         if (buffer->devicebuffer)
3066                                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer);
3067                                         buffer->devicebuffer = NULL;
3068                                         if (FAILED(result = IDirect3DDevice9_CreateVertexBuffer(vid_d3d9dev, size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9vertexbuffer, NULL)))
3069                                                 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);
3070                                         buffer->devicebuffer = (void *)d3d9vertexbuffer;
3071                                         buffer->size = size;
3072                                 }
3073                                 if (!FAILED(IDirect3DVertexBuffer9_Lock(d3d9vertexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
3074                                 {
3075                                         if (data)
3076                                                 memcpy(datapointer, data, size);
3077                                         else
3078                                                 memset(datapointer, 0, size);
3079                                         IDirect3DVertexBuffer9_Unlock(d3d9vertexbuffer);
3080                                 }
3081                         }
3082                 }
3083 #endif
3084                 break;
3085         case RENDERPATH_D3D10:
3086                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3087                 break;
3088         case RENDERPATH_D3D11:
3089                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3090                 break;
3091         case RENDERPATH_SOFT:
3092                 break;
3093         }
3094 }
3095
3096 void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
3097 {
3098         if (!buffer)
3099                 return;
3100         switch(vid.renderpath)
3101         {
3102         case RENDERPATH_GL11:
3103         case RENDERPATH_GL13:
3104         case RENDERPATH_GL20:
3105         case RENDERPATH_GLES1:
3106         case RENDERPATH_GLES2:
3107                 qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject);
3108                 break;
3109         case RENDERPATH_D3D9:
3110 #ifdef SUPPORTD3D
3111                 if (gl_state.d3dvertexbuffer == (void *)buffer)
3112                         gl_state.d3dvertexbuffer = NULL;
3113                 if (buffer->devicebuffer)
3114                 {
3115                         if (buffer->isindexbuffer)
3116                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9 *)buffer->devicebuffer);
3117                         else
3118                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9 *)buffer->devicebuffer);
3119                         buffer->devicebuffer = NULL;
3120                 }
3121 #endif
3122                 break;
3123         case RENDERPATH_D3D10:
3124                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3125                 break;
3126         case RENDERPATH_D3D11:
3127                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3128                 break;
3129         case RENDERPATH_SOFT:
3130                 break;
3131         }
3132         Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
3133 }
3134
3135 void GL_Mesh_ListVBOs(qboolean printeach)
3136 {
3137         int i, endindex;
3138         size_t ebocount = 0, ebomemory = 0;
3139         size_t vbocount = 0, vbomemory = 0;
3140         r_meshbuffer_t *buffer;
3141         endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
3142         for (i = 0;i < endindex;i++)
3143         {
3144                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
3145                 if (!buffer)
3146                         continue;
3147                 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)");}
3148                 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)");}
3149         }
3150         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);
3151 }
3152
3153
3154
3155 void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
3156 {
3157         switch(vid.renderpath)
3158         {
3159         case RENDERPATH_GL11:
3160         case RENDERPATH_GL13:
3161         case RENDERPATH_GLES1:
3162                 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)
3163                 {
3164                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3165                         gl_state.pointer_vertex_components = components;
3166                         gl_state.pointer_vertex_gltype = gltype;
3167                         gl_state.pointer_vertex_stride = stride;
3168                         gl_state.pointer_vertex_pointer = pointer;
3169                         gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
3170                         gl_state.pointer_vertex_offset = bufferoffset;
3171                         CHECKGLERROR
3172                         GL_BindVBO(bufferobject);
3173                         qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3174                 }
3175                 break;
3176         case RENDERPATH_GL20:
3177         case RENDERPATH_GLES2:
3178                 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)
3179                 {
3180                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3181                         gl_state.pointer_vertex_components = components;
3182                         gl_state.pointer_vertex_gltype = gltype;
3183                         gl_state.pointer_vertex_stride = stride;
3184                         gl_state.pointer_vertex_pointer = pointer;
3185                         gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
3186                         gl_state.pointer_vertex_offset = bufferoffset;
3187                         CHECKGLERROR
3188                         GL_BindVBO(bufferobject);
3189                         qglVertexAttribPointer(GLSLATTRIB_POSITION, components, gltype, false, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3190                 }
3191                 break;
3192         case RENDERPATH_D3D9:
3193         case RENDERPATH_D3D10:
3194         case RENDERPATH_D3D11:
3195         case RENDERPATH_SOFT:
3196                 break;
3197         }
3198 }
3199
3200 void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
3201 {
3202         // note: vertexbuffer may be non-NULL even if pointer is NULL, so check
3203         // the pointer only.
3204         switch(vid.renderpath)
3205         {
3206         case RENDERPATH_GL11:
3207         case RENDERPATH_GL13:
3208         case RENDERPATH_GLES1:
3209                 CHECKGLERROR
3210                 if (pointer)
3211                 {
3212                         // caller wants color array enabled
3213                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3214                         if (!gl_state.pointer_color_enabled)
3215                         {
3216                                 gl_state.pointer_color_enabled = true;
3217                                 CHECKGLERROR
3218                                 qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
3219                         }
3220                         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)
3221                         {
3222                                 gl_state.pointer_color_components = components;
3223                                 gl_state.pointer_color_gltype = gltype;
3224                                 gl_state.pointer_color_stride = stride;
3225                                 gl_state.pointer_color_pointer = pointer;
3226                                 gl_state.pointer_color_vertexbuffer = vertexbuffer;
3227                                 gl_state.pointer_color_offset = bufferoffset;
3228                                 CHECKGLERROR
3229                                 GL_BindVBO(bufferobject);
3230                                 qglColorPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3231                         }
3232                 }
3233                 else
3234                 {
3235                         // caller wants color array disabled
3236                         if (gl_state.pointer_color_enabled)
3237                         {
3238                                 gl_state.pointer_color_enabled = false;
3239                                 CHECKGLERROR
3240                                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
3241                                 // when color array is on the glColor gets trashed, set it again
3242                                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
3243                         }
3244                 }
3245                 break;
3246         case RENDERPATH_GL20:
3247         case RENDERPATH_GLES2:
3248                 CHECKGLERROR
3249                 if (pointer)
3250                 {
3251                         // caller wants color array enabled
3252                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3253                         if (!gl_state.pointer_color_enabled)
3254                         {
3255                                 gl_state.pointer_color_enabled = true;
3256                                 CHECKGLERROR
3257                                 qglEnableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR
3258                         }
3259                         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)
3260                         {
3261                                 gl_state.pointer_color_components = components;
3262                                 gl_state.pointer_color_gltype = gltype;
3263                                 gl_state.pointer_color_stride = stride;
3264                                 gl_state.pointer_color_pointer = pointer;
3265                                 gl_state.pointer_color_vertexbuffer = vertexbuffer;
3266                                 gl_state.pointer_color_offset = bufferoffset;
3267                                 CHECKGLERROR
3268                                 GL_BindVBO(bufferobject);
3269                                 qglVertexAttribPointer(GLSLATTRIB_COLOR, components, gltype, false, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3270                         }
3271                 }
3272                 else
3273                 {
3274                         // caller wants color array disabled
3275                         if (gl_state.pointer_color_enabled)
3276                         {
3277                                 gl_state.pointer_color_enabled = false;
3278                                 CHECKGLERROR
3279                                 qglDisableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR
3280                                 // when color array is on the glColor gets trashed, set it again
3281                                 qglVertexAttrib4f(GLSLATTRIB_COLOR, gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
3282                         }
3283                 }
3284                 break;
3285         case RENDERPATH_D3D9:
3286         case RENDERPATH_D3D10:
3287         case RENDERPATH_D3D11:
3288         case RENDERPATH_SOFT:
3289                 break;
3290         }
3291 }
3292
3293 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)
3294 {
3295         gltextureunit_t *unit = gl_state.units + unitnum;
3296         // update array settings
3297         // note: there is no need to check bufferobject here because all cases
3298         // that involve a valid bufferobject also supply a texcoord array
3299         switch(vid.renderpath)
3300         {
3301         case RENDERPATH_GL11:
3302         case RENDERPATH_GL13:
3303         case RENDERPATH_GLES1:
3304                 CHECKGLERROR
3305                 if (pointer)
3306                 {
3307                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3308                         // texture array unit is enabled, enable the array
3309                         if (!unit->arrayenabled)
3310                         {
3311                                 unit->arrayenabled = true;
3312                                 GL_ClientActiveTexture(unitnum);
3313                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
3314                         }
3315                         // texcoord array
3316                         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)
3317                         {
3318                                 unit->pointer_texcoord_components = components;
3319                                 unit->pointer_texcoord_gltype = gltype;
3320                                 unit->pointer_texcoord_stride = stride;
3321                                 unit->pointer_texcoord_pointer = pointer;
3322                                 unit->pointer_texcoord_vertexbuffer = vertexbuffer;
3323                                 unit->pointer_texcoord_offset = bufferoffset;
3324                                 GL_ClientActiveTexture(unitnum);
3325                                 GL_BindVBO(bufferobject);
3326                                 qglTexCoordPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3327                         }
3328                 }
3329                 else
3330                 {
3331                         // texture array unit is disabled, disable the array
3332                         if (unit->arrayenabled)
3333                         {
3334                                 unit->arrayenabled = false;
3335                                 GL_ClientActiveTexture(unitnum);
3336                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
3337                         }
3338                 }
3339                 break;
3340         case RENDERPATH_GL20:
3341         case RENDERPATH_GLES2:
3342                 CHECKGLERROR
3343                 if (pointer)
3344                 {
3345                         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3346                         // texture array unit is enabled, enable the array
3347                         if (!unit->arrayenabled)
3348                         {
3349                                 unit->arrayenabled = true;
3350                                 qglEnableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
3351                         }
3352                         // texcoord array
3353                         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)
3354                         {
3355                                 unit->pointer_texcoord_components = components;
3356                                 unit->pointer_texcoord_gltype = gltype;
3357                                 unit->pointer_texcoord_stride = stride;
3358                                 unit->pointer_texcoord_pointer = pointer;
3359                                 unit->pointer_texcoord_vertexbuffer = vertexbuffer;
3360                                 unit->pointer_texcoord_offset = bufferoffset;
3361                                 GL_BindVBO(bufferobject);
3362                                 qglVertexAttribPointer(unitnum+GLSLATTRIB_TEXCOORD0, components, gltype, false, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3363                         }
3364                 }
3365                 else
3366                 {
3367                         // texture array unit is disabled, disable the array
3368                         if (unit->arrayenabled)
3369                         {
3370                                 unit->arrayenabled = false;
3371                                 qglDisableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
3372                         }
3373                 }
3374                 break;
3375         case RENDERPATH_D3D9:
3376         case RENDERPATH_D3D10:
3377         case RENDERPATH_D3D11:
3378         case RENDERPATH_SOFT:
3379                 break;
3380         }
3381 }
3382
3383 int R_Mesh_TexBound(unsigned int unitnum, int id)
3384 {
3385         gltextureunit_t *unit = gl_state.units + unitnum;
3386         if (unitnum >= vid.teximageunits)
3387                 return 0;
3388         if (id == GL_TEXTURE_2D)
3389                 return unit->t2d;
3390         if (id == GL_TEXTURE_3D)
3391                 return unit->t3d;
3392         if (id == GL_TEXTURE_CUBE_MAP_ARB)
3393                 return unit->tcubemap;
3394         return 0;
3395 }
3396
3397 void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int width, int height)
3398 {
3399         switch(vid.renderpath)
3400         {
3401         case RENDERPATH_GL11:
3402         case RENDERPATH_GL13:
3403         case RENDERPATH_GL20:
3404         case RENDERPATH_GLES1:
3405         case RENDERPATH_GLES2:
3406                 R_Mesh_TexBind(0, tex);
3407                 GL_ActiveTexture(0);CHECKGLERROR
3408                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, sx, sy, width, height);CHECKGLERROR
3409                 break;
3410         case RENDERPATH_D3D9:
3411 #ifdef SUPPORTD3D
3412                 {
3413                         IDirect3DSurface9 *currentsurface = NULL;
3414                         IDirect3DSurface9 *texturesurface = NULL;
3415                         RECT sourcerect;
3416                         RECT destrect;
3417                         sourcerect.left = sx;
3418                         sourcerect.top = sy;
3419                         sourcerect.right = sx + width;
3420                         sourcerect.bottom = sy + height;
3421                         destrect.left = tx;
3422                         destrect.top = ty;
3423                         destrect.right = tx + width;
3424                         destrect.bottom = ty + height;
3425                         if (!FAILED(IDirect3DTexture9_GetSurfaceLevel(((IDirect3DTexture9 *)tex->d3dtexture), 0, &texturesurface)))
3426                         {
3427                                 if (!FAILED(IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &currentsurface)))
3428                                 {
3429                                         IDirect3DDevice9_StretchRect(vid_d3d9dev, currentsurface, &sourcerect, texturesurface, &destrect, D3DTEXF_NONE);
3430                                         IDirect3DSurface9_Release(currentsurface);
3431                                 }
3432                                 IDirect3DSurface9_Release(texturesurface);
3433                         }
3434                 }
3435 #endif
3436                 break;
3437         case RENDERPATH_D3D10:
3438                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3439                 break;
3440         case RENDERPATH_D3D11:
3441                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3442                 break;
3443         case RENDERPATH_SOFT:
3444                 DPSOFTRAST_CopyRectangleToTexture(tex->texnum, 0, tx, ty, sx, sy, width, height);
3445                 break;
3446         }
3447 }
3448
3449 #ifdef SUPPORTD3D
3450 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};
3451 #endif
3452
3453 void R_Mesh_ClearBindingsForTexture(int texnum)
3454 {
3455         gltextureunit_t *unit;
3456         unsigned int unitnum;
3457         // 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)
3458         for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
3459         {
3460                 unit = gl_state.units + unitnum;
3461                 if (unit->t2d == texnum)
3462                         unit->t2d = -1;
3463                 if (unit->t3d == texnum)
3464                         unit->t3d = -1;
3465                 if (unit->tcubemap == texnum)
3466                         unit->tcubemap = -1;
3467         }
3468 }
3469
3470 void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
3471 {
3472         gltextureunit_t *unit = gl_state.units + unitnum;
3473         int tex2d, tex3d, texcubemap, texnum;
3474         if (unitnum >= vid.teximageunits)
3475                 return;
3476 //      if (unit->texture == tex)
3477 //              return;
3478         switch(vid.renderpath)
3479         {
3480         case RENDERPATH_GL20:
3481         case RENDERPATH_GLES2:
3482                 if (!tex)
3483                 {
3484                         tex = r_texture_white;
3485                         // not initialized enough yet...
3486                         if (!tex)
3487                                 return;
3488                 }
3489                 unit->texture = tex;
3490                 texnum = R_GetTexture(tex);
3491                 switch(tex->gltexturetypeenum)
3492                 {
3493                 case GL_TEXTURE_2D: if (unit->t2d != texnum) {GL_ActiveTexture(unitnum);unit->t2d = texnum;qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR}break;
3494                 case GL_TEXTURE_3D: if (unit->t3d != texnum) {GL_ActiveTexture(unitnum);unit->t3d = texnum;qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR}break;
3495                 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;
3496                 }
3497                 break;
3498         case RENDERPATH_GL11:
3499         case RENDERPATH_GL13:
3500         case RENDERPATH_GLES1:
3501                 unit->texture = tex;
3502                 tex2d = 0;
3503                 tex3d = 0;
3504                 texcubemap = 0;
3505                 if (tex)
3506                 {
3507                         texnum = R_GetTexture(tex);
3508                         switch(tex->gltexturetypeenum)
3509                         {
3510                         case GL_TEXTURE_2D:
3511                                 tex2d = texnum;
3512                                 break;
3513                         case GL_TEXTURE_3D:
3514                                 tex3d = texnum;
3515                                 break;
3516                         case GL_TEXTURE_CUBE_MAP_ARB:
3517                                 texcubemap = texnum;
3518                                 break;
3519                         }
3520                 }
3521                 // update 2d texture binding
3522                 if (unit->t2d != tex2d)
3523                 {
3524                         GL_ActiveTexture(unitnum);
3525                         if (tex2d)
3526                         {
3527                                 if (unit->t2d == 0)
3528                                 {
3529                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
3530                                 }
3531                         }
3532                         else
3533                         {
3534                                 if (unit->t2d)
3535                                 {
3536                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
3537                                 }
3538                         }
3539                         unit->t2d = tex2d;
3540                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
3541                 }
3542                 // update 3d texture binding
3543                 if (unit->t3d != tex3d)
3544                 {
3545                         GL_ActiveTexture(unitnum);
3546                         if (tex3d)
3547                         {
3548                                 if (unit->t3d == 0)
3549                                 {
3550                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
3551                                 }
3552                         }
3553                         else
3554                         {
3555                                 if (unit->t3d)
3556                                 {
3557                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
3558                                 }
3559                         }
3560                         unit->t3d = tex3d;
3561                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
3562                 }
3563                 // update cubemap texture binding
3564                 if (unit->tcubemap != texcubemap)
3565                 {
3566                         GL_ActiveTexture(unitnum);
3567                         if (texcubemap)
3568                         {
3569                                 if (unit->tcubemap == 0)
3570                                 {
3571                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
3572                                 }
3573                         }
3574                         else
3575                         {
3576                                 if (unit->tcubemap)
3577                                 {
3578                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
3579                                 }
3580                         }
3581                         unit->tcubemap = texcubemap;
3582                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
3583                 }
3584                 break;
3585         case RENDERPATH_D3D9:
3586 #ifdef SUPPORTD3D
3587                 {
3588                         extern cvar_t gl_texture_anisotropy;
3589                         if (!tex)
3590                         {
3591                                 tex = r_texture_white;
3592                                 // not initialized enough yet...
3593                                 if (!tex)
3594                                         return;
3595                         }
3596                         // upload texture if needed
3597                         R_GetTexture(tex);
3598                         if (unit->texture == tex)
3599                                 return;
3600                         unit->texture = tex;
3601                         IDirect3DDevice9_SetTexture(vid_d3d9dev, unitnum, (IDirect3DBaseTexture9*)tex->d3dtexture);
3602                         //IDirect3DDevice9_SetRenderState(vid_d3d9dev, d3drswrap[unitnum], (tex->flags & TEXF_CLAMP) ? (D3DWRAPCOORD_0 | D3DWRAPCOORD_1 | D3DWRAPCOORD_2) : 0);
3603                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSU, tex->d3daddressu);
3604                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSV, tex->d3daddressv);
3605                         if (tex->d3daddressw)
3606                                 IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSW,  tex->d3daddressw);
3607                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAGFILTER, tex->d3dmagfilter);
3608                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MINFILTER, tex->d3dminfilter);
3609                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MIPFILTER, tex->d3dmipfilter);
3610                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MIPMAPLODBIAS, tex->d3dmipmaplodbias);
3611                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAXMIPLEVEL, tex->d3dmaxmiplevelfilter);
3612                         IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAXANISOTROPY, gl_texture_anisotropy.integer);
3613                 }
3614 #endif
3615                 break;
3616         case RENDERPATH_D3D10:
3617                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3618                 break;
3619         case RENDERPATH_D3D11:
3620                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3621                 break;
3622         case RENDERPATH_SOFT:
3623                 if (!tex)
3624                 {
3625                         tex = r_texture_white;
3626                         // not initialized enough yet...
3627                         if (!tex)
3628                                 return;
3629                 }
3630                 texnum = R_GetTexture(tex);
3631                 if (unit->texture == tex)
3632                         return;
3633                 unit->texture = tex;
3634                 DPSOFTRAST_SetTexture(unitnum, texnum);
3635                 break;
3636         }
3637 }
3638
3639 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
3640 {
3641         gltextureunit_t *unit = gl_state.units + unitnum;
3642         switch(vid.renderpath)
3643         {
3644         case RENDERPATH_GL11:
3645         case RENDERPATH_GL13:
3646         case RENDERPATH_GL20:
3647         case RENDERPATH_GLES1:
3648         case RENDERPATH_GLES2:
3649                 if (matrix && matrix->m[3][3])
3650                 {
3651                         // texmatrix specified, check if it is different
3652                         if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
3653                         {
3654                                 float glmatrix[16];
3655                                 unit->texmatrixenabled = true;
3656                                 unit->matrix = *matrix;
3657                                 CHECKGLERROR
3658                                 Matrix4x4_ToArrayFloatGL(&unit->matrix, glmatrix);
3659                                 GL_ActiveTexture(unitnum);
3660                                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
3661                                 qglLoadMatrixf(glmatrix);CHECKGLERROR
3662                                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
3663                         }
3664                 }
3665                 else
3666                 {
3667                         // no texmatrix specified, revert to identity
3668                         if (unit->texmatrixenabled)
3669                         {
3670                                 unit->texmatrixenabled = false;
3671                                 unit->matrix = identitymatrix;
3672                                 CHECKGLERROR
3673                                 GL_ActiveTexture(unitnum);
3674                                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
3675                                 qglLoadIdentity();CHECKGLERROR
3676                                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
3677                         }
3678                 }
3679                 break;
3680         case RENDERPATH_D3D9:
3681         case RENDERPATH_D3D10:
3682         case RENDERPATH_D3D11:
3683                 break;
3684         case RENDERPATH_SOFT:
3685                 break;
3686         }
3687 }
3688
3689 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
3690 {
3691         gltextureunit_t *unit = gl_state.units + unitnum;
3692         CHECKGLERROR
3693         switch(vid.renderpath)
3694         {
3695         case RENDERPATH_GL20:
3696         case RENDERPATH_GLES2:
3697                 // do nothing
3698                 break;
3699         case RENDERPATH_GL13:
3700         case RENDERPATH_GLES1:
3701                 // GL_ARB_texture_env_combine
3702                 if (!combinergb)
3703                         combinergb = GL_MODULATE;
3704                 if (!combinealpha)
3705                         combinealpha = GL_MODULATE;
3706                 if (!rgbscale)
3707                         rgbscale = 1;
3708                 if (!alphascale)
3709                         alphascale = 1;
3710                 if (combinergb != combinealpha || rgbscale != 1 || alphascale != 1)
3711                 {
3712                         if (combinergb == GL_DECAL)
3713                                 combinergb = GL_INTERPOLATE_ARB;
3714                         if (unit->combine != GL_COMBINE_ARB)
3715                         {
3716                                 unit->combine = GL_COMBINE_ARB;
3717                                 GL_ActiveTexture(unitnum);
3718                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
3719                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
3720                         }
3721                         if (unit->combinergb != combinergb)
3722                         {
3723                                 unit->combinergb = combinergb;
3724                                 GL_ActiveTexture(unitnum);
3725                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
3726                         }
3727                         if (unit->combinealpha != combinealpha)
3728                         {
3729                                 unit->combinealpha = combinealpha;
3730                                 GL_ActiveTexture(unitnum);
3731                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
3732                         }
3733                         if (unit->rgbscale != rgbscale)
3734                         {
3735                                 unit->rgbscale = rgbscale;
3736                                 GL_ActiveTexture(unitnum);
3737                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, unit->rgbscale);CHECKGLERROR
3738                         }
3739                         if (unit->alphascale != alphascale)
3740                         {
3741                                 unit->alphascale = alphascale;
3742                                 GL_ActiveTexture(unitnum);
3743                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, unit->alphascale);CHECKGLERROR
3744                         }
3745                 }
3746                 else
3747                 {
3748                         if (unit->combine != combinergb)
3749                         {
3750                                 unit->combine = combinergb;
3751                                 GL_ActiveTexture(unitnum);
3752                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
3753                         }
3754                 }
3755                 break;
3756         case RENDERPATH_GL11:
3757                 // normal GL texenv
3758                 if (!combinergb)
3759                         combinergb = GL_MODULATE;
3760                 if (unit->combine != combinergb)
3761                 {
3762                         unit->combine = combinergb;
3763                         GL_ActiveTexture(unitnum);
3764                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
3765                 }
3766                 break;
3767         case RENDERPATH_D3D9:
3768         case RENDERPATH_D3D10:
3769         case RENDERPATH_D3D11:
3770                 break;
3771         case RENDERPATH_SOFT:
3772                 break;
3773         }
3774 }
3775
3776 void R_Mesh_ResetTextureState(void)
3777 {
3778         unsigned int unitnum;
3779
3780         BACKENDACTIVECHECK
3781
3782         for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
3783                 R_Mesh_TexBind(unitnum, NULL);
3784         for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++)
3785                 R_Mesh_TexCoordPointer(unitnum, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3786         switch(vid.renderpath)
3787         {
3788         case RENDERPATH_GL20:
3789         case RENDERPATH_GLES2:
3790         case RENDERPATH_D3D9:
3791         case RENDERPATH_D3D10:
3792         case RENDERPATH_D3D11:
3793         case RENDERPATH_SOFT:
3794                 break;
3795         case RENDERPATH_GL11:
3796         case RENDERPATH_GL13:
3797         case RENDERPATH_GLES1:
3798                 for (unitnum = 0;unitnum < vid.texunits;unitnum++)
3799                 {
3800                         R_Mesh_TexCombine(unitnum, GL_MODULATE, GL_MODULATE, 1, 1);
3801                         R_Mesh_TexMatrix(unitnum, NULL);
3802                 }
3803                 break;
3804         }
3805 }
3806
3807
3808
3809 #ifdef SUPPORTD3D
3810 //#define r_vertex3f_d3d9fvf (D3DFVF_XYZ)
3811 //#define r_vertexgeneric_d3d9fvf (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
3812 //#define r_vertexmesh_d3d9fvf (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX5 | D3DFVF_TEXCOORDSIZE1(3) | D3DFVF_TEXCOORDSIZE2(3) | D3DFVF_TEXCOORDSIZE3(3))
3813
3814 D3DVERTEXELEMENT9 r_vertex3f_d3d9elements[] =
3815 {
3816         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3817         D3DDECL_END()
3818 };
3819
3820 D3DVERTEXELEMENT9 r_vertexgeneric_d3d9elements[] =
3821 {
3822         {0, (int)((size_t)&((r_vertexgeneric_t *)0)->vertex3f  ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3823         {0, (int)((size_t)&((r_vertexgeneric_t *)0)->color4f   ), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
3824         {0, (int)((size_t)&((r_vertexgeneric_t *)0)->texcoord2f), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
3825         D3DDECL_END()
3826 };
3827
3828 D3DVERTEXELEMENT9 r_vertexmesh_d3d9elements[] =
3829 {
3830         {0, (int)((size_t)&((r_vertexmesh_t *)0)->vertex3f          ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3831         {0, (int)((size_t)&((r_vertexmesh_t *)0)->color4f           ), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
3832         {0, (int)((size_t)&((r_vertexmesh_t *)0)->texcoordtexture2f ), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
3833         {0, (int)((size_t)&((r_vertexmesh_t *)0)->svector3f         ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
3834         {0, (int)((size_t)&((r_vertexmesh_t *)0)->tvector3f         ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2},
3835         {0, (int)((size_t)&((r_vertexmesh_t *)0)->normal3f          ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3},
3836         {0, (int)((size_t)&((r_vertexmesh_t *)0)->texcoordlightmap2f), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4},
3837         D3DDECL_END()
3838 };
3839
3840 IDirect3DVertexDeclaration9 *r_vertex3f_d3d9decl;
3841 IDirect3DVertexDeclaration9 *r_vertexgeneric_d3d9decl;
3842 IDirect3DVertexDeclaration9 *r_vertexmesh_d3d9decl;
3843 #endif
3844
3845 static void R_Mesh_InitVertexDeclarations(void)
3846 {
3847 #ifdef SUPPORTD3D
3848         r_vertex3f_d3d9decl = NULL;
3849         r_vertexgeneric_d3d9decl = NULL;
3850         r_vertexmesh_d3d9decl = NULL;
3851         switch(vid.renderpath)
3852         {
3853         case RENDERPATH_GL20:
3854         case RENDERPATH_GL13:
3855         case RENDERPATH_GL11:
3856         case RENDERPATH_GLES1:
3857         case RENDERPATH_GLES2:
3858                 break;
3859         case RENDERPATH_D3D9:
3860                 IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertex3f_d3d9elements, &r_vertex3f_d3d9decl);
3861                 IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexgeneric_d3d9elements, &r_vertexgeneric_d3d9decl);
3862                 IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexmesh_d3d9elements, &r_vertexmesh_d3d9decl);
3863                 break;
3864         case RENDERPATH_D3D10:
3865                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3866                 break;
3867         case RENDERPATH_D3D11:
3868                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3869                 break;
3870         case RENDERPATH_SOFT:
3871                 break;
3872         }
3873 #endif
3874 }
3875
3876 static void R_Mesh_DestroyVertexDeclarations(void)
3877 {
3878 #ifdef SUPPORTD3D
3879         if (r_vertex3f_d3d9decl)
3880                 IDirect3DVertexDeclaration9_Release(r_vertex3f_d3d9decl);
3881         r_vertex3f_d3d9decl = NULL;
3882         if (r_vertexgeneric_d3d9decl)
3883                 IDirect3DVertexDeclaration9_Release(r_vertexgeneric_d3d9decl);
3884         r_vertexgeneric_d3d9decl = NULL;
3885         if (r_vertexmesh_d3d9decl)
3886                 IDirect3DVertexDeclaration9_Release(r_vertexmesh_d3d9decl);
3887         r_vertexmesh_d3d9decl = NULL;
3888 #endif
3889 }
3890
3891 void R_Mesh_PrepareVertices_Vertex3f(int numvertices, const float *vertex3f, const r_meshbuffer_t *vertexbuffer)
3892 {
3893         // upload temporary vertexbuffer for this rendering
3894         if (!gl_state.usevbo_staticvertex)
3895                 vertexbuffer = NULL;
3896         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
3897         {
3898                 if (gl_state.preparevertices_dynamicvertexbuffer)
3899                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex3f, numvertices * sizeof(float[3]));
3900                 else
3901                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex3f, numvertices * sizeof(float[3]), "temporary", false, true, false);
3902                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
3903         }
3904         switch(vid.renderpath)
3905         {
3906         case RENDERPATH_GL20:
3907         case RENDERPATH_GLES2:
3908                 if (vertexbuffer)
3909                 {
3910                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3911                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3912                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3913                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3914                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3915                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3916                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3917                 }
3918                 else
3919                 {
3920                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3921                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3922                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3923                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3924                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3925                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3926                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3927                 }
3928                 break;
3929         case RENDERPATH_GL13:
3930         case RENDERPATH_GLES1:
3931                 if (vertexbuffer)
3932                 {
3933                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3934                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3935                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3936                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3937                 }
3938                 else
3939                 {
3940                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3941                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3942                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3943                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3944                 }
3945                 break;
3946         case RENDERPATH_GL11:
3947                 if (vertexbuffer)
3948                 {
3949                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3950                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3951                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3952                 }
3953                 else
3954                 {
3955                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
3956                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
3957                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
3958                 }
3959                 break;
3960         case RENDERPATH_D3D9:
3961 #ifdef SUPPORTD3D
3962                 IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertex3f_d3d9decl);
3963                 if (vertexbuffer)
3964                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, 0, sizeof(float[3]));
3965                 else
3966                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0);
3967                 gl_state.d3dvertexbuffer = (void *)vertexbuffer;
3968                 gl_state.d3dvertexdata = (void *)vertex3f;
3969                 gl_state.d3dvertexsize = sizeof(float[3]);
3970 #endif
3971                 break;
3972         case RENDERPATH_D3D10:
3973                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3974                 break;
3975         case RENDERPATH_D3D11:
3976                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3977                 break;
3978         case RENDERPATH_SOFT:
3979                 DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3]));
3980                 DPSOFTRAST_SetColorPointer(NULL, 0);
3981                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), NULL);
3982                 DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(float[2]), NULL);
3983                 DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(float[2]), NULL);
3984                 DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(float[2]), NULL);
3985                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), NULL);
3986                 break;
3987         }
3988 }
3989
3990
3991
3992 r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices)
3993 {
3994         size_t size;
3995         size = sizeof(r_vertexgeneric_t) * numvertices;
3996         if (gl_state.preparevertices_tempdatamaxsize < size)
3997         {
3998                 gl_state.preparevertices_tempdatamaxsize = size;
3999                 gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
4000         }
4001         gl_state.preparevertices_vertexgeneric = (r_vertexgeneric_t *)gl_state.preparevertices_tempdata;
4002         gl_state.preparevertices_numvertices = numvertices;
4003         return gl_state.preparevertices_vertexgeneric;
4004 }
4005
4006 qboolean R_Mesh_PrepareVertices_Generic_Unlock(void)
4007 {
4008         R_Mesh_PrepareVertices_Generic(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexgeneric, NULL);
4009         gl_state.preparevertices_vertexgeneric = NULL;
4010         gl_state.preparevertices_numvertices = 0;
4011         return true;
4012 }
4013
4014 void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f)
4015 {
4016         int i;
4017         r_vertexgeneric_t *vertex;
4018         switch(vid.renderpath)
4019         {
4020         case RENDERPATH_GL20:
4021         case RENDERPATH_GLES2:
4022                 if (!vid.useinterleavedarrays)
4023                 {
4024                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
4025                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
4026                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
4027                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4028                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4029                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4030                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4031                         return;
4032                 }
4033                 break;
4034         case RENDERPATH_GL11:
4035         case RENDERPATH_GL13:
4036         case RENDERPATH_GLES1:
4037                 if (!vid.useinterleavedarrays)
4038                 {
4039                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
4040                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
4041                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
4042                         if (vid.texunits >= 2)
4043                                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4044                         if (vid.texunits >= 3)
4045                                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4046                         return;
4047                 }
4048                 break;
4049         case RENDERPATH_D3D9:
4050         case RENDERPATH_D3D10:
4051         case RENDERPATH_D3D11:
4052                 break;
4053         case RENDERPATH_SOFT:
4054                 DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3]));
4055                 DPSOFTRAST_SetColorPointer(color4f, sizeof(float[4]));
4056                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), texcoord2f);
4057                 DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(float[2]), NULL);
4058                 DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(float[2]), NULL);
4059                 DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(float[2]), NULL);
4060                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), NULL);
4061                 return;
4062         }
4063
4064         // no quick path for this case, convert to vertex structs
4065         vertex = R_Mesh_PrepareVertices_Generic_Lock(numvertices);
4066         for (i = 0;i < numvertices;i++)
4067                 VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
4068         if (color4f)
4069         {
4070                 for (i = 0;i < numvertices;i++)
4071                         Vector4Copy(color4f + 4*i, vertex[i].color4f);
4072         }
4073         else
4074         {
4075                 for (i = 0;i < numvertices;i++)
4076                         Vector4Copy(gl_state.color4f, vertex[i].color4f);
4077         }
4078         if (texcoord2f)
4079                 for (i = 0;i < numvertices;i++)
4080                         Vector2Copy(texcoord2f + 2*i, vertex[i].texcoord2f);
4081         R_Mesh_PrepareVertices_Generic_Unlock();
4082         R_Mesh_PrepareVertices_Generic(numvertices, vertex, NULL);
4083 }
4084
4085 void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer)
4086 {
4087         // upload temporary vertexbuffer for this rendering
4088         if (!gl_state.usevbo_staticvertex)
4089                 vertexbuffer = NULL;
4090         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
4091         {
4092                 if (gl_state.preparevertices_dynamicvertexbuffer)
4093                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
4094                 else
4095                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true, false);
4096                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
4097         }
4098         switch(vid.renderpath)
4099         {
4100         case RENDERPATH_GL20:
4101         case RENDERPATH_GLES2:
4102                 if (vertexbuffer)
4103                 {
4104                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4105                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4106                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
4107                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4108                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4109                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4110                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4111                 }
4112                 else
4113                 {
4114                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4115                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4116                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
4117                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4118                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4119                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4120                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4121                 }
4122                 break;
4123         case RENDERPATH_GL13:
4124         case RENDERPATH_GLES1:
4125                 if (vertexbuffer)
4126                 {
4127                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4128                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4129                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
4130                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4131                 }
4132                 else
4133                 {
4134                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4135                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4136                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
4137                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4138                 }
4139                 break;
4140         case RENDERPATH_GL11:
4141                 if (vertexbuffer)
4142                 {
4143                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4144                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4145                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
4146                 }
4147                 else
4148                 {
4149                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4150                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4151                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
4152                 }
4153                 break;
4154         case RENDERPATH_D3D9:
4155 #ifdef SUPPORTD3D
4156                 IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertexgeneric_d3d9decl);
4157                 if (vertexbuffer)
4158                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, 0, sizeof(*vertex));
4159                 else
4160                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0);
4161                 gl_state.d3dvertexbuffer = (void *)vertexbuffer;
4162                 gl_state.d3dvertexdata = (void *)vertex;
4163                 gl_state.d3dvertexsize = sizeof(*vertex);
4164 #endif
4165                 break;
4166         case RENDERPATH_D3D10:
4167                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4168                 break;
4169         case RENDERPATH_D3D11:
4170                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4171                 break;
4172         case RENDERPATH_SOFT:
4173                 DPSOFTRAST_SetVertexPointer(vertex->vertex3f, sizeof(*vertex));
4174                 DPSOFTRAST_SetColorPointer(vertex->color4f, sizeof(*vertex));
4175                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(*vertex), vertex->texcoord2f);
4176                 DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(*vertex), NULL);
4177                 DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(*vertex), NULL);
4178                 DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(*vertex), NULL);
4179                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(*vertex), NULL);
4180                 break;
4181         }
4182 }
4183
4184
4185
4186 r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices)
4187 {
4188         size_t size;
4189         size = sizeof(r_vertexmesh_t) * numvertices;
4190         if (gl_state.preparevertices_tempdatamaxsize < size)
4191         {
4192                 gl_state.preparevertices_tempdatamaxsize = size;
4193                 gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
4194         }
4195         gl_state.preparevertices_vertexmesh = (r_vertexmesh_t *)gl_state.preparevertices_tempdata;
4196         gl_state.preparevertices_numvertices = numvertices;
4197         return gl_state.preparevertices_vertexmesh;
4198 }
4199
4200 qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void)
4201 {
4202         R_Mesh_PrepareVertices_Mesh(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexmesh, NULL);
4203         gl_state.preparevertices_vertexmesh = NULL;
4204         gl_state.preparevertices_numvertices = 0;
4205         return true;
4206 }
4207
4208 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)
4209 {
4210         int i;
4211         r_vertexmesh_t *vertex;
4212         switch(vid.renderpath)
4213         {
4214         case RENDERPATH_GL20:
4215         case RENDERPATH_GLES2:
4216                 if (!vid.useinterleavedarrays)
4217                 {
4218                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
4219                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
4220                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
4221                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), svector3f, NULL, 0);
4222                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), tvector3f, NULL, 0);
4223                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), normal3f, NULL, 0);
4224                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
4225                         return;
4226                 }
4227                 break;
4228         case RENDERPATH_GL11:
4229         case RENDERPATH_GL13:
4230         case RENDERPATH_GLES1:
4231                 if (!vid.useinterleavedarrays)
4232                 {
4233                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
4234                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
4235                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
4236                         if (vid.texunits >= 2)
4237                                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
4238                         if (vid.texunits >= 3)
4239                                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
4240                         return;
4241                 }
4242                 break;
4243         case RENDERPATH_D3D9:
4244         case RENDERPATH_D3D10:
4245         case RENDERPATH_D3D11:
4246                 break;
4247         case RENDERPATH_SOFT:
4248                 DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3]));
4249                 DPSOFTRAST_SetColorPointer(color4f, sizeof(float[4]));
4250                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), texcoordtexture2f);
4251                 DPSOFTRAST_SetTexCoordPointer(1, 3, sizeof(float[3]), svector3f);
4252                 DPSOFTRAST_SetTexCoordPointer(2, 3, sizeof(float[3]), tvector3f);
4253                 DPSOFTRAST_SetTexCoordPointer(3, 3, sizeof(float[3]), normal3f);
4254                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), texcoordlightmap2f);
4255                 return;
4256         }
4257
4258         vertex = R_Mesh_PrepareVertices_Mesh_Lock(numvertices);
4259         for (i = 0;i < numvertices;i++)
4260                 VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
4261         if (svector3f)
4262                 for (i = 0;i < numvertices;i++)
4263                         VectorCopy(svector3f + 3*i, vertex[i].svector3f);
4264         if (tvector3f)
4265                 for (i = 0;i < numvertices;i++)
4266                         VectorCopy(tvector3f + 3*i, vertex[i].tvector3f);
4267         if (normal3f)
4268                 for (i = 0;i < numvertices;i++)
4269                         VectorCopy(normal3f + 3*i, vertex[i].normal3f);
4270         if (color4f)
4271         {
4272                 for (i = 0;i < numvertices;i++)
4273                         Vector4Copy(color4f + 4*i, vertex[i].color4f);
4274         }
4275         else
4276         {
4277                 for (i = 0;i < numvertices;i++)
4278                         Vector4Copy(gl_state.color4f, vertex[i].color4f);
4279         }
4280         if (texcoordtexture2f)
4281                 for (i = 0;i < numvertices;i++)
4282                         Vector2Copy(texcoordtexture2f + 2*i, vertex[i].texcoordtexture2f);
4283         if (texcoordlightmap2f)
4284                 for (i = 0;i < numvertices;i++)
4285                         Vector2Copy(texcoordlightmap2f + 2*i, vertex[i].texcoordlightmap2f);
4286         R_Mesh_PrepareVertices_Mesh_Unlock();
4287         R_Mesh_PrepareVertices_Mesh(numvertices, vertex, NULL);
4288 }
4289
4290 void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *vertexbuffer)
4291 {
4292         // upload temporary vertexbuffer for this rendering
4293         if (!gl_state.usevbo_staticvertex)
4294                 vertexbuffer = NULL;
4295         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
4296         {
4297                 if (gl_state.preparevertices_dynamicvertexbuffer)
4298                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
4299                 else
4300                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true, false);
4301                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
4302         }
4303         switch(vid.renderpath)
4304         {
4305         case RENDERPATH_GL20:
4306         case RENDERPATH_GLES2:
4307                 if (vertexbuffer)
4308                 {
4309                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4310                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4311                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
4312                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , vertexbuffer, (int)((unsigned char *)vertex->svector3f          - (unsigned char *)vertex));
4313                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , vertexbuffer, (int)((unsigned char *)vertex->tvector3f          - (unsigned char *)vertex));
4314                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , vertexbuffer, (int)((unsigned char *)vertex->normal3f           - (unsigned char *)vertex));
4315                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
4316                 }
4317                 else
4318                 {
4319                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4320                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4321                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
4322                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , NULL, 0);
4323                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , NULL, 0);
4324                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , NULL, 0);
4325                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
4326                 }
4327                 break;
4328         case RENDERPATH_GL13:
4329         case RENDERPATH_GLES1:
4330                 if (vertexbuffer)
4331                 {
4332                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4333                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4334                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
4335                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
4336                 }
4337                 else
4338                 {
4339                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4340                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4341                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
4342                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
4343                 }
4344                 break;
4345         case RENDERPATH_GL11:
4346                 if (vertexbuffer)
4347                 {
4348                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
4349                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
4350                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
4351                 }
4352                 else
4353                 {
4354                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
4355                         R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
4356                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
4357                 }
4358                 break;
4359         case RENDERPATH_D3D9:
4360 #ifdef SUPPORTD3D
4361                 IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertexmesh_d3d9decl);
4362                 if (vertexbuffer)
4363                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, 0, sizeof(*vertex));
4364                 else
4365                         IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0);
4366                 gl_state.d3dvertexbuffer = (void *)vertexbuffer;
4367                 gl_state.d3dvertexdata = (void *)vertex;
4368                 gl_state.d3dvertexsize = sizeof(*vertex);
4369 #endif
4370                 break;
4371         case RENDERPATH_D3D10:
4372                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4373                 break;
4374         case RENDERPATH_D3D11:
4375                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4376                 break;
4377         case RENDERPATH_SOFT:
4378                 DPSOFTRAST_SetVertexPointer(vertex->vertex3f, sizeof(*vertex));
4379                 DPSOFTRAST_SetColorPointer(vertex->color4f, sizeof(*vertex));
4380                 DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(*vertex), vertex->texcoordtexture2f);
4381                 DPSOFTRAST_SetTexCoordPointer(1, 3, sizeof(*vertex), vertex->svector3f);
4382                 DPSOFTRAST_SetTexCoordPointer(2, 3, sizeof(*vertex), vertex->tvector3f);
4383                 DPSOFTRAST_SetTexCoordPointer(3, 3, sizeof(*vertex), vertex->normal3f);
4384                 DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(*vertex), vertex->texcoordlightmap2f);
4385                 break;
4386         }
4387 }