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