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