added RENDERPATH_GLES1
[xonotic/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4 #include "dpsoftrast.h"
5 #ifdef SUPPORTD3D
6 #include <d3d9.h>
7 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
8 extern D3DCAPS9 vid_d3d9caps;
9 #endif
10
11 #define MAX_RENDERTARGETS 4
12
13 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
14 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
15 cvar_t gl_mesh_prefer_short_elements = {CVAR_SAVE, "gl_mesh_prefer_short_elements", "1", "use GL_UNSIGNED_SHORT element arrays instead of GL_UNSIGNED_INT"};
16 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
17 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
18
19 cvar_t r_render = {0, "r_render", "1", "enables rendering 3D views (you want this on!)"};
20 cvar_t r_renderview = {0, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
21 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
22 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
23 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
24 cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"};
25 cvar_t gl_vbo_dynamicvertex = {CVAR_SAVE, "gl_vbo_dynamicvertex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
26 cvar_t gl_vbo_dynamicindex = {CVAR_SAVE, "gl_vbo_dynamicindex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
27 cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"};
28
29 cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
30 qboolean v_flipped_state = false;
31
32 r_viewport_t gl_viewport;
33 matrix4x4_t gl_modelmatrix;
34 matrix4x4_t gl_viewmatrix;
35 matrix4x4_t gl_modelviewmatrix;
36 matrix4x4_t gl_projectionmatrix;
37 matrix4x4_t gl_modelviewprojectionmatrix;
38 float gl_modelview16f[16];
39 float gl_modelviewprojection16f[16];
40 qboolean gl_modelmatrixchanged;
41
42 int gl_maxdrawrangeelementsvertices;
43 int gl_maxdrawrangeelementsindices;
44
45 #ifdef DEBUGGL
46 int errornumber = 0;
47
48 void GL_PrintError(int errornumber, const char *filename, int linenumber)
49 {
50         switch(errornumber)
51         {
52 #ifdef GL_INVALID_ENUM
53         case GL_INVALID_ENUM:
54                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
55                 break;
56 #endif
57 #ifdef GL_INVALID_VALUE
58         case GL_INVALID_VALUE:
59                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
60                 break;
61 #endif
62 #ifdef GL_INVALID_OPERATION
63         case GL_INVALID_OPERATION:
64                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
65                 break;
66 #endif
67 #ifdef GL_STACK_OVERFLOW
68         case GL_STACK_OVERFLOW:
69                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
70                 break;
71 #endif
72 #ifdef GL_STACK_UNDERFLOW
73         case GL_STACK_UNDERFLOW:
74                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
75                 break;
76 #endif
77 #ifdef GL_OUT_OF_MEMORY
78         case GL_OUT_OF_MEMORY:
79                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
80                 break;
81 #endif
82 #ifdef GL_TABLE_TOO_LARGE
83         case GL_TABLE_TOO_LARGE:
84                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
85                 break;
86 #endif
87 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
88         case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
89                 Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber);
90                 break;
91 #endif
92         default:
93                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
94                 break;
95         }
96 }
97 #endif
98
99 #define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active");
100
101 void SCR_ScreenShot_f (void);
102
103 typedef struct gltextureunit_s
104 {
105         int pointer_texcoord_components;
106         int pointer_texcoord_gltype;
107         size_t pointer_texcoord_stride;
108         const void *pointer_texcoord_pointer;
109         const r_meshbuffer_t *pointer_texcoord_vertexbuffer;
110         size_t pointer_texcoord_offset;
111
112         rtexture_t *texture;
113         int t2d, t3d, tcubemap;
114         int arrayenabled;
115         int rgbscale, alphascale;
116         int combine;
117         int combinergb, combinealpha;
118         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
119         int texmatrixenabled;
120         matrix4x4_t matrix;
121 }
122 gltextureunit_t;
123
124 typedef struct gl_state_s
125 {
126         int cullface;
127         int cullfaceenable;
128         int blendfunc1;
129         int blendfunc2;
130         qboolean blend;
131         GLboolean depthmask;
132         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
133         int depthtest;
134         int depthfunc;
135         float depthrange[2];
136         float polygonoffset[2];
137         int alphatest;
138         int alphafunc;
139         float alphafuncvalue;
140         int scissortest;
141         unsigned int unit;
142         unsigned int clientunit;
143         gltextureunit_t units[MAX_TEXTUREUNITS];
144         float color4f[4];
145         int lockrange_first;
146         int lockrange_count;
147         int vertexbufferobject;
148         int elementbufferobject;
149         int framebufferobject;
150         int defaultframebufferobject; // deal with platforms that use a non-zero default fbo
151         qboolean pointer_color_enabled;
152
153         int pointer_vertex_components;
154         int pointer_vertex_gltype;
155         size_t pointer_vertex_stride;
156         const void *pointer_vertex_pointer;
157         const r_meshbuffer_t *pointer_vertex_vertexbuffer;
158         size_t pointer_vertex_offset;
159
160         int pointer_color_components;
161         int pointer_color_gltype;
162         size_t pointer_color_stride;
163         const void *pointer_color_pointer;
164         const r_meshbuffer_t *pointer_color_vertexbuffer;
165         size_t pointer_color_offset;
166
167         void *preparevertices_tempdata;
168         size_t preparevertices_tempdatamaxsize;
169         r_meshbuffer_t *preparevertices_dynamicvertexbuffer;
170         r_vertexgeneric_t *preparevertices_vertexgeneric;
171         r_vertexmesh_t *preparevertices_vertexmesh;
172         int preparevertices_numvertices;
173
174         r_meshbuffer_t *draw_dynamicindexbuffer;
175
176         qboolean usevbo_staticvertex;
177         qboolean usevbo_staticindex;
178         qboolean usevbo_dynamicvertex;
179         qboolean usevbo_dynamicindex;
180
181         memexpandablearray_t meshbufferarray;
182
183         qboolean active;
184
185 #ifdef SUPPORTD3D
186 //      rtexture_t *d3drt_depthtexture;
187 //      rtexture_t *d3drt_colortextures[MAX_RENDERTARGETS];
188         IDirect3DSurface9 *d3drt_depthsurface;
189         IDirect3DSurface9 *d3drt_colorsurfaces[MAX_RENDERTARGETS];
190         IDirect3DSurface9 *d3drt_backbufferdepthsurface;
191         IDirect3DSurface9 *d3drt_backbuffercolorsurface;
192         void *d3dvertexbuffer;
193         void *d3dvertexdata;
194         size_t d3dvertexsize;
195 #endif
196 }
197 gl_state_t;
198
199 static gl_state_t gl_state;
200
201
202 /*
203 note: here's strip order for a terrain row:
204 0--1--2--3--4
205 |\ |\ |\ |\ |
206 | \| \| \| \|
207 A--B--C--D--E
208 clockwise
209
210 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
211
212 *elements++ = i + row;
213 *elements++ = i;
214 *elements++ = i + row + 1;
215 *elements++ = i;
216 *elements++ = i + 1;
217 *elements++ = i + row + 1;
218
219
220 for (y = 0;y < rows - 1;y++)
221 {
222         for (x = 0;x < columns - 1;x++)
223         {
224                 i = y * rows + x;
225                 *elements++ = i + columns;
226                 *elements++ = i;
227                 *elements++ = i + columns + 1;
228                 *elements++ = i;
229                 *elements++ = i + 1;
230                 *elements++ = i + columns + 1;
231         }
232 }
233
234 alternative:
235 0--1--2--3--4
236 | /| /|\ | /|
237 |/ |/ | \|/ |
238 A--B--C--D--E
239 counterclockwise
240
241 for (y = 0;y < rows - 1;y++)
242 {
243         for (x = 0;x < columns - 1;x++)
244         {
245                 i = y * rows + x;
246                 *elements++ = i;
247                 *elements++ = i + columns;
248                 *elements++ = i + columns + 1;
249                 *elements++ = i + columns;
250                 *elements++ = i + columns + 1;
251                 *elements++ = i + 1;
252         }
253 }
254 */
255
256 int polygonelement3i[(POLYGONELEMENTS_MAXPOINTS-2)*3];
257 unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3];
258 int quadelement3i[QUADELEMENTS_MAXQUADS*6];
259 unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6];
260
261 void GL_VBOStats_f(void)
262 {
263         GL_Mesh_ListVBOs(true);
264 }
265
266 static void GL_Backend_ResetState(void);
267
268 static void R_Mesh_InitVertexDeclarations(void);
269 static void R_Mesh_DestroyVertexDeclarations(void);
270
271 static void R_Mesh_SetUseVBO(void)
272 {
273         switch(vid.renderpath)
274         {
275         case RENDERPATH_GL11:
276         case RENDERPATH_GL13:
277         case RENDERPATH_GL20:
278         case RENDERPATH_GLES1:
279                 gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
280                 gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo;
281                 gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
282                 gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo;
283                 break;
284         case RENDERPATH_D3D9:
285                 gl_state.usevbo_staticvertex = gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
286                 gl_state.usevbo_dynamicvertex = gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer && gl_vbo_dynamicindex.integer) || vid.forcevbo;
287                 break;
288         case RENDERPATH_D3D10:
289                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
290                 break;
291         case RENDERPATH_D3D11:
292                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
293                 break;
294         case RENDERPATH_SOFT:
295                 gl_state.usevbo_staticvertex = false;
296                 gl_state.usevbo_staticindex = false;
297                 gl_state.usevbo_dynamicvertex = false;
298                 gl_state.usevbo_dynamicindex = false;
299                 break;
300         case RENDERPATH_GLES2:
301                 gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
302                 gl_state.usevbo_staticindex = false;
303                 gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
304                 gl_state.usevbo_dynamicindex = false;
305                 break;
306         }
307 }
308
309 static void gl_backend_start(void)
310 {
311         memset(&gl_state, 0, sizeof(gl_state));
312
313         R_Mesh_InitVertexDeclarations();
314
315         R_Mesh_SetUseVBO();
316         Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128);
317
318         Con_DPrintf("OpenGL backend started.\n");
319
320         CHECKGLERROR
321
322         GL_Backend_ResetState();
323
324         switch(vid.renderpath)
325         {
326         case RENDERPATH_GL11:
327         case RENDERPATH_GL13:
328         case RENDERPATH_GL20:
329         case RENDERPATH_GLES1:
330         case RENDERPATH_GLES2:
331                 // fetch current fbo here (default fbo is not 0 on some GLES devices)
332                 if (vid.support.ext_framebuffer_object)
333                         qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &gl_state.defaultframebufferobject);
334                 break;
335         case RENDERPATH_D3D9:
336 #ifdef SUPPORTD3D
337                 IDirect3DDevice9_GetDepthStencilSurface(vid_d3d9dev, &gl_state.d3drt_backbufferdepthsurface);
338                 IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &gl_state.d3drt_backbuffercolorsurface);
339 #endif
340                 break;
341         case RENDERPATH_D3D10:
342                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
343                 break;
344         case RENDERPATH_D3D11:
345                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
346                 break;
347         case RENDERPATH_SOFT:
348                 break;
349         }
350 }
351
352 static void gl_backend_shutdown(void)
353 {
354         Con_DPrint("OpenGL Backend shutting down\n");
355
356         switch(vid.renderpath)
357         {
358         case RENDERPATH_GL11:
359         case RENDERPATH_GL13:
360         case RENDERPATH_GL20:
361         case RENDERPATH_SOFT:
362         case RENDERPATH_GLES1:
363         case RENDERPATH_GLES2:
364                 break;
365         case RENDERPATH_D3D9:
366 #ifdef SUPPORTD3D
367                 IDirect3DSurface9_Release(gl_state.d3drt_backbufferdepthsurface);
368                 IDirect3DSurface9_Release(gl_state.d3drt_backbuffercolorsurface);
369 #endif
370                 break;
371         case RENDERPATH_D3D10:
372                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
373                 break;
374         case RENDERPATH_D3D11:
375                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
376                 break;
377         }
378
379         if (gl_state.preparevertices_tempdata)
380                 Mem_Free(gl_state.preparevertices_tempdata);
381         if (gl_state.preparevertices_dynamicvertexbuffer)
382                 R_Mesh_DestroyMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer);
383
384         Mem_ExpandableArray_FreeArray(&gl_state.meshbufferarray);
385
386         R_Mesh_DestroyVertexDeclarations();
387
388         memset(&gl_state, 0, sizeof(gl_state));
389 }
390
391 static void gl_backend_newmap(void)
392 {
393 }
394
395 static void gl_backend_devicelost(void)
396 {
397         int i, endindex;
398         r_meshbuffer_t *buffer;
399 #ifdef SUPPORTD3D
400         gl_state.d3dvertexbuffer = NULL;
401 #endif
402         switch(vid.renderpath)
403         {
404         case RENDERPATH_GL11:
405         case RENDERPATH_GL13:
406         case RENDERPATH_GL20:
407         case RENDERPATH_SOFT:
408         case RENDERPATH_GLES1:
409         case RENDERPATH_GLES2:
410                 break;
411         case RENDERPATH_D3D9:
412 #ifdef SUPPORTD3D
413                 IDirect3DSurface9_Release(gl_state.d3drt_backbufferdepthsurface);
414                 IDirect3DSurface9_Release(gl_state.d3drt_backbuffercolorsurface);
415 #endif
416                 break;
417         case RENDERPATH_D3D10:
418                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
419                 break;
420         case RENDERPATH_D3D11:
421                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
422                 break;
423         }
424         endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
425         for (i = 0;i < endindex;i++)
426         {
427                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
428                 if (!buffer || !buffer->isdynamic)
429                         continue;
430                 switch(vid.renderpath)
431                 {
432                 case RENDERPATH_GL11:
433                 case RENDERPATH_GL13:
434                 case RENDERPATH_GL20:
435                 case RENDERPATH_SOFT:
436                 case RENDERPATH_GLES1:
437                 case RENDERPATH_GLES2:
438                         break;
439                 case RENDERPATH_D3D9:
440 #ifdef SUPPORTD3D
441                         if (buffer->devicebuffer)
442                         {
443                                 if (buffer->isindexbuffer)
444                                         IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer);
445                                 else
446                                         IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer);
447                                 buffer->devicebuffer = NULL;
448                         }
449 #endif
450                         break;
451                 case RENDERPATH_D3D10:
452                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
453                         break;
454                 case RENDERPATH_D3D11:
455                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
456                         break;
457                 }
458         }
459 }
460
461 static void gl_backend_devicerestored(void)
462 {
463         switch(vid.renderpath)
464         {
465         case RENDERPATH_GL11:
466         case RENDERPATH_GL13:
467         case RENDERPATH_GL20:
468         case RENDERPATH_SOFT:
469         case RENDERPATH_GLES1:
470         case RENDERPATH_GLES2:
471                 break;
472         case RENDERPATH_D3D9:
473 #ifdef SUPPORTD3D
474                 IDirect3DDevice9_GetDepthStencilSurface(vid_d3d9dev, &gl_state.d3drt_backbufferdepthsurface);
475                 IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &gl_state.d3drt_backbuffercolorsurface);
476 #endif
477                 break;
478         case RENDERPATH_D3D10:
479                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
480                 break;
481         case RENDERPATH_D3D11:
482                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
483                 break;
484         }
485 }
486
487 void gl_backend_init(void)
488 {
489         int i;
490
491         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
492         {
493                 polygonelement3s[i * 3 + 0] = 0;
494                 polygonelement3s[i * 3 + 1] = i + 1;
495                 polygonelement3s[i * 3 + 2] = i + 2;
496         }
497         // elements for rendering a series of quads as triangles
498         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
499         {
500                 quadelement3s[i * 6 + 0] = i * 4;
501                 quadelement3s[i * 6 + 1] = i * 4 + 1;
502                 quadelement3s[i * 6 + 2] = i * 4 + 2;
503                 quadelement3s[i * 6 + 3] = i * 4;
504                 quadelement3s[i * 6 + 4] = i * 4 + 2;
505                 quadelement3s[i * 6 + 5] = i * 4 + 3;
506         }
507
508         for (i = 0;i < (POLYGONELEMENTS_MAXPOINTS - 2)*3;i++)
509                 polygonelement3i[i] = polygonelement3s[i];
510         for (i = 0;i < QUADELEMENTS_MAXQUADS*6;i++)
511                 quadelement3i[i] = quadelement3s[i];
512
513         Cvar_RegisterVariable(&r_render);
514         Cvar_RegisterVariable(&r_renderview);
515         Cvar_RegisterVariable(&r_waterwarp);
516         Cvar_RegisterVariable(&gl_polyblend);
517         Cvar_RegisterVariable(&v_flipped);
518         Cvar_RegisterVariable(&gl_dither);
519         Cvar_RegisterVariable(&gl_vbo);
520         Cvar_RegisterVariable(&gl_vbo_dynamicvertex);
521         Cvar_RegisterVariable(&gl_vbo_dynamicindex);
522         Cvar_RegisterVariable(&gl_paranoid);
523         Cvar_RegisterVariable(&gl_printcheckerror);
524
525         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
526         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
527         Cvar_RegisterVariable(&gl_mesh_prefer_short_elements);
528
529         Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them");
530
531         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap, gl_backend_devicelost, gl_backend_devicerestored);
532 }
533
534 void GL_SetMirrorState(qboolean state);
535
536 void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out)
537 {
538         vec4_t temp;
539         float iw;
540         Matrix4x4_Transform4 (&v->viewmatrix, in, temp);
541         Matrix4x4_Transform4 (&v->projectmatrix, temp, out);
542         iw = 1.0f / out[3];
543         out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f;
544
545         // for an odd reason, inverting this is wrong for R_Shadow_ScissorForBBox (we then get badly scissored lights)
546         //out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f;
547         out[1] = v->y + (out[1] * iw + 1.0f) * v->height * 0.5f;
548
549         out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f;
550 }
551
552 void GL_Finish(void)
553 {
554         switch(vid.renderpath)
555         {
556         case RENDERPATH_GL11:
557         case RENDERPATH_GL13:
558         case RENDERPATH_GL20:
559         case RENDERPATH_GLES1:
560         case RENDERPATH_GLES2:
561                 qglFinish();
562                 break;
563         case RENDERPATH_D3D9:
564                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
565                 break;
566         case RENDERPATH_D3D10:
567                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
568                 break;
569         case RENDERPATH_D3D11:
570                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
571                 break;
572         case RENDERPATH_SOFT:
573                 DPSOFTRAST_Finish();
574                 break;
575         }
576 }
577
578 static int bboxedges[12][2] =
579 {
580         // top
581         {0, 1}, // +X
582         {0, 2}, // +Y
583         {1, 3}, // Y, +X
584         {2, 3}, // X, +Y
585         // bottom
586         {4, 5}, // +X
587         {4, 6}, // +Y
588         {5, 7}, // Y, +X
589         {6, 7}, // X, +Y
590         // verticals
591         {0, 4}, // +Z
592         {1, 5}, // X, +Z
593         {2, 6}, // Y, +Z
594         {3, 7}, // XY, +Z
595 };
596
597 qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor)
598 {
599         int i, ix1, iy1, ix2, iy2;
600         float x1, y1, x2, y2;
601         vec4_t v, v2;
602         float vertex[20][3];
603         int j, k;
604         vec4_t plane4f;
605         int numvertices;
606         float corner[8][4];
607         float dist[8];
608         int sign[8];
609         float f;
610
611         scissor[0] = r_refdef.view.viewport.x;
612         scissor[1] = r_refdef.view.viewport.y;
613         scissor[2] = r_refdef.view.viewport.width;
614         scissor[3] = r_refdef.view.viewport.height;
615
616         // if view is inside the box, just say yes it's visible
617         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
618                 return false;
619
620         x1 = y1 = x2 = y2 = 0;
621
622         // transform all corners that are infront of the nearclip plane
623         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
624         plane4f[3] = r_refdef.view.frustum[4].dist;
625         numvertices = 0;
626         for (i = 0;i < 8;i++)
627         {
628                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
629                 dist[i] = DotProduct4(corner[i], plane4f);
630                 sign[i] = dist[i] > 0;
631                 if (!sign[i])
632                 {
633                         VectorCopy(corner[i], vertex[numvertices]);
634                         numvertices++;
635                 }
636         }
637         // if some points are behind the nearclip, add clipped edge points to make
638         // sure that the scissor boundary is complete
639         if (numvertices > 0 && numvertices < 8)
640         {
641                 // add clipped edge points
642                 for (i = 0;i < 12;i++)
643                 {
644                         j = bboxedges[i][0];
645                         k = bboxedges[i][1];
646                         if (sign[j] != sign[k])
647                         {
648                                 f = dist[j] / (dist[j] - dist[k]);
649                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
650                                 numvertices++;
651                         }
652                 }
653         }
654
655         // if we have no points to check, it is behind the view plane
656         if (!numvertices)
657                 return true;
658
659         // if we have some points to transform, check what screen area is covered
660         x1 = y1 = x2 = y2 = 0;
661         v[3] = 1.0f;
662         //Con_Printf("%i vertices to transform...\n", numvertices);
663         for (i = 0;i < numvertices;i++)
664         {
665                 VectorCopy(vertex[i], v);
666                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
667                 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
668                 if (i)
669                 {
670                         if (x1 > v2[0]) x1 = v2[0];
671                         if (x2 < v2[0]) x2 = v2[0];
672                         if (y1 > v2[1]) y1 = v2[1];
673                         if (y2 < v2[1]) y2 = v2[1];
674                 }
675                 else
676                 {
677                         x1 = x2 = v2[0];
678                         y1 = y2 = v2[1];
679                 }
680         }
681
682         // now convert the scissor rectangle to integer screen coordinates
683         ix1 = (int)(x1 - 1.0f);
684         //iy1 = vid.height - (int)(y2 - 1.0f);
685         //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f);
686         iy1 = (int)(y1 - 1.0f);
687         ix2 = (int)(x2 + 1.0f);
688         //iy2 = vid.height - (int)(y1 + 1.0f);
689         //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f);
690         iy2 = (int)(y2 + 1.0f);
691         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
692
693         // clamp it to the screen
694         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
695         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
696         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
697         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
698
699         // if it is inside out, it's not visible
700         if (ix2 <= ix1 || iy2 <= iy1)
701                 return true;
702
703         // the light area is visible, set up the scissor rectangle
704         scissor[0] = ix1;
705         scissor[1] = iy1;
706         scissor[2] = ix2 - ix1;
707         scissor[3] = iy2 - iy1;
708
709         // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
710         switch(vid.renderpath)
711         {
712         case RENDERPATH_D3D9:
713         case RENDERPATH_D3D10:
714         case RENDERPATH_D3D11:
715                 scissor[1] = vid.height - scissor[1] - scissor[3];
716                 break;
717         case RENDERPATH_GL11:
718         case RENDERPATH_GL13:
719         case RENDERPATH_GL20:
720         case RENDERPATH_SOFT:
721         case RENDERPATH_GLES1:
722         case RENDERPATH_GLES2:
723                 break;
724         }
725
726         return false;
727 }
728
729
730 static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m, float normalx, float normaly, float normalz, float dist)
731 {
732         float q[4];
733         float d;
734         float clipPlane[4], v3[3], v4[3];
735         float normal[3];
736
737         // This is inspired by Oblique Depth Projection from http://www.terathon.com/code/oblique.php
738
739         VectorSet(normal, normalx, normaly, normalz);
740         Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane);
741         VectorScale(normal, -dist, v3);
742         Matrix4x4_Transform(&v->viewmatrix, v3, v4);
743         // FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique
744         clipPlane[3] = -DotProduct(v4, clipPlane);
745
746 #if 0
747 {
748         // testing code for comparing results
749         float clipPlane2[4];
750         VectorCopy4(clipPlane, clipPlane2);
751         R_EntityMatrix(&identitymatrix);
752         VectorSet(q, normal[0], normal[1], normal[2], -dist);
753         qglClipPlane(GL_CLIP_PLANE0, q);
754         qglGetClipPlane(GL_CLIP_PLANE0, q);
755         VectorCopy4(q, clipPlane);
756 }
757 #endif
758
759         // Calculate the clip-space corner point opposite the clipping plane
760         // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
761         // transform it into camera space by multiplying it
762         // by the inverse of the projection matrix
763         q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + m[8]) / m[0];
764         q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + m[9]) / m[5];
765         q[2] = -1.0f;
766         q[3] = (1.0f + m[10]) / m[14];
767
768         // Calculate the scaled plane vector
769         d = 2.0f / DotProduct4(clipPlane, q);
770
771         // Replace the third row of the projection matrix
772         m[2] = clipPlane[0] * d;
773         m[6] = clipPlane[1] * d;
774         m[10] = clipPlane[2] * d + 1.0f;
775         m[14] = clipPlane[3] * d;
776 }
777
778 void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float x1, float y1, float x2, float y2, float nearclip, float farclip, const float *nearplane)
779 {
780         float left = x1, right = x2, bottom = y2, top = y1, zNear = nearclip, zFar = farclip;
781         float m[16];
782         memset(v, 0, sizeof(*v));
783         v->type = R_VIEWPORTTYPE_ORTHO;
784         v->cameramatrix = *cameramatrix;
785         v->x = x;
786         v->y = y;
787         v->z = 0;
788         v->width = width;
789         v->height = height;
790         v->depth = 1;
791         memset(m, 0, sizeof(m));
792         m[0]  = 2/(right - left);
793         m[5]  = 2/(top - bottom);
794         m[10] = -2/(zFar - zNear);
795         m[12] = - (right + left)/(right - left);
796         m[13] = - (top + bottom)/(top - bottom);
797         m[14] = - (zFar + zNear)/(zFar - zNear);
798         m[15] = 1;
799         switch(vid.renderpath)
800         {
801         case RENDERPATH_GL11:
802         case RENDERPATH_GL13:
803         case RENDERPATH_GL20:
804         case RENDERPATH_SOFT:
805         case RENDERPATH_GLES1:
806         case RENDERPATH_GLES2:
807                 break;
808         case RENDERPATH_D3D9:
809         case RENDERPATH_D3D10:
810         case RENDERPATH_D3D11:
811                 m[10] = -1/(zFar - zNear);
812                 m[14] = -zNear/(zFar-zNear);
813                 break;
814         }
815         v->screentodepth[0] = -farclip / (farclip - nearclip);
816         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
817
818         Matrix4x4_Invert_Full(&v->viewmatrix, &v->cameramatrix);
819
820         if (nearplane)
821                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
822
823         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
824
825 #if 0
826         {
827                 vec4_t test1;
828                 vec4_t test2;
829                 Vector4Set(test1, (x1+x2)*0.5f, (y1+y2)*0.5f, 0.0f, 1.0f);
830                 R_Viewport_TransformToScreen(v, test1, test2);
831                 Con_Printf("%f %f %f -> %f %f %f\n", test1[0], test1[1], test1[2], test2[0], test2[1], test2[2]);
832         }
833 #endif
834 }
835
836 void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, float farclip, const float *nearplane)
837 {
838         matrix4x4_t tempmatrix, basematrix;
839         float m[16];
840         memset(v, 0, sizeof(*v));
841
842         v->type = R_VIEWPORTTYPE_PERSPECTIVE;
843         v->cameramatrix = *cameramatrix;
844         v->x = x;
845         v->y = y;
846         v->z = 0;
847         v->width = width;
848         v->height = height;
849         v->depth = 1;
850         memset(m, 0, sizeof(m));
851         m[0]  = 1.0 / frustumx;
852         m[5]  = 1.0 / frustumy;
853         m[10] = -(farclip + nearclip) / (farclip - nearclip);
854         m[11] = -1;
855         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
856         v->screentodepth[0] = -farclip / (farclip - nearclip);
857         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
858
859         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
860         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
861         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
862         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
863
864         if (nearplane)
865                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
866
867         if(v_flipped.integer)
868         {
869                 m[0] = -m[0];
870                 m[4] = -m[4];
871                 m[8] = -m[8];
872                 m[12] = -m[12];
873         }
874
875         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
876 }
877
878 void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, const float *nearplane)
879 {
880         matrix4x4_t tempmatrix, basematrix;
881         const float nudge = 1.0 - 1.0 / (1<<23);
882         float m[16];
883         memset(v, 0, sizeof(*v));
884
885         v->type = R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP;
886         v->cameramatrix = *cameramatrix;
887         v->x = x;
888         v->y = y;
889         v->z = 0;
890         v->width = width;
891         v->height = height;
892         v->depth = 1;
893         memset(m, 0, sizeof(m));
894         m[ 0] = 1.0 / frustumx;
895         m[ 5] = 1.0 / frustumy;
896         m[10] = -nudge;
897         m[11] = -1;
898         m[14] = -2 * nearclip * nudge;
899         v->screentodepth[0] = (m[10] + 1) * 0.5 - 1;
900         v->screentodepth[1] = m[14] * -0.5;
901
902         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
903         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
904         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
905         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
906
907         if (nearplane)
908                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
909
910         if(v_flipped.integer)
911         {
912                 m[0] = -m[0];
913                 m[4] = -m[4];
914                 m[8] = -m[8];
915                 m[12] = -m[12];
916         }
917
918         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
919 }
920
921 float cubeviewmatrix[6][16] =
922 {
923     // standard cubemap projections
924     { // +X
925          0, 0,-1, 0,
926          0,-1, 0, 0,
927         -1, 0, 0, 0,
928          0, 0, 0, 1,
929     },
930     { // -X
931          0, 0, 1, 0,
932          0,-1, 0, 0,
933          1, 0, 0, 0,
934          0, 0, 0, 1,
935     },
936     { // +Y
937          1, 0, 0, 0,
938          0, 0,-1, 0,
939          0, 1, 0, 0,
940          0, 0, 0, 1,
941     },
942     { // -Y
943          1, 0, 0, 0,
944          0, 0, 1, 0,
945          0,-1, 0, 0,
946          0, 0, 0, 1,
947     },
948     { // +Z
949          1, 0, 0, 0,
950          0,-1, 0, 0,
951          0, 0,-1, 0,
952          0, 0, 0, 1,
953     },
954     { // -Z
955         -1, 0, 0, 0,
956          0,-1, 0, 0,
957          0, 0, 1, 0,
958          0, 0, 0, 1,
959     },
960 };
961 float rectviewmatrix[6][16] =
962 {
963     // sign-preserving cubemap projections
964     { // +X
965          0, 0,-1, 0,
966          0, 1, 0, 0,
967          1, 0, 0, 0,
968          0, 0, 0, 1,
969     },
970     { // -X
971          0, 0, 1, 0,
972          0, 1, 0, 0,
973          1, 0, 0, 0,
974          0, 0, 0, 1,
975     },
976     { // +Y
977          1, 0, 0, 0,
978          0, 0,-1, 0,
979          0, 1, 0, 0,
980          0, 0, 0, 1,
981     },
982     { // -Y
983          1, 0, 0, 0,
984          0, 0, 1, 0,
985          0, 1, 0, 0,
986          0, 0, 0, 1,
987     },
988     { // +Z
989          1, 0, 0, 0,
990          0, 1, 0, 0,
991          0, 0,-1, 0,
992          0, 0, 0, 1,
993     },
994     { // -Z
995          1, 0, 0, 0,
996          0, 1, 0, 0,
997          0, 0, 1, 0,
998          0, 0, 0, 1,
999     },
1000 };
1001
1002 void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane)
1003 {
1004         matrix4x4_t tempmatrix, basematrix;
1005         float m[16];
1006         memset(v, 0, sizeof(*v));
1007         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
1008         v->cameramatrix = *cameramatrix;
1009         v->width = size;
1010         v->height = size;
1011         v->depth = 1;
1012         memset(m, 0, sizeof(m));
1013         m[0] = m[5] = 1.0f;
1014         m[10] = -(farclip + nearclip) / (farclip - nearclip);
1015         m[11] = -1;
1016         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
1017
1018         Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]);
1019         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
1020         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
1021
1022         if (nearplane)
1023                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
1024
1025         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
1026 }
1027
1028 void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane)
1029 {
1030         matrix4x4_t tempmatrix, basematrix;
1031         float m[16];
1032         memset(v, 0, sizeof(*v));
1033         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
1034         v->cameramatrix = *cameramatrix;
1035         v->x = (side & 1) * size;
1036         v->y = (side >> 1) * size;
1037         v->width = size;
1038         v->height = size;
1039         v->depth = 1;
1040         memset(m, 0, sizeof(m));
1041         m[0] = m[5] = 1.0f * ((float)size - border) / size;
1042         m[10] = -(farclip + nearclip) / (farclip - nearclip);
1043         m[11] = -1;
1044         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
1045
1046         Matrix4x4_FromArrayFloatGL(&basematrix, rectviewmatrix[side]);
1047         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
1048         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
1049
1050         switch(vid.renderpath)
1051         {
1052         case RENDERPATH_GL20:
1053         case RENDERPATH_GL13:
1054         case RENDERPATH_GL11:
1055         case RENDERPATH_SOFT:
1056         case RENDERPATH_GLES1:
1057         case RENDERPATH_GLES2:
1058                 break;
1059         case RENDERPATH_D3D9:
1060                 m[5] *= -1;
1061                 break;
1062         case RENDERPATH_D3D10:
1063                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1064                 break;
1065         case RENDERPATH_D3D11:
1066                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1067                 break;
1068         }
1069
1070         if (nearplane)
1071                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
1072
1073         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
1074 }
1075
1076 void R_SetViewport(const r_viewport_t *v)
1077 {
1078         float m[16];
1079         gl_viewport = *v;
1080
1081         // FIXME: v_flipped_state is evil, this probably breaks somewhere
1082         GL_SetMirrorState(v_flipped.integer && (v->type == R_VIEWPORTTYPE_PERSPECTIVE || v->type == R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP));
1083
1084         // copy over the matrices to our state
1085         gl_viewmatrix = v->viewmatrix;
1086         gl_projectionmatrix = v->projectmatrix;
1087
1088         switch(vid.renderpath)
1089         {
1090         case RENDERPATH_GL13:
1091         case RENDERPATH_GL11:
1092         case RENDERPATH_GLES1:
1093                 CHECKGLERROR
1094                 qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
1095                 // Load the projection matrix into OpenGL
1096                 qglMatrixMode(GL_PROJECTION);CHECKGLERROR
1097                 Matrix4x4_ToArrayFloatGL(&gl_projectionmatrix, m);
1098                 qglLoadMatrixf(m);CHECKGLERROR
1099                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1100                 break;
1101         case RENDERPATH_D3D9:
1102 #ifdef SUPPORTD3D
1103                 {
1104                         D3DVIEWPORT9 d3dviewport;
1105                         d3dviewport.X = gl_viewport.x;
1106                         d3dviewport.Y = gl_viewport.y;
1107                         d3dviewport.Width = gl_viewport.width;
1108                         d3dviewport.Height = gl_viewport.height;
1109                         d3dviewport.MinZ = gl_state.depthrange[0];
1110                         d3dviewport.MaxZ = gl_state.depthrange[1];
1111                         IDirect3DDevice9_SetViewport(vid_d3d9dev, &d3dviewport);
1112                 }
1113 #endif
1114                 break;
1115         case RENDERPATH_D3D10:
1116                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1117                 break;
1118         case RENDERPATH_D3D11:
1119                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1120                 break;
1121         case RENDERPATH_SOFT:
1122                 DPSOFTRAST_Viewport(v->x, v->y, v->width, v->height);
1123                 break;
1124         case RENDERPATH_GL20:
1125         case RENDERPATH_GLES2:
1126                 CHECKGLERROR
1127                 qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
1128                 break;
1129         }
1130
1131         // force an update of the derived matrices
1132         gl_modelmatrixchanged = true;
1133         R_EntityMatrix(&gl_modelmatrix);
1134 }
1135
1136 void R_GetViewport(r_viewport_t *v)
1137 {
1138         *v = gl_viewport;
1139 }
1140
1141 static void GL_BindVBO(int bufferobject)
1142 {
1143         if (gl_state.vertexbufferobject != bufferobject)
1144         {
1145                 gl_state.vertexbufferobject = bufferobject;
1146                 CHECKGLERROR
1147                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);CHECKGLERROR
1148         }
1149 }
1150
1151 static void GL_BindEBO(int bufferobject)
1152 {
1153         if (gl_state.elementbufferobject != bufferobject)
1154         {
1155                 gl_state.elementbufferobject = bufferobject;
1156                 CHECKGLERROR
1157                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);CHECKGLERROR
1158         }
1159 }
1160
1161 int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
1162 {
1163         int temp;
1164         switch(vid.renderpath)
1165         {
1166         case RENDERPATH_GL11:
1167         case RENDERPATH_GL13:
1168         case RENDERPATH_GL20:
1169         case RENDERPATH_GLES1:
1170         case RENDERPATH_GLES2:
1171                 if (!vid.support.ext_framebuffer_object)
1172                         return 0;
1173                 qglGenFramebuffersEXT(1, (GLuint*)&temp);CHECKGLERROR
1174                 R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
1175                 if (depthtexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, depthtexture->gltexturetypeenum, R_GetTexture(depthtexture), 0);CHECKGLERROR
1176                 if (colortexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, colortexture->gltexturetypeenum, R_GetTexture(colortexture), 0);CHECKGLERROR
1177                 if (colortexture2) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, colortexture2->gltexturetypeenum, R_GetTexture(colortexture2), 0);CHECKGLERROR
1178                 if (colortexture3) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, colortexture3->gltexturetypeenum, R_GetTexture(colortexture3), 0);CHECKGLERROR
1179                 if (colortexture4) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, colortexture4->gltexturetypeenum, R_GetTexture(colortexture4), 0);CHECKGLERROR
1180                 return temp;
1181         case RENDERPATH_D3D9:
1182         case RENDERPATH_D3D10:
1183         case RENDERPATH_D3D11:
1184                 return 1;
1185         case RENDERPATH_SOFT:
1186                 return 1;
1187         }
1188         return 0;
1189 }
1190
1191 void R_Mesh_DestroyFramebufferObject(int fbo)
1192 {
1193         switch(vid.renderpath)
1194         {
1195         case RENDERPATH_GL11:
1196         case RENDERPATH_GL13:
1197         case RENDERPATH_GL20:
1198         case RENDERPATH_GLES1:
1199         case RENDERPATH_GLES2:
1200                 if (fbo)
1201                         qglDeleteFramebuffersEXT(1, (GLuint*)&fbo);
1202                 break;
1203         case RENDERPATH_D3D9:
1204         case RENDERPATH_D3D10:
1205         case RENDERPATH_D3D11:
1206                 break;
1207         case RENDERPATH_SOFT:
1208                 break;
1209         }
1210 }
1211
1212 #ifdef SUPPORTD3D
1213 void R_Mesh_SetRenderTargetsD3D9(IDirect3DSurface9 *depthsurface, IDirect3DSurface9 *colorsurface0, IDirect3DSurface9 *colorsurface1, IDirect3DSurface9 *colorsurface2, IDirect3DSurface9 *colorsurface3)
1214 {
1215 // LordHavoc: for some weird reason the redundant SetDepthStencilSurface calls are necessary (otherwise the lights fail depth test, as if they were using the shadowmap depth surface and render target still)
1216         if (gl_state.d3drt_depthsurface == depthsurface && gl_state.d3drt_colorsurfaces[0] == colorsurface0 && gl_state.d3drt_colorsurfaces[1] == colorsurface1 && gl_state.d3drt_colorsurfaces[2] == colorsurface2 && gl_state.d3drt_colorsurfaces[3] == colorsurface3)
1217                 return;
1218
1219         gl_state.framebufferobject = depthsurface != gl_state.d3drt_backbufferdepthsurface || colorsurface0 != gl_state.d3drt_backbuffercolorsurface;
1220         if (gl_state.d3drt_depthsurface != depthsurface)
1221         {
1222                 gl_state.d3drt_depthsurface = depthsurface;
1223                 IDirect3DDevice9_SetDepthStencilSurface(vid_d3d9dev, gl_state.d3drt_depthsurface);
1224         }
1225         if (gl_state.d3drt_colorsurfaces[0] != colorsurface0)
1226         {
1227                 gl_state.d3drt_colorsurfaces[0] = colorsurface0;
1228                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 0, gl_state.d3drt_colorsurfaces[0]);
1229         }
1230         if (gl_state.d3drt_colorsurfaces[1] != colorsurface1)
1231         {
1232                 gl_state.d3drt_colorsurfaces[1] = colorsurface1;
1233                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 1, gl_state.d3drt_colorsurfaces[1]);
1234         }
1235         if (gl_state.d3drt_colorsurfaces[2] != colorsurface2)
1236         {
1237                 gl_state.d3drt_colorsurfaces[2] = colorsurface2;
1238                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 2, gl_state.d3drt_colorsurfaces[2]);
1239         }
1240         if (gl_state.d3drt_colorsurfaces[3] != colorsurface3)
1241         {
1242                 gl_state.d3drt_colorsurfaces[3] = colorsurface3;
1243                 IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 3, gl_state.d3drt_colorsurfaces[3]);
1244         }
1245 }
1246 #endif
1247
1248 void R_Mesh_ResetRenderTargets(void)
1249 {
1250         switch(vid.renderpath)
1251         {
1252         case RENDERPATH_GL11:
1253         case RENDERPATH_GL13:
1254         case RENDERPATH_GL20:
1255         case RENDERPATH_GLES1:
1256         case RENDERPATH_GLES2:
1257                 if (gl_state.framebufferobject)
1258                 {
1259                         gl_state.framebufferobject = 0;
1260                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.defaultframebufferobject);
1261                 }
1262                 break;
1263         case RENDERPATH_D3D9:
1264 #ifdef SUPPORTD3D
1265                 R_Mesh_SetRenderTargetsD3D9(gl_state.d3drt_backbufferdepthsurface, gl_state.d3drt_backbuffercolorsurface, NULL, NULL, NULL);
1266 #endif
1267                 break;
1268         case RENDERPATH_D3D10:
1269                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1270                 break;
1271         case RENDERPATH_D3D11:
1272                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1273                 break;
1274         case RENDERPATH_SOFT:
1275                 DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
1276                 break;
1277         }
1278 }
1279
1280 void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
1281 {
1282         unsigned int i;
1283         unsigned int j;
1284         rtexture_t *textures[5];
1285         Vector4Set(textures, colortexture, colortexture2, colortexture3, colortexture4);
1286         textures[4] = depthtexture;
1287         // unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target
1288         for (j = 0;j < 5;j++)
1289                 if (textures[j])
1290                         for (i = 0;i < vid.teximageunits;i++)
1291                                 if (gl_state.units[i].texture == textures[j])
1292                                         R_Mesh_TexBind(i, NULL);
1293         // set up framebuffer object or render targets for the active rendering API
1294         switch(vid.renderpath)
1295         {
1296         case RENDERPATH_GL11:
1297         case RENDERPATH_GL13:
1298         case RENDERPATH_GL20:
1299         case RENDERPATH_GLES1:
1300         case RENDERPATH_GLES2:
1301                 if (gl_state.framebufferobject != fbo)
1302                 {
1303                         gl_state.framebufferobject = fbo;
1304                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);
1305                 }
1306                 break;
1307         case RENDERPATH_D3D9:
1308 #ifdef SUPPORTD3D
1309                 // set up the new render targets, a NULL depthtexture intentionally binds nothing
1310                 // TODO: optimize: keep surface pointer around in rtexture_t until texture is freed or lost
1311                 if (fbo)
1312                 {
1313                         IDirect3DSurface9 *colorsurfaces[4];
1314                         for (i = 0;i < 4;i++)
1315                         {
1316                                 colorsurfaces[i] = NULL;
1317                                 if (textures[i])
1318                                         IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9 *)textures[i]->d3dtexture, 0, &colorsurfaces[i]);
1319                         }
1320                         // set the render targets for real
1321                         R_Mesh_SetRenderTargetsD3D9(depthtexture ? (IDirect3DSurface9 *)depthtexture->d3dtexture : NULL, colorsurfaces[0], colorsurfaces[1], colorsurfaces[2], colorsurfaces[3]);
1322                         // release the texture surface levels (they won't be lost while bound...)
1323                         for (i = 0;i < 4;i++)
1324                                 if (textures[i])
1325                                         IDirect3DSurface9_Release(colorsurfaces[i]);
1326                 }
1327                 else
1328                         R_Mesh_SetRenderTargetsD3D9(gl_state.d3drt_backbufferdepthsurface, gl_state.d3drt_backbuffercolorsurface, NULL, NULL, NULL);
1329 #endif
1330                 break;
1331         case RENDERPATH_D3D10:
1332                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1333                 break;
1334         case RENDERPATH_D3D11:
1335                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1336                 break;
1337         case RENDERPATH_SOFT:
1338                 if (fbo)
1339                 {
1340                         int width, height;
1341                         unsigned int *pointers[5];
1342                         memset(pointers, 0, sizeof(pointers));
1343                         for (i = 0;i < 5;i++)
1344                                 pointers[i] = textures[i] ? (unsigned int *)DPSOFTRAST_Texture_GetPixelPointer(textures[i]->texnum, 0) : NULL;
1345                         width = DPSOFTRAST_Texture_GetWidth(textures[0] ? textures[0]->texnum : textures[4]->texnum, 0);
1346                         height = DPSOFTRAST_Texture_GetHeight(textures[0] ? textures[0]->texnum : textures[4]->texnum, 0);
1347                         DPSOFTRAST_SetRenderTargets(width, height, pointers[4], pointers[0], pointers[1], pointers[2], pointers[3]);
1348                 }
1349                 else
1350                         DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
1351                 break;
1352         }
1353 }
1354
1355 #ifdef SUPPORTD3D
1356 static int d3dcmpforglfunc(int f)
1357 {
1358         switch(f)
1359         {
1360         case GL_NEVER: return D3DCMP_NEVER;
1361         case GL_LESS: return D3DCMP_LESS;
1362         case GL_EQUAL: return D3DCMP_EQUAL;
1363         case GL_LEQUAL: return D3DCMP_LESSEQUAL;
1364         case GL_GREATER: return D3DCMP_GREATER;
1365         case GL_NOTEQUAL: return D3DCMP_NOTEQUAL;
1366         case GL_GEQUAL: return D3DCMP_GREATEREQUAL;
1367         case GL_ALWAYS: return D3DCMP_ALWAYS;
1368         default: Con_DPrintf("Unknown GL_DepthFunc\n");return D3DCMP_ALWAYS;
1369         }
1370 }
1371
1372 static int d3dstencilopforglfunc(int f)
1373 {
1374         switch(f)
1375         {
1376         case GL_KEEP: return D3DSTENCILOP_KEEP;
1377         case GL_INCR: return D3DSTENCILOP_INCR; // note: GL_INCR is clamped, D3DSTENCILOP_INCR wraps
1378         case GL_DECR: return D3DSTENCILOP_DECR; // note: GL_DECR is clamped, D3DSTENCILOP_DECR wraps
1379         default: Con_DPrintf("Unknown GL_StencilFunc\n");return D3DSTENCILOP_KEEP;
1380         }
1381 }
1382 #endif
1383
1384
1385 static void GL_Backend_ResetState(void)
1386 {
1387         unsigned int i;
1388         gl_state.active = true;
1389         gl_state.depthtest = true;
1390         gl_state.alphatest = false;
1391         gl_state.alphafunc = GL_GEQUAL;
1392         gl_state.alphafuncvalue = 0.5f;
1393         gl_state.blendfunc1 = GL_ONE;
1394         gl_state.blendfunc2 = GL_ZERO;
1395         gl_state.blend = false;
1396         gl_state.depthmask = GL_TRUE;
1397         gl_state.colormask = 15;
1398         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
1399         gl_state.lockrange_first = 0;
1400         gl_state.lockrange_count = 0;
1401         gl_state.cullface = GL_FRONT;
1402         gl_state.cullfaceenable = false;
1403         gl_state.polygonoffset[0] = 0;
1404         gl_state.polygonoffset[1] = 0;
1405         gl_state.framebufferobject = 0;
1406         gl_state.depthfunc = GL_LEQUAL;
1407
1408         switch(vid.renderpath)
1409         {
1410         case RENDERPATH_D3D9:
1411 #ifdef SUPPORTD3D
1412                 {
1413                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, gl_state.colormask);
1414                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHATESTENABLE, gl_state.alphatest);
1415                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHAFUNC, d3dcmpforglfunc(gl_state.alphafunc));
1416                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHAREF, (int)bound(0, gl_state.alphafuncvalue * 256.0f, 255));
1417                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_NONE);
1418                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZFUNC, d3dcmpforglfunc(gl_state.depthfunc));
1419                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZENABLE, gl_state.depthtest);
1420                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZWRITEENABLE, gl_state.depthmask);
1421                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SLOPESCALEDEPTHBIAS, gl_state.polygonoffset[0]);
1422                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DEPTHBIAS, gl_state.polygonoffset[1] * (1.0f / 16777216.0f));
1423                 }
1424 #endif
1425                 break;
1426         case RENDERPATH_D3D10:
1427                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1428                 break;
1429         case RENDERPATH_D3D11:
1430                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1431                 break;
1432         case RENDERPATH_GL11:
1433         case RENDERPATH_GL13:
1434         case RENDERPATH_GLES1:
1435                 CHECKGLERROR
1436
1437                 qglColorMask(1, 1, 1, 1);CHECKGLERROR
1438                 qglAlphaFunc(gl_state.alphafunc, gl_state.alphafuncvalue);CHECKGLERROR
1439                 qglDisable(GL_ALPHA_TEST);CHECKGLERROR
1440                 qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1441                 qglDisable(GL_BLEND);CHECKGLERROR
1442                 qglCullFace(gl_state.cullface);CHECKGLERROR
1443                 qglDisable(GL_CULL_FACE);CHECKGLERROR
1444                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1445                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1446                 qglDepthMask(gl_state.depthmask);CHECKGLERROR
1447                 qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1448
1449                 if (vid.support.arb_vertex_buffer_object)
1450                 {
1451                         qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1452                         qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1453                 }
1454
1455                 if (vid.support.ext_framebuffer_object)
1456                 {
1457                         //qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
1458                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1459                 }
1460
1461                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
1462                 qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1463
1464                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
1465                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1466                 qglColor4f(1, 1, 1, 1);CHECKGLERROR
1467
1468                 if (vid.support.ext_framebuffer_object)
1469                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.framebufferobject);
1470
1471                 gl_state.unit = MAX_TEXTUREUNITS;
1472                 gl_state.clientunit = MAX_TEXTUREUNITS;
1473                 for (i = 0;i < vid.texunits;i++)
1474                 {
1475                         GL_ActiveTexture(i);
1476                         GL_ClientActiveTexture(i);
1477                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1478                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1479                         if (vid.support.ext_texture_3d)
1480                         {
1481                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1482                                 qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1483                         }
1484                         if (vid.support.arb_texture_cube_map)
1485                         {
1486                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1487                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1488                         }
1489                         GL_BindVBO(0);
1490                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
1491                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1492                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1493                         qglLoadIdentity();CHECKGLERROR
1494                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1495                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1496                 }
1497                 CHECKGLERROR
1498                 break;
1499         case RENDERPATH_SOFT:
1500                 DPSOFTRAST_ColorMask(1,1,1,1);
1501                 DPSOFTRAST_AlphaTest(gl_state.alphatest);
1502                 DPSOFTRAST_BlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);
1503                 DPSOFTRAST_CullFace(gl_state.cullface);
1504                 DPSOFTRAST_DepthFunc(gl_state.depthfunc);
1505                 DPSOFTRAST_DepthMask(gl_state.depthmask);
1506                 DPSOFTRAST_PolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1507                 DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
1508                 DPSOFTRAST_Viewport(0, 0, vid.width, vid.height);
1509                 break;
1510         case RENDERPATH_GL20:
1511         case RENDERPATH_GLES2:
1512                 CHECKGLERROR
1513                 qglColorMask(1, 1, 1, 1);CHECKGLERROR
1514                 qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1515                 qglDisable(GL_BLEND);CHECKGLERROR
1516                 qglCullFace(gl_state.cullface);CHECKGLERROR
1517                 qglDisable(GL_CULL_FACE);CHECKGLERROR
1518                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1519                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1520                 qglDepthMask(gl_state.depthmask);CHECKGLERROR
1521                 qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1522         //      if (vid.renderpath == RENDERPATH_GL20)
1523         //      {
1524         //              qglAlphaFunc(gl_state.alphafunc, gl_state.alphafuncvalue);CHECKGLERROR
1525         //              qglDisable(GL_ALPHA_TEST);CHECKGLERROR
1526         //      }
1527                 if (vid.support.arb_vertex_buffer_object)
1528                 {
1529                         qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1530                         qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1531                 }
1532                 if (vid.support.ext_framebuffer_object)
1533                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.defaultframebufferobject);
1534                 qglEnableVertexAttribArray(GLSLATTRIB_POSITION);
1535                 qglVertexAttribPointer(GLSLATTRIB_POSITION, 3, GL_FLOAT, false, sizeof(float[3]), NULL);CHECKGLERROR
1536                 qglDisableVertexAttribArray(GLSLATTRIB_COLOR);
1537                 qglVertexAttribPointer(GLSLATTRIB_COLOR, 4, GL_FLOAT, false, sizeof(float[4]), NULL);CHECKGLERROR
1538                 qglVertexAttrib4f(GLSLATTRIB_COLOR, 1, 1, 1, 1);
1539                 gl_state.unit = MAX_TEXTUREUNITS;
1540                 gl_state.clientunit = MAX_TEXTUREUNITS;
1541                 for (i = 0;i < vid.teximageunits;i++)
1542                 {
1543                         GL_ActiveTexture(i);
1544                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1545                         if (vid.support.ext_texture_3d)
1546                         {
1547                                 qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1548                         }
1549                         if (vid.support.arb_texture_cube_map)
1550                         {
1551                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1552                         }
1553                 }
1554                 for (i = 0;i < vid.texarrayunits;i++)
1555                 {
1556                         GL_BindVBO(0);
1557                         qglVertexAttribPointer(i+GLSLATTRIB_TEXCOORD0, 2, GL_FLOAT, false, sizeof(float[2]), NULL);CHECKGLERROR
1558                         qglDisableVertexAttribArray(i+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
1559                 }
1560                 CHECKGLERROR
1561                 break;
1562         }
1563 }
1564
1565 void GL_ActiveTexture(unsigned int num)
1566 {
1567         if (gl_state.unit != num)
1568         {
1569                 gl_state.unit = num;
1570                 switch(vid.renderpath)
1571                 {
1572                 case RENDERPATH_GL11:
1573                 case RENDERPATH_GL13:
1574                 case RENDERPATH_GL20:
1575                 case RENDERPATH_GLES1:
1576                 case RENDERPATH_GLES2:
1577                         if (qglActiveTexture)
1578                         {
1579                                 CHECKGLERROR
1580                                 qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
1581                                 CHECKGLERROR
1582                         }
1583                         break;
1584                 case RENDERPATH_D3D9:
1585                 case RENDERPATH_D3D10:
1586                 case RENDERPATH_D3D11:
1587                         break;
1588                 case RENDERPATH_SOFT:
1589                         break;
1590                 }
1591         }
1592 }
1593
1594 void GL_ClientActiveTexture(unsigned int num)
1595 {
1596         if (gl_state.clientunit != num)
1597         {
1598                 gl_state.clientunit = num;
1599                 switch(vid.renderpath)
1600                 {
1601                 case RENDERPATH_GL11:
1602                 case RENDERPATH_GL13:
1603                 case RENDERPATH_GLES1:
1604                         if (qglActiveTexture)
1605                         {
1606                                 CHECKGLERROR
1607                                 qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
1608                                 CHECKGLERROR
1609                         }
1610                         break;
1611                 case RENDERPATH_D3D9:
1612                 case RENDERPATH_D3D10:
1613                 case RENDERPATH_D3D11:
1614                         break;
1615                 case RENDERPATH_SOFT:
1616                         break;
1617                 case RENDERPATH_GL20:
1618                 case RENDERPATH_GLES2:
1619                         break;
1620                 }
1621         }
1622 }
1623
1624 void GL_BlendFunc(int blendfunc1, int blendfunc2)
1625 {
1626         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
1627         {
1628                 qboolean blendenable;
1629                 gl_state.blendfunc1 = blendfunc1;
1630                 gl_state.blendfunc2 = blendfunc2;
1631                 blendenable = (gl_state.blendfunc1 != GL_ONE || gl_state.blendfunc2 != GL_ZERO);
1632                 switch(vid.renderpath)
1633                 {
1634                 case RENDERPATH_GL11:
1635                 case RENDERPATH_GL13:
1636                 case RENDERPATH_GL20:
1637                 case RENDERPATH_GLES1:
1638                 case RENDERPATH_GLES2:
1639                         CHECKGLERROR
1640                         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
1641                         if (gl_state.blend != blendenable)
1642                         {
1643                                 gl_state.blend = blendenable;
1644                                 if (!gl_state.blend)
1645                                 {
1646                                         qglDisable(GL_BLEND);CHECKGLERROR
1647                                 }
1648                                 else
1649                                 {
1650                                         qglEnable(GL_BLEND);CHECKGLERROR
1651                                 }
1652                         }
1653                         break;
1654                 case RENDERPATH_D3D9:
1655 #ifdef SUPPORTD3D
1656                         {
1657                                 int i;
1658                                 int glblendfunc[2];
1659                                 D3DBLEND d3dblendfunc[2];
1660                                 glblendfunc[0] = gl_state.blendfunc1;
1661                                 glblendfunc[1] = gl_state.blendfunc2;
1662                                 for (i = 0;i < 2;i++)
1663                                 {
1664                                         switch(glblendfunc[i])
1665                                         {
1666                                         case GL_ZERO: d3dblendfunc[i] = D3DBLEND_ZERO;break;
1667                                         case GL_ONE: d3dblendfunc[i] = D3DBLEND_ONE;break;
1668                                         case GL_SRC_COLOR: d3dblendfunc[i] = D3DBLEND_SRCCOLOR;break;
1669                                         case GL_ONE_MINUS_SRC_COLOR: d3dblendfunc[i] = D3DBLEND_INVSRCCOLOR;break;
1670                                         case GL_SRC_ALPHA: d3dblendfunc[i] = D3DBLEND_SRCALPHA;break;
1671                                         case GL_ONE_MINUS_SRC_ALPHA: d3dblendfunc[i] = D3DBLEND_INVSRCALPHA;break;
1672                                         case GL_DST_ALPHA: d3dblendfunc[i] = D3DBLEND_DESTALPHA;break;
1673                                         case GL_ONE_MINUS_DST_ALPHA: d3dblendfunc[i] = D3DBLEND_INVDESTALPHA;break;
1674                                         case GL_DST_COLOR: d3dblendfunc[i] = D3DBLEND_DESTCOLOR;break;
1675                                         case GL_ONE_MINUS_DST_COLOR: d3dblendfunc[i] = D3DBLEND_INVDESTCOLOR;break;
1676                                         }
1677                                 }
1678                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SRCBLEND, d3dblendfunc[0]);
1679                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DESTBLEND, d3dblendfunc[1]);
1680                                 if (gl_state.blend != blendenable)
1681                                 {
1682                                         gl_state.blend = blendenable;
1683                                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHABLENDENABLE, gl_state.blend);
1684                                 }
1685                         }
1686 #endif
1687                         break;
1688                 case RENDERPATH_D3D10:
1689                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1690                         break;
1691                 case RENDERPATH_D3D11:
1692                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1693                         break;
1694                 case RENDERPATH_SOFT:
1695                         DPSOFTRAST_BlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);
1696                         break;
1697                 }
1698         }
1699 }
1700
1701 void GL_DepthMask(int state)
1702 {
1703         if (gl_state.depthmask != state)
1704         {
1705                 gl_state.depthmask = state;
1706                 switch(vid.renderpath)
1707                 {
1708                 case RENDERPATH_GL11:
1709                 case RENDERPATH_GL13:
1710                 case RENDERPATH_GL20:
1711                 case RENDERPATH_GLES1:
1712                 case RENDERPATH_GLES2:
1713                         CHECKGLERROR
1714                         qglDepthMask(gl_state.depthmask);CHECKGLERROR
1715                         break;
1716                 case RENDERPATH_D3D9:
1717 #ifdef SUPPORTD3D
1718                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZWRITEENABLE, gl_state.depthmask);
1719 #endif
1720                         break;
1721                 case RENDERPATH_D3D10:
1722                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1723                         break;
1724                 case RENDERPATH_D3D11:
1725                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1726                         break;
1727                 case RENDERPATH_SOFT:
1728                         DPSOFTRAST_DepthMask(gl_state.depthmask);
1729                         break;
1730                 }
1731         }
1732 }
1733
1734 void GL_DepthTest(int state)
1735 {
1736         if (gl_state.depthtest != state)
1737         {
1738                 gl_state.depthtest = state;
1739                 switch(vid.renderpath)
1740                 {
1741                 case RENDERPATH_GL11:
1742                 case RENDERPATH_GL13:
1743                 case RENDERPATH_GL20:
1744                 case RENDERPATH_GLES1:
1745                 case RENDERPATH_GLES2:
1746                         CHECKGLERROR
1747                         if (gl_state.depthtest)
1748                         {
1749                                 qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1750                         }
1751                         else
1752                         {
1753                                 qglDisable(GL_DEPTH_TEST);CHECKGLERROR
1754                         }
1755                         break;
1756                 case RENDERPATH_D3D9:
1757 #ifdef SUPPORTD3D
1758                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZENABLE, gl_state.depthtest);
1759 #endif
1760                         break;
1761                 case RENDERPATH_D3D10:
1762                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1763                         break;
1764                 case RENDERPATH_D3D11:
1765                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1766                         break;
1767                 case RENDERPATH_SOFT:
1768                         DPSOFTRAST_DepthTest(gl_state.depthtest);
1769                         break;
1770                 }
1771         }
1772 }
1773
1774 void GL_DepthFunc(int state)
1775 {
1776         if (gl_state.depthfunc != state)
1777         {
1778                 gl_state.depthfunc = state;
1779                 switch(vid.renderpath)
1780                 {
1781                 case RENDERPATH_GL11:
1782                 case RENDERPATH_GL13:
1783                 case RENDERPATH_GL20:
1784                 case RENDERPATH_GLES1:
1785                 case RENDERPATH_GLES2:
1786                         CHECKGLERROR
1787                         qglDepthFunc(gl_state.depthfunc);CHECKGLERROR
1788                         break;
1789                 case RENDERPATH_D3D9:
1790 #ifdef SUPPORTD3D
1791                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZFUNC, d3dcmpforglfunc(gl_state.depthfunc));
1792 #endif
1793                         break;
1794                 case RENDERPATH_D3D10:
1795                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1796                         break;
1797                 case RENDERPATH_D3D11:
1798                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1799                         break;
1800                 case RENDERPATH_SOFT:
1801                         DPSOFTRAST_DepthFunc(gl_state.depthfunc);
1802                         break;
1803                 }
1804         }
1805 }
1806
1807 void GL_DepthRange(float nearfrac, float farfrac)
1808 {
1809         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
1810         {
1811                 gl_state.depthrange[0] = nearfrac;
1812                 gl_state.depthrange[1] = farfrac;
1813                 switch(vid.renderpath)
1814                 {
1815                 case RENDERPATH_GL11:
1816                 case RENDERPATH_GL13:
1817                 case RENDERPATH_GL20:
1818                 case RENDERPATH_GLES1:
1819                 case RENDERPATH_GLES2:
1820                         qglDepthRange(gl_state.depthrange[0], gl_state.depthrange[1]);
1821                         break;
1822                 case RENDERPATH_D3D9:
1823 #ifdef SUPPORTD3D
1824                         {
1825                                 D3DVIEWPORT9 d3dviewport;
1826                                 d3dviewport.X = gl_viewport.x;
1827                                 d3dviewport.Y = gl_viewport.y;
1828                                 d3dviewport.Width = gl_viewport.width;
1829                                 d3dviewport.Height = gl_viewport.height;
1830                                 d3dviewport.MinZ = gl_state.depthrange[0];
1831                                 d3dviewport.MaxZ = gl_state.depthrange[1];
1832                                 IDirect3DDevice9_SetViewport(vid_d3d9dev, &d3dviewport);
1833                         }
1834 #endif
1835                         break;
1836                 case RENDERPATH_D3D10:
1837                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1838                         break;
1839                 case RENDERPATH_D3D11:
1840                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1841                         break;
1842                 case RENDERPATH_SOFT:
1843                         DPSOFTRAST_DepthRange(gl_state.depthrange[0], gl_state.depthrange[1]);
1844                         break;
1845                 }
1846         }
1847 }
1848
1849 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)
1850 {
1851         switch (vid.renderpath)
1852         {
1853         case RENDERPATH_GL11:
1854         case RENDERPATH_GL13:
1855         case RENDERPATH_GL20:
1856         case RENDERPATH_GLES1:
1857         case RENDERPATH_GLES2:
1858                 CHECKGLERROR
1859                 if (enable)
1860                 {
1861                         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1862                 }
1863                 else
1864                 {
1865                         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1866                 }
1867                 if (vid.support.ati_separate_stencil)
1868                 {
1869                         qglStencilMask(writemask);CHECKGLERROR
1870                         qglStencilOpSeparate(GL_FRONT, frontfail, frontzfail, frontzpass);CHECKGLERROR
1871                         qglStencilOpSeparate(GL_BACK, backfail, backzfail, backzpass);CHECKGLERROR
1872                         qglStencilFuncSeparate(frontcompare, backcompare, comparereference, comparereference);CHECKGLERROR
1873                 }
1874                 else if (vid.support.ext_stencil_two_side)
1875                 {
1876                         qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1877                         qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR
1878                         qglStencilMask(writemask);CHECKGLERROR
1879                         qglStencilOp(frontfail, frontzfail, frontzpass);CHECKGLERROR
1880                         qglStencilFunc(frontcompare, comparereference, comparemask);CHECKGLERROR
1881                         qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR
1882                         qglStencilMask(writemask);CHECKGLERROR
1883                         qglStencilOp(backfail, backzfail, backzpass);CHECKGLERROR
1884                         qglStencilFunc(backcompare, comparereference, comparemask);CHECKGLERROR
1885                 }
1886                 break;
1887         case RENDERPATH_D3D9:
1888 #ifdef SUPPORTD3D
1889                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_TWOSIDEDSTENCILMODE, true);
1890                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILENABLE, enable);
1891                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILWRITEMASK, writemask);
1892                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFAIL, d3dstencilopforglfunc(frontfail));
1893                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILZFAIL, d3dstencilopforglfunc(frontzfail));
1894                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILPASS, d3dstencilopforglfunc(frontzpass));
1895                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFUNC, d3dcmpforglfunc(frontcompare));
1896                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILFAIL, d3dstencilopforglfunc(backfail));
1897                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILZFAIL, d3dstencilopforglfunc(backzfail));
1898                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILPASS, d3dstencilopforglfunc(backzpass));
1899                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILFUNC, d3dcmpforglfunc(backcompare));
1900                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILREF, comparereference);
1901                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILMASK, comparemask);
1902 #endif
1903                 break;
1904         case RENDERPATH_D3D10:
1905                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1906                 break;
1907         case RENDERPATH_D3D11:
1908                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1909                 break;
1910         case RENDERPATH_SOFT:
1911                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1912                 break;
1913         }
1914 }
1915
1916 void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass, int compare, int comparereference, int comparemask)
1917 {
1918         switch (vid.renderpath)
1919         {
1920         case RENDERPATH_GL11:
1921         case RENDERPATH_GL13:
1922         case RENDERPATH_GL20:
1923         case RENDERPATH_GLES1:
1924         case RENDERPATH_GLES2:
1925                 CHECKGLERROR
1926                 if (enable)
1927                 {
1928                         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1929                 }
1930                 else
1931                 {
1932                         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1933                 }
1934                 if (vid.support.ext_stencil_two_side)
1935                 {
1936                         qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1937                 }
1938                 qglStencilMask(writemask);CHECKGLERROR
1939                 qglStencilOp(fail, zfail, zpass);CHECKGLERROR
1940                 qglStencilFunc(compare, comparereference, comparemask);CHECKGLERROR
1941                 CHECKGLERROR
1942                 break;
1943         case RENDERPATH_D3D9:
1944 #ifdef SUPPORTD3D
1945                 if (vid.support.ati_separate_stencil)
1946                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_TWOSIDEDSTENCILMODE, true);
1947                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILENABLE, enable);
1948                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILWRITEMASK, writemask);
1949                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFAIL, d3dstencilopforglfunc(fail));
1950                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILZFAIL, d3dstencilopforglfunc(zfail));
1951                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILPASS, d3dstencilopforglfunc(zpass));
1952                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFUNC, d3dcmpforglfunc(compare));
1953                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILREF, comparereference);
1954                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILMASK, comparemask);
1955 #endif
1956                 break;
1957         case RENDERPATH_D3D10:
1958                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1959                 break;
1960         case RENDERPATH_D3D11:
1961                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1962                 break;
1963         case RENDERPATH_SOFT:
1964                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1965                 break;
1966         }
1967 }
1968
1969 void GL_PolygonOffset(float planeoffset, float depthoffset)
1970 {
1971         if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset)
1972         {
1973                 gl_state.polygonoffset[0] = planeoffset;
1974                 gl_state.polygonoffset[1] = depthoffset;
1975                 switch(vid.renderpath)
1976                 {
1977                 case RENDERPATH_GL11:
1978                 case RENDERPATH_GL13:
1979                 case RENDERPATH_GL20:
1980                 case RENDERPATH_GLES1:
1981                 case RENDERPATH_GLES2:
1982                         qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1983                         break;
1984                 case RENDERPATH_D3D9:
1985 #ifdef SUPPORTD3D
1986                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SLOPESCALEDEPTHBIAS, gl_state.polygonoffset[0]);
1987                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DEPTHBIAS, gl_state.polygonoffset[1] * (1.0f / 16777216.0f));
1988 #endif
1989                         break;
1990                 case RENDERPATH_D3D10:
1991                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1992                         break;
1993                 case RENDERPATH_D3D11:
1994                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
1995                         break;
1996                 case RENDERPATH_SOFT:
1997                         DPSOFTRAST_PolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
1998                         break;
1999                 }
2000         }
2001 }
2002
2003 void GL_SetMirrorState(qboolean state)
2004 {
2005         if (v_flipped_state != state)
2006         {
2007                 v_flipped_state = state;
2008                 if (gl_state.cullface == GL_BACK)
2009                         gl_state.cullface = GL_FRONT;
2010                 else if (gl_state.cullface == GL_FRONT)
2011                         gl_state.cullface = GL_BACK;
2012                 else
2013                         return;
2014                 switch(vid.renderpath)
2015                 {
2016                 case RENDERPATH_GL11:
2017                 case RENDERPATH_GL13:
2018                 case RENDERPATH_GL20:
2019                 case RENDERPATH_GLES1:
2020                 case RENDERPATH_GLES2:
2021                         qglCullFace(gl_state.cullface);CHECKGLERROR
2022                         break;
2023                 case RENDERPATH_D3D9:
2024 #ifdef SUPPORTD3D
2025                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, gl_state.cullface == GL_FRONT ? D3DCULL_CCW : D3DCULL_CW);
2026 #endif
2027                         break;
2028                 case RENDERPATH_D3D10:
2029                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2030                         break;
2031                 case RENDERPATH_D3D11:
2032                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2033                         break;
2034                 case RENDERPATH_SOFT:
2035                         DPSOFTRAST_CullFace(gl_state.cullface);
2036                         break;
2037                 }
2038         }
2039 }
2040
2041 void GL_CullFace(int state)
2042 {
2043         if(v_flipped_state)
2044         {
2045                 if(state == GL_FRONT)
2046                         state = GL_BACK;
2047                 else if(state == GL_BACK)
2048                         state = GL_FRONT;
2049         }
2050
2051         switch(vid.renderpath)
2052         {
2053         case RENDERPATH_GL11:
2054         case RENDERPATH_GL13:
2055         case RENDERPATH_GL20:
2056         case RENDERPATH_GLES1:
2057         case RENDERPATH_GLES2:
2058                 CHECKGLERROR
2059
2060                 if (state != GL_NONE)
2061                 {
2062                         if (!gl_state.cullfaceenable)
2063                         {
2064                                 gl_state.cullfaceenable = true;
2065                                 qglEnable(GL_CULL_FACE);CHECKGLERROR
2066                         }
2067                         if (gl_state.cullface != state)
2068                         {
2069                                 gl_state.cullface = state;
2070                                 qglCullFace(gl_state.cullface);CHECKGLERROR
2071                         }
2072                 }
2073                 else
2074                 {
2075                         if (gl_state.cullfaceenable)
2076                         {
2077                                 gl_state.cullfaceenable = false;
2078                                 qglDisable(GL_CULL_FACE);CHECKGLERROR
2079                         }
2080                 }
2081                 break;
2082         case RENDERPATH_D3D9:
2083 #ifdef SUPPORTD3D
2084                 if (gl_state.cullface != state)
2085                 {
2086                         gl_state.cullface = state;
2087                         switch(gl_state.cullface)
2088                         {
2089                         case GL_NONE:
2090                                 gl_state.cullfaceenable = false;
2091                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_NONE);
2092                                 break;
2093                         case GL_FRONT:
2094                                 gl_state.cullfaceenable = true;
2095                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_CCW);
2096                                 break;
2097                         case GL_BACK:
2098                                 gl_state.cullfaceenable = true;
2099                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_CW);
2100                                 break;
2101                         }
2102                 }
2103 #endif
2104                 break;
2105         case RENDERPATH_D3D10:
2106                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2107                 break;
2108         case RENDERPATH_D3D11:
2109                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2110                 break;
2111         case RENDERPATH_SOFT:
2112                 if (gl_state.cullface != state)
2113                 {
2114                         gl_state.cullface = state;
2115                         gl_state.cullfaceenable = state != GL_NONE ? true : false;
2116                         DPSOFTRAST_CullFace(gl_state.cullface);
2117                 }
2118                 break;
2119         }
2120 }
2121
2122 void GL_AlphaTest(int state)
2123 {
2124         if (gl_state.alphatest != state)
2125         {
2126                 gl_state.alphatest = state;
2127                 switch(vid.renderpath)
2128                 {
2129                 case RENDERPATH_GL11:
2130                 case RENDERPATH_GL13:
2131                 case RENDERPATH_GLES1:
2132                         // only fixed function uses alpha test, other paths use pixel kill capability in shaders
2133                         CHECKGLERROR
2134                         if (gl_state.alphatest)
2135                         {
2136                                 qglEnable(GL_ALPHA_TEST);CHECKGLERROR
2137                         }
2138                         else
2139                         {
2140                                 qglDisable(GL_ALPHA_TEST);CHECKGLERROR
2141                         }
2142                         break;
2143                 case RENDERPATH_D3D9:
2144 #ifdef SUPPORTD3D
2145 //                      IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHATESTENABLE, gl_state.alphatest);
2146 #endif
2147                         break;
2148                 case RENDERPATH_D3D10:
2149                         break;
2150                 case RENDERPATH_D3D11:
2151                         break;
2152                 case RENDERPATH_SOFT:
2153 //                      DPSOFTRAST_AlphaTest(gl_state.alphatest);
2154                         break;
2155                 case RENDERPATH_GL20:
2156                 case RENDERPATH_GLES2:
2157                         break;
2158                 }
2159         }
2160 }
2161
2162 void GL_ColorMask(int r, int g, int b, int a)
2163 {
2164         // NOTE: this matches D3DCOLORWRITEENABLE_RED, GREEN, BLUE, ALPHA
2165         int state = (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0) | (a ? 8 : 0);
2166         if (gl_state.colormask != state)
2167         {
2168                 gl_state.colormask = state;
2169                 switch(vid.renderpath)
2170                 {
2171                 case RENDERPATH_GL11:
2172                 case RENDERPATH_GL13:
2173                 case RENDERPATH_GL20:
2174                 case RENDERPATH_GLES1:
2175                 case RENDERPATH_GLES2:
2176                         CHECKGLERROR
2177                         qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
2178                         break;
2179                 case RENDERPATH_D3D9:
2180 #ifdef SUPPORTD3D
2181                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, state);
2182 #endif
2183                         break;
2184                 case RENDERPATH_D3D10:
2185                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2186                         break;
2187                 case RENDERPATH_D3D11:
2188                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2189                         break;
2190                 case RENDERPATH_SOFT:
2191                         DPSOFTRAST_ColorMask(r, g, b, a);
2192                         break;
2193                 }
2194         }
2195 }
2196
2197 void GL_Color(float cr, float cg, float cb, float ca)
2198 {
2199         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)
2200         {
2201                 gl_state.color4f[0] = cr;
2202                 gl_state.color4f[1] = cg;
2203                 gl_state.color4f[2] = cb;
2204                 gl_state.color4f[3] = ca;
2205                 switch(vid.renderpath)
2206                 {
2207                 case RENDERPATH_GL11:
2208                 case RENDERPATH_GL13:
2209                 case RENDERPATH_GLES1:
2210                         CHECKGLERROR
2211                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
2212                         CHECKGLERROR
2213                         break;
2214                 case RENDERPATH_D3D9:
2215                 case RENDERPATH_D3D10:
2216                 case RENDERPATH_D3D11:
2217                         // no equivalent in D3D
2218                         break;
2219                 case RENDERPATH_SOFT:
2220                         DPSOFTRAST_Color4f(cr, cg, cb, ca);
2221                         break;
2222                 case RENDERPATH_GL20:
2223                 case RENDERPATH_GLES2:
2224                         qglVertexAttrib4f(GLSLATTRIB_COLOR, cr, cg, cb, ca);
2225                         break;
2226                 }
2227         }
2228 }
2229
2230 void GL_Scissor (int x, int y, int width, int height)
2231 {
2232         switch(vid.renderpath)
2233         {
2234         case RENDERPATH_GL11:
2235         case RENDERPATH_GL13:
2236         case RENDERPATH_GL20:
2237         case RENDERPATH_GLES1:
2238         case RENDERPATH_GLES2:
2239                 CHECKGLERROR
2240                 qglScissor(x, y,width,height);
2241                 CHECKGLERROR
2242                 break;
2243         case RENDERPATH_D3D9:
2244 #ifdef SUPPORTD3D
2245                 {
2246                         RECT d3drect;
2247                         d3drect.left = x;
2248                         d3drect.top = y;
2249                         d3drect.right = x + width;
2250                         d3drect.bottom = y + height;
2251                         IDirect3DDevice9_SetScissorRect(vid_d3d9dev, &d3drect);
2252                 }
2253 #endif
2254                 break;
2255         case RENDERPATH_D3D10:
2256                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2257                 break;
2258         case RENDERPATH_D3D11:
2259                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2260                 break;
2261         case RENDERPATH_SOFT:
2262                 DPSOFTRAST_Scissor(x, y, width, height);
2263                 break;
2264         }
2265 }
2266
2267 void GL_ScissorTest(int state)
2268 {
2269         if (gl_state.scissortest != state)
2270         {
2271                 gl_state.scissortest = state;
2272                 switch(vid.renderpath)
2273                 {
2274                 case RENDERPATH_GL11:
2275                 case RENDERPATH_GL13:
2276                 case RENDERPATH_GL20:
2277                 case RENDERPATH_GLES1:
2278                 case RENDERPATH_GLES2:
2279                         CHECKGLERROR
2280                         if(gl_state.scissortest)
2281                                 qglEnable(GL_SCISSOR_TEST);
2282                         else
2283                                 qglDisable(GL_SCISSOR_TEST);
2284                         CHECKGLERROR
2285                         break;
2286                 case RENDERPATH_D3D9:
2287 #ifdef SUPPORTD3D
2288                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SCISSORTESTENABLE, gl_state.scissortest);
2289 #endif
2290                         break;
2291                 case RENDERPATH_D3D10:
2292                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2293                         break;
2294                 case RENDERPATH_D3D11:
2295                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2296                         break;
2297                 case RENDERPATH_SOFT:
2298                         DPSOFTRAST_ScissorTest(gl_state.scissortest);
2299                         break;
2300                 }
2301         }
2302 }
2303
2304 void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilvalue)
2305 {
2306         static const float blackcolor[4] = {0, 0, 0, 0};
2307         // prevent warnings when trying to clear a buffer that does not exist
2308         if (!colorvalue)
2309                 colorvalue = blackcolor;
2310         if (!vid.stencil)
2311         {
2312                 mask &= ~GL_STENCIL_BUFFER_BIT;
2313                 stencilvalue = 0;
2314         }
2315         switch(vid.renderpath)
2316         {
2317         case RENDERPATH_GL11:
2318         case RENDERPATH_GL13:
2319         case RENDERPATH_GL20:
2320         case RENDERPATH_GLES1:
2321         case RENDERPATH_GLES2:
2322                 CHECKGLERROR
2323                 if (mask & GL_COLOR_BUFFER_BIT)
2324                 {
2325                         qglClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);CHECKGLERROR
2326                 }
2327                 if (mask & GL_DEPTH_BUFFER_BIT)
2328                 {
2329                         qglClearDepth(depthvalue);CHECKGLERROR
2330                 }
2331                 if (mask & GL_STENCIL_BUFFER_BIT)
2332                 {
2333                         qglClearStencil(stencilvalue);CHECKGLERROR
2334                 }
2335                 qglClear(mask);CHECKGLERROR
2336                 break;
2337         case RENDERPATH_D3D9:
2338 #ifdef SUPPORTD3D
2339                 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);
2340 #endif
2341                 break;
2342         case RENDERPATH_D3D10:
2343                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2344                 break;
2345         case RENDERPATH_D3D11:
2346                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2347                 break;
2348         case RENDERPATH_SOFT:
2349                 if (mask & GL_COLOR_BUFFER_BIT)
2350                         DPSOFTRAST_ClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);
2351                 if (mask & GL_DEPTH_BUFFER_BIT)
2352                         DPSOFTRAST_ClearDepth(depthvalue);
2353                 break;
2354         }
2355 }
2356
2357 void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels)
2358 {
2359         switch(vid.renderpath)
2360         {
2361         case RENDERPATH_GL11:
2362         case RENDERPATH_GL13:
2363         case RENDERPATH_GL20:
2364         case RENDERPATH_GLES1:
2365         case RENDERPATH_GLES2:
2366                 CHECKGLERROR
2367                 qglReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, outpixels);CHECKGLERROR
2368                 break;
2369         case RENDERPATH_D3D9:
2370 #ifdef SUPPORTD3D
2371                 {
2372                         // LordHavoc: we can't directly download the backbuffer because it may be
2373                         // multisampled, and it may not be lockable, so we blit it to a lockable
2374                         // surface of the same dimensions (but without multisample) to resolve the
2375                         // multisample buffer to a normal image, and then lock that...
2376                         IDirect3DSurface9 *stretchsurface = NULL;
2377                         if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &stretchsurface, NULL)))
2378                         {
2379                                 D3DLOCKED_RECT lockedrect;
2380                                 if (!FAILED(IDirect3DDevice9_StretchRect(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, NULL, stretchsurface, NULL, D3DTEXF_POINT)))
2381                                 {
2382                                         if (!FAILED(IDirect3DSurface9_LockRect(stretchsurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2383                                         {
2384                                                 int line;
2385                                                 unsigned char *row = (unsigned char *)lockedrect.pBits + x * 4 + lockedrect.Pitch * (vid.height - 1 - y);
2386                                                 for (line = 0;line < height;line++, row -= lockedrect.Pitch)
2387                                                         memcpy(outpixels + line * width * 4, row, width * 4);
2388                                                 IDirect3DSurface9_UnlockRect(stretchsurface);
2389                                         }
2390                                 }
2391                                 IDirect3DSurface9_Release(stretchsurface);
2392                         }
2393                         // code scraps
2394                         //IDirect3DSurface9 *syssurface = NULL;
2395                         //if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &stretchsurface, NULL)))
2396                         //if (!FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &syssurface, NULL)))
2397                         //IDirect3DDevice9_GetRenderTargetData(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, syssurface);
2398                         //if (!FAILED(IDirect3DDevice9_GetFrontBufferData(vid_d3d9dev, 0, syssurface)))
2399                         //if (!FAILED(IDirect3DSurface9_LockRect(syssurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2400                         //IDirect3DSurface9_UnlockRect(syssurface);
2401                         //IDirect3DSurface9_Release(syssurface);
2402                 }
2403 #endif
2404                 break;
2405         case RENDERPATH_D3D10:
2406                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2407                 break;
2408         case RENDERPATH_D3D11:
2409                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2410                 break;
2411         case RENDERPATH_SOFT:
2412                 DPSOFTRAST_GetPixelsBGRA(x, y, width, height, outpixels);
2413                 break;
2414         }
2415 }
2416
2417 // called at beginning of frame
2418 void R_Mesh_Start(void)
2419 {
2420         BACKENDACTIVECHECK
2421         R_Mesh_ResetRenderTargets();
2422         R_Mesh_SetUseVBO();
2423         if (gl_printcheckerror.integer && !gl_paranoid.integer)
2424         {
2425                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
2426                 Cvar_SetValueQuick(&gl_paranoid, 1);
2427         }
2428 }
2429
2430 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
2431 {
2432         int shaderobject;
2433         int shadercompiled;
2434         char compilelog[MAX_INPUTLINE];
2435         shaderobject = qglCreateShader(shadertypeenum);CHECKGLERROR
2436         if (!shaderobject)
2437                 return false;
2438         qglShaderSource(shaderobject, numstrings, strings, NULL);CHECKGLERROR
2439         qglCompileShader(shaderobject);CHECKGLERROR
2440         qglGetShaderiv(shaderobject, GL_COMPILE_STATUS, &shadercompiled);CHECKGLERROR
2441         qglGetShaderInfoLog(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
2442         if (compilelog[0] && (strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error") || strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")))
2443         {
2444                 int i, j, pretextlines = 0;
2445                 for (i = 0;i < numstrings - 1;i++)
2446                         for (j = 0;strings[i][j];j++)
2447                                 if (strings[i][j] == '\n')
2448                                         pretextlines++;
2449                 Con_Printf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
2450         }
2451         if (!shadercompiled)
2452         {
2453                 qglDeleteShader(shaderobject);CHECKGLERROR
2454                 return false;
2455         }
2456         qglAttachShader(programobject, shaderobject);CHECKGLERROR
2457         qglDeleteShader(shaderobject);CHECKGLERROR
2458         return true;
2459 }
2460
2461 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)
2462 {
2463         GLint programlinked;
2464         GLuint programobject = 0;
2465         char linklog[MAX_INPUTLINE];
2466         CHECKGLERROR
2467
2468         programobject = qglCreateProgram();CHECKGLERROR
2469         if (!programobject)
2470                 return 0;
2471
2472         qglBindAttribLocation(programobject, GLSLATTRIB_POSITION , "Attrib_Position" );
2473         qglBindAttribLocation(programobject, GLSLATTRIB_COLOR    , "Attrib_Color"    );
2474         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD0, "Attrib_TexCoord0");
2475         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD1, "Attrib_TexCoord1");
2476         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD2, "Attrib_TexCoord2");
2477         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD3, "Attrib_TexCoord3");
2478         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD4, "Attrib_TexCoord4");
2479         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD5, "Attrib_TexCoord5");
2480         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD6, "Attrib_TexCoord6");
2481         qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD7, "Attrib_TexCoord7");
2482         if(vid.support.gl20shaders130)
2483                 qglBindFragDataLocation(programobject, 0, "dp_FragColor");
2484
2485         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER, "vertex", vertexstrings_count, vertexstrings_list))
2486                 goto cleanup;
2487
2488 #ifdef GL_GEOMETRY_SHADER
2489         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER, "geometry", geometrystrings_count, geometrystrings_list))
2490                 goto cleanup;
2491 #endif
2492
2493         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER, "fragment", fragmentstrings_count, fragmentstrings_list))
2494                 goto cleanup;
2495
2496         qglLinkProgram(programobject);CHECKGLERROR
2497         qglGetProgramiv(programobject, GL_LINK_STATUS, &programlinked);CHECKGLERROR
2498         qglGetProgramInfoLog(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
2499         if (linklog[0])
2500         {
2501                 if (strstr(linklog, "error") || strstr(linklog, "ERROR") || strstr(linklog, "Error") || strstr(linklog, "WARNING") || strstr(linklog, "warning") || strstr(linklog, "Warning"))
2502                         Con_DPrintf("program link log:\n%s\n", linklog);
2503                 // software vertex shader is ok but software fragment shader is WAY
2504                 // too slow, fail program if so.
2505                 // NOTE: this string might be ATI specific, but that's ok because the
2506                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
2507                 // software fragment shader due to low instruction and dependent
2508                 // texture limits.
2509                 if (strstr(linklog, "fragment shader will run in software"))
2510                         programlinked = false;
2511         }
2512         if (!programlinked)
2513                 goto cleanup;
2514         return programobject;
2515 cleanup:
2516         qglDeleteProgram(programobject);CHECKGLERROR
2517         return 0;
2518 }
2519
2520 void GL_Backend_FreeProgram(unsigned int prog)
2521 {
2522         CHECKGLERROR
2523         qglDeleteProgram(prog);
2524         CHECKGLERROR
2525 }
2526
2527 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
2528 {
2529         int i;
2530         if (offset)
2531         {
2532                 for (i = 0;i < count;i++)
2533                         *out++ = *in++ + offset;
2534         }
2535         else
2536                 memcpy(out, in, sizeof(*out) * count);
2537 }
2538
2539 // renders triangles using vertices from the active arrays
2540 int paranoidblah = 0;
2541 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)
2542 {
2543         unsigned int numelements = numtriangles * 3;
2544         int bufferobject3i;
2545         size_t bufferoffset3i;
2546         int bufferobject3s;
2547         size_t bufferoffset3s;
2548         if (numvertices < 3 || numtriangles < 1)
2549         {
2550                 if (numvertices < 0 || numtriangles < 0 || developer_extra.integer)
2551                         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);
2552                 return;
2553         }
2554         if (!gl_mesh_prefer_short_elements.integer)
2555         {
2556                 if (element3i)
2557                         element3s = NULL;
2558                 if (element3i_indexbuffer)
2559                         element3i_indexbuffer = NULL;
2560         }
2561         // adjust the pointers for firsttriangle
2562         if (element3i)
2563                 element3i += firsttriangle * 3;
2564         if (element3i_indexbuffer)
2565                 element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i);
2566         if (element3s)
2567                 element3s += firsttriangle * 3;
2568         if (element3s_indexbuffer)
2569                 element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
2570         switch(vid.renderpath)
2571         {
2572         case RENDERPATH_GL11:
2573         case RENDERPATH_GL13:
2574         case RENDERPATH_GL20:
2575         case RENDERPATH_GLES1:
2576         case RENDERPATH_GLES2:
2577                 // check if the user specified to ignore static index buffers
2578                 if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset)))
2579                 {
2580                         element3i_indexbuffer = NULL;
2581                         element3s_indexbuffer = NULL;
2582                 }
2583                 break;
2584         case RENDERPATH_D3D9:
2585         case RENDERPATH_D3D10:
2586         case RENDERPATH_D3D11:
2587                 break;
2588         case RENDERPATH_SOFT:
2589                 break;
2590         }
2591         // upload a dynamic index buffer if needed
2592         if (element3s)
2593         {
2594                 if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex)
2595                 {
2596                         if (gl_state.draw_dynamicindexbuffer)
2597                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3s, numelements * sizeof(*element3s));
2598                         else
2599                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3s, numelements * sizeof(*element3s), "temporary", true, true, true);
2600                         element3s_indexbuffer = gl_state.draw_dynamicindexbuffer;
2601                         element3s_bufferoffset = 0;
2602                 }
2603         }
2604         else if (element3i)
2605         {
2606                 if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex)
2607                 {
2608                         if (gl_state.draw_dynamicindexbuffer)
2609                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3i, numelements * sizeof(*element3i));
2610                         else
2611                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3i, numelements * sizeof(*element3i), "temporary", true, true, false);
2612                         element3i_indexbuffer = gl_state.draw_dynamicindexbuffer;
2613                         element3i_bufferoffset = 0;
2614                 }
2615         }
2616         bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
2617         bufferoffset3i = element3i_bufferoffset;
2618         bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0;
2619         bufferoffset3s = element3s_bufferoffset;
2620         r_refdef.stats.draws++;
2621         r_refdef.stats.draws_vertices += numvertices;
2622         r_refdef.stats.draws_elements += numelements;
2623         if (gl_paranoid.integer)
2624         {
2625                 unsigned int i;
2626                 // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
2627 #if 0
2628                 unsigned int j, size;
2629                 const int *p;
2630                 // note: there's no validation done here on buffer objects because it
2631                 // is somewhat difficult to get at the data, and gl_paranoid can be
2632                 // used without buffer objects if the need arises
2633                 // (the data could be gotten using glMapBuffer but it would be very
2634                 //  slow due to uncachable video memory reads)
2635                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
2636                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
2637                 CHECKGLERROR
2638                 if (gl_state.pointer_vertex_pointer)
2639                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
2640                                 paranoidblah += *p;
2641                 if (gl_state.pointer_color_enabled)
2642                 {
2643                         if (!qglIsEnabled(GL_COLOR_ARRAY))
2644                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
2645                         CHECKGLERROR
2646                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
2647                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
2648                                         paranoidblah += *p;
2649                 }
2650                 for (i = 0;i < vid.texarrayunits;i++)
2651                 {
2652                         if (gl_state.units[i].arrayenabled)
2653                         {
2654                                 GL_ClientActiveTexture(i);
2655                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
2656                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
2657                                 CHECKGLERROR
2658                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
2659                                         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++)
2660                                                 paranoidblah += *p;
2661                         }
2662                 }
2663 #endif
2664                 if (element3i)
2665                 {
2666                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2667                         {
2668                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
2669                                 {
2670                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
2671                                         return;
2672                                 }
2673                         }
2674                 }
2675                 if (element3s)
2676                 {
2677                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2678                         {
2679                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
2680                                 {
2681                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
2682                                         return;
2683                                 }
2684                         }
2685                 }
2686         }
2687         if (r_render.integer || r_refdef.draw2dstage)
2688         {
2689                 switch(vid.renderpath)
2690                 {
2691                 case RENDERPATH_GL11:
2692                 case RENDERPATH_GL13:
2693                 case RENDERPATH_GL20:
2694                         CHECKGLERROR
2695                         if (gl_mesh_testmanualfeeding.integer)
2696                         {
2697                                 unsigned int i, j, element;
2698                                 const GLfloat *p;
2699                                 qglBegin(GL_TRIANGLES);
2700                                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2701                                 {
2702                                         if (element3i)
2703                                                 element = element3i[i];
2704                                         else if (element3s)
2705                                                 element = element3s[i];
2706                                         else
2707                                                 element = firstvertex + i;
2708                                         for (j = 0;j < vid.texarrayunits;j++)
2709                                         {
2710                                                 if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
2711                                                 {
2712                                                         if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
2713                                                         {
2714                                                                 p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2715                                                                 if (vid.texarrayunits > 1)
2716                                                                 {
2717                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2718                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
2719                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2720                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
2721                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2722                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
2723                                                                         else
2724                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
2725                                                                 }
2726                                                                 else
2727                                                                 {
2728                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2729                                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
2730                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2731                                                                                 qglTexCoord3f(p[0], p[1], p[2]);
2732                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2733                                                                                 qglTexCoord2f(p[0], p[1]);
2734                                                                         else
2735                                                                                 qglTexCoord1f(p[0]);
2736                                                                 }
2737                                                         }
2738                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
2739                                                         {
2740                                                                 const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2741                                                                 if (vid.texarrayunits > 1)
2742                                                                 {
2743                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2744                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
2745                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2746                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]);
2747                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2748                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
2749                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2750                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
2751                                                                 }
2752                                                                 else
2753                                                                 {
2754                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2755                                                                                 qglTexCoord4f(s[0], s[1], s[2], s[3]);
2756                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2757                                                                                 qglTexCoord3f(s[0], s[1], s[2]);
2758                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2759                                                                                 qglTexCoord2f(s[0], s[1]);
2760                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2761                                                                                 qglTexCoord1f(s[0]);
2762                                                                 }
2763                                                         }
2764                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
2765                                                         {
2766                                                                 const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2767                                                                 if (vid.texarrayunits > 1)
2768                                                                 {
2769                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2770                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
2771                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2772                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]);
2773                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2774                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
2775                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2776                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
2777                                                                 }
2778                                                                 else
2779                                                                 {
2780                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2781                                                                                 qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
2782                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2783                                                                                 qglTexCoord3f(sb[0], sb[1], sb[2]);
2784                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2785                                                                                 qglTexCoord2f(sb[0], sb[1]);
2786                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2787                                                                                 qglTexCoord1f(sb[0]);
2788                                                                 }
2789                                                         }
2790                                                 }
2791                                         }
2792                                         if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
2793                                         {
2794                                                 if (gl_state.pointer_color_gltype == GL_FLOAT)
2795                                                 {
2796                                                         p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2797                                                         qglColor4f(p[0], p[1], p[2], p[3]);
2798                                                 }
2799                                                 else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
2800                                                 {
2801                                                         const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2802                                                         qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
2803                                                 }
2804                                         }
2805                                         if (gl_state.pointer_vertex_gltype == GL_FLOAT)
2806                                         {
2807                                                 p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
2808                                                 if (gl_state.pointer_vertex_components == 4)
2809                                                         qglVertex4f(p[0], p[1], p[2], p[3]);
2810                                                 else if (gl_state.pointer_vertex_components == 3)
2811                                                         qglVertex3f(p[0], p[1], p[2]);
2812                                                 else
2813                                                         qglVertex2f(p[0], p[1]);
2814                                         }
2815                                 }
2816                                 qglEnd();
2817                                 CHECKGLERROR
2818                         }
2819                         else if (bufferobject3s)
2820                         {
2821                                 GL_BindEBO(bufferobject3s);
2822                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2823                                 {
2824                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
2825                                         CHECKGLERROR
2826                                 }
2827                                 else
2828                                 {
2829                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
2830                                         CHECKGLERROR
2831                                 }
2832                         }
2833                         else if (bufferobject3i)
2834                         {
2835                                 GL_BindEBO(bufferobject3i);
2836                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2837                                 {
2838                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
2839                                         CHECKGLERROR
2840                                 }
2841                                 else
2842                                 {
2843                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
2844                                         CHECKGLERROR
2845                                 }
2846                         }
2847                         else if (element3s)
2848                         {
2849                                 GL_BindEBO(0);
2850                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2851                                 {
2852                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
2853                                         CHECKGLERROR
2854                                 }
2855                                 else
2856                                 {
2857                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
2858                                         CHECKGLERROR
2859                                 }
2860                         }
2861                         else if (element3i)
2862                         {
2863                                 GL_BindEBO(0);
2864                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2865                                 {
2866                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
2867                                         CHECKGLERROR
2868                                 }
2869                                 else
2870                                 {
2871                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
2872                                         CHECKGLERROR
2873                                 }
2874                         }
2875                         else
2876                         {
2877                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
2878                                 CHECKGLERROR
2879                         }
2880                         break;
2881                 case RENDERPATH_D3D9:
2882 #ifdef SUPPORTD3D
2883                         if (gl_state.d3dvertexbuffer && ((element3s && element3s_indexbuffer) || (element3i && element3i_indexbuffer)))
2884                         {
2885                                 if (element3s_indexbuffer)
2886                                 {
2887                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3s_indexbuffer->devicebuffer);
2888                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3s_bufferoffset>>1, numtriangles);
2889                                 }
2890                                 else if (element3i_indexbuffer)
2891                                 {
2892                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3i_indexbuffer->devicebuffer);
2893                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3i_bufferoffset>>2, numtriangles);
2894                                 }
2895                                 else
2896                                         IDirect3DDevice9_DrawPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices);
2897                         }
2898                         else
2899                         {
2900                                 if (element3s)
2901                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3s, D3DFMT_INDEX16, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2902                                 else if (element3i)
2903                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3i, D3DFMT_INDEX32, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2904                                 else
2905                                         IDirect3DDevice9_DrawPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, numvertices, (void *)gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2906                         }
2907 #endif
2908                         break;
2909                 case RENDERPATH_D3D10:
2910                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2911                         break;
2912                 case RENDERPATH_D3D11:
2913                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2914                         break;
2915                 case RENDERPATH_SOFT:
2916                         DPSOFTRAST_DrawTriangles(firstvertex, numvertices, numtriangles, element3i, element3s);
2917                         break;
2918                 case RENDERPATH_GLES1:
2919                 case RENDERPATH_GLES2:
2920                         // GLES does not have glDrawRangeElements, and generally
2921                         // underperforms with index buffers, so this code path is
2922                         // relatively straightforward...
2923 #if 0
2924                         if (gl_paranoid.integer)
2925                         {
2926                                 int r, prog, enabled, i;
2927                                 GLsizei         attriblength;
2928                                 GLint           attribsize;
2929                                 GLenum          attribtype;
2930                                 GLchar          attribname[1024];
2931                                 r = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2932                                 if (r != GL_FRAMEBUFFER_COMPLETE_EXT)
2933                                         Con_DPrintf("fbo %i not complete (default %i)\n", gl_state.framebufferobject, gl_state.defaultframebufferobject);
2934 #ifndef GL_CURRENT_PROGRAM
2935 #define GL_CURRENT_PROGRAM 0x8B8D
2936 #endif
2937                                 qglGetIntegerv(GL_CURRENT_PROGRAM, &r);CHECKGLERROR
2938                                 if (r < 0 || r > 10000)
2939                                         Con_DPrintf("GL_CURRENT_PROGRAM = %i\n", r);
2940                                 prog = r;
2941                                 for (i = 0;i < 8;i++)
2942                                 {
2943                                         qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &r);CHECKGLERROR
2944                                         if (!r)
2945                                                 continue;
2946                                         qglGetActiveAttrib(prog, i, sizeof(attribname), &attriblength, &attribsize, &attribtype, attribname);CHECKGLERROR
2947                                         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);
2948                                 }
2949                         }
2950 #endif
2951                         if (element3s)
2952                         {
2953                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
2954                                 CHECKGLERROR
2955                         }
2956                         else if (element3i)
2957                         {
2958                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
2959                                 CHECKGLERROR
2960                         }
2961                         else
2962                         {
2963                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
2964                                 CHECKGLERROR
2965                         }
2966                         break;
2967                 }
2968         }
2969 }
2970
2971 // restores backend state, used when done with 3D rendering
2972 void R_Mesh_Finish(void)
2973 {
2974         R_Mesh_ResetRenderTargets();
2975 }
2976
2977 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic, qboolean isindex16)
2978 {
2979         r_meshbuffer_t *buffer;
2980         if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex)))
2981                 return NULL;
2982         buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
2983         memset(buffer, 0, sizeof(*buffer));
2984         buffer->bufferobject = 0;
2985         buffer->devicebuffer = NULL;
2986         buffer->size = 0;
2987         buffer->isindexbuffer = isindexbuffer;
2988         buffer->isdynamic = isdynamic;
2989         buffer->isindex16 = isindex16;
2990         strlcpy(buffer->name, name, sizeof(buffer->name));
2991         R_Mesh_UpdateMeshBuffer(buffer, data, size);
2992         return buffer;
2993 }
2994
2995 void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size)
2996 {
2997         if (!buffer)
2998                 return;
2999         if (buffer->isindexbuffer)
3000         {
3001                 r_refdef.stats.indexbufferuploadcount++;
3002                 r_refdef.stats.indexbufferuploadsize += size;
3003         }
3004         else
3005         {
3006                 r_refdef.stats.vertexbufferuploadcount++;
3007                 r_refdef.stats.vertexbufferuploadsize += size;
3008         }
3009         switch(vid.renderpath)
3010         {
3011         case RENDERPATH_GL11:
3012         case RENDERPATH_GL13:
3013         case RENDERPATH_GL20:
3014         case RENDERPATH_GLES1:
3015         case RENDERPATH_GLES2:
3016                 if (!buffer->bufferobject)
3017                         qglGenBuffersARB(1, (GLuint *)&buffer->bufferobject);
3018                 if (buffer->isindexbuffer)
3019                         GL_BindEBO(buffer->bufferobject);
3020                 else
3021                         GL_BindVBO(buffer->bufferobject);
3022                 qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
3023                 break;
3024         case RENDERPATH_D3D9:
3025 #ifdef SUPPORTD3D
3026                 {
3027                         int result;
3028                         void *datapointer = NULL;
3029                         if (buffer->isindexbuffer)
3030                         {
3031                                 IDirect3DIndexBuffer9 *d3d9indexbuffer = (IDirect3DIndexBuffer9 *)buffer->devicebuffer;
3032                                 if (size > buffer->size || !buffer->devicebuffer)
3033                                 {
3034                                         if (buffer->devicebuffer)
3035                                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer);
3036                                         buffer->devicebuffer = NULL;
3037                                         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)))
3038                                                 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);
3039                                         buffer->devicebuffer = (void *)d3d9indexbuffer;
3040                                         buffer->size = size;
3041                                 }
3042                                 if (!FAILED(IDirect3DIndexBuffer9_Lock(d3d9indexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
3043                                 {
3044                                         if (data)
3045                                                 memcpy(datapointer, data, size);
3046                                         else
3047                                                 memset(datapointer, 0, size);
3048                                         IDirect3DIndexBuffer9_Unlock(d3d9indexbuffer);
3049                                 }
3050                         }
3051                         else
3052                         {
3053                                 IDirect3DVertexBuffer9 *d3d9vertexbuffer = (IDirect3DVertexBuffer9 *)buffer->devicebuffer;
3054                                 if (size > buffer->size || !buffer->devicebuffer)
3055                                 {
3056                                         if (buffer->devicebuffer)
3057                                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer);
3058                                         buffer->devicebuffer = NULL;
3059                                         if (FAILED(result = IDirect3DDevice9_CreateVertexBuffer(vid_d3d9dev, size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9vertexbuffer, NULL)))
3060                                                 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);
3061                                         buffer->devicebuffer = (void *)d3d9vertexbuffer;
3062                                         buffer->size = size;
3063                                 }
3064                                 if (!FAILED(IDirect3DVertexBuffer9_Lock(d3d9vertexbuffer, 0, 0,