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