added DPSOFTRAST software rasterizer, a work in progress
[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*3;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                 DPSOFTRAST_CullFace(gl_state.cullface);
2065                 break;
2066         }
2067 }
2068
2069 void GL_AlphaTest(int state)
2070 {
2071         if (gl_state.alphatest != state)
2072         {
2073                 gl_state.alphatest = state;
2074                 switch(vid.renderpath)
2075                 {
2076                 case RENDERPATH_GL11:
2077                 case RENDERPATH_GL13:
2078                 case RENDERPATH_GL20:
2079                 case RENDERPATH_CGGL:
2080                         CHECKGLERROR
2081                         if (gl_state.alphatest)
2082                         {
2083                                 qglEnable(GL_ALPHA_TEST);CHECKGLERROR
2084                         }
2085                         else
2086                         {
2087                                 qglDisable(GL_ALPHA_TEST);CHECKGLERROR
2088                         }
2089                         break;
2090                 case RENDERPATH_D3D9:
2091 #ifdef SUPPORTD3D
2092                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHATESTENABLE, gl_state.alphatest);
2093 #endif
2094                         break;
2095                 case RENDERPATH_D3D10:
2096                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2097                         break;
2098                 case RENDERPATH_D3D11:
2099                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2100                         break;
2101                 case RENDERPATH_SOFT:
2102                         DPSOFTRAST_AlphaTest(gl_state.alphatest);
2103                         break;
2104                 }
2105         }
2106 }
2107
2108 void GL_AlphaFunc(int state, float value)
2109 {
2110         if (gl_state.alphafunc != state || gl_state.alphafuncvalue != value)
2111         {
2112                 gl_state.alphafunc = state;
2113                 gl_state.alphafuncvalue = value;
2114                 switch(vid.renderpath)
2115                 {
2116                 case RENDERPATH_GL11:
2117                 case RENDERPATH_GL13:
2118                 case RENDERPATH_GL20:
2119                 case RENDERPATH_CGGL:
2120                         CHECKGLERROR
2121                         qglAlphaFunc(gl_state.alphafunc, gl_state.alphafuncvalue);CHECKGLERROR
2122                         break;
2123                 case RENDERPATH_D3D9:
2124 #ifdef SUPPORTD3D
2125                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHAFUNC, d3dcmpforglfunc(gl_state.alphafunc));
2126                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHAREF, (int)bound(0, value * 256.0f, 255));
2127 #endif
2128                         break;
2129                 case RENDERPATH_D3D10:
2130                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2131                         break;
2132                 case RENDERPATH_D3D11:
2133                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2134                         break;
2135                 case RENDERPATH_SOFT:
2136                         DPSOFTRAST_AlphaFunc(gl_state.alphafunc, gl_state.alphafuncvalue);
2137                         break;
2138                 }
2139         }
2140 }
2141
2142 void GL_ColorMask(int r, int g, int b, int a)
2143 {
2144         // NOTE: this matches D3DCOLORWRITEENABLE_RED, GREEN, BLUE, ALPHA
2145         int state = (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0) | (a ? 8 : 0);
2146         if (gl_state.colormask != state)
2147         {
2148                 gl_state.colormask = state;
2149                 switch(vid.renderpath)
2150                 {
2151                 case RENDERPATH_GL11:
2152                 case RENDERPATH_GL13:
2153                 case RENDERPATH_GL20:
2154                 case RENDERPATH_CGGL:
2155                         CHECKGLERROR
2156                         qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
2157                         break;
2158                 case RENDERPATH_D3D9:
2159 #ifdef SUPPORTD3D
2160                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, state);
2161 #endif
2162                         break;
2163                 case RENDERPATH_D3D10:
2164                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2165                         break;
2166                 case RENDERPATH_D3D11:
2167                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2168                         break;
2169                 case RENDERPATH_SOFT:
2170                         DPSOFTRAST_ColorMask(r, g, b, a);
2171                         break;
2172                 }
2173         }
2174 }
2175
2176 void GL_Color(float cr, float cg, float cb, float ca)
2177 {
2178         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)
2179         {
2180                 gl_state.color4f[0] = cr;
2181                 gl_state.color4f[1] = cg;
2182                 gl_state.color4f[2] = cb;
2183                 gl_state.color4f[3] = ca;
2184                 switch(vid.renderpath)
2185                 {
2186                 case RENDERPATH_GL11:
2187                 case RENDERPATH_GL13:
2188                 case RENDERPATH_GL20:
2189                 case RENDERPATH_CGGL:
2190                         CHECKGLERROR
2191                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
2192                         CHECKGLERROR
2193                         break;
2194                 case RENDERPATH_D3D9:
2195                 case RENDERPATH_D3D10:
2196                 case RENDERPATH_D3D11:
2197                         // no equivalent in D3D
2198                         break;
2199                 case RENDERPATH_SOFT:
2200                         DPSOFTRAST_Color4f(cr, cg, cb, ca);
2201                         break;
2202                 }
2203         }
2204 }
2205
2206 void GL_Scissor (int x, int y, int width, int height)
2207 {
2208         switch(vid.renderpath)
2209         {
2210         case RENDERPATH_GL11:
2211         case RENDERPATH_GL13:
2212         case RENDERPATH_GL20:
2213         case RENDERPATH_CGGL:
2214                 CHECKGLERROR
2215                 qglScissor(x, y,width,height);
2216                 CHECKGLERROR
2217                 break;
2218         case RENDERPATH_D3D9:
2219 #ifdef SUPPORTD3D
2220                 {
2221                         RECT d3drect;
2222                         d3drect.left = x;
2223                         d3drect.top = y;
2224                         d3drect.right = x + width;
2225                         d3drect.bottom = y + height;
2226                         IDirect3DDevice9_SetScissorRect(vid_d3d9dev, &d3drect);
2227                 }
2228 #endif
2229                 break;
2230         case RENDERPATH_D3D10:
2231                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2232                 break;
2233         case RENDERPATH_D3D11:
2234                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2235                 break;
2236         case RENDERPATH_SOFT:
2237                 DPSOFTRAST_Scissor(x, y, width, height);
2238                 break;
2239         }
2240 }
2241
2242 void GL_ScissorTest(int state)
2243 {
2244         if (gl_state.scissortest != state)
2245         {
2246                 gl_state.scissortest = state;
2247                 switch(vid.renderpath)
2248                 {
2249                 case RENDERPATH_GL11:
2250                 case RENDERPATH_GL13:
2251                 case RENDERPATH_GL20:
2252                 case RENDERPATH_CGGL:
2253                         CHECKGLERROR
2254                         if(gl_state.scissortest)
2255                                 qglEnable(GL_SCISSOR_TEST);
2256                         else
2257                                 qglDisable(GL_SCISSOR_TEST);
2258                         CHECKGLERROR
2259                         break;
2260                 case RENDERPATH_D3D9:
2261 #ifdef SUPPORTD3D
2262                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SCISSORTESTENABLE, gl_state.scissortest);
2263 #endif
2264                         break;
2265                 case RENDERPATH_D3D10:
2266                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2267                         break;
2268                 case RENDERPATH_D3D11:
2269                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2270                         break;
2271                 case RENDERPATH_SOFT:
2272                         DPSOFTRAST_ScissorTest(gl_state.scissortest);
2273                         break;
2274                 }
2275         }
2276 }
2277
2278 void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilvalue)
2279 {
2280         static const float blackcolor[4] = {0, 0, 0, 0};
2281         // prevent warnings when trying to clear a buffer that does not exist
2282         if (!colorvalue)
2283                 colorvalue = blackcolor;
2284         if (!vid.stencil)
2285         {
2286                 mask &= ~GL_STENCIL_BUFFER_BIT;
2287                 stencilvalue = 0;
2288         }
2289         switch(vid.renderpath)
2290         {
2291         case RENDERPATH_GL11:
2292         case RENDERPATH_GL13:
2293         case RENDERPATH_GL20:
2294         case RENDERPATH_CGGL:
2295                 CHECKGLERROR
2296                 if (mask & GL_COLOR_BUFFER_BIT)
2297                 {
2298                         qglClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);CHECKGLERROR
2299                 }
2300                 if (mask & GL_DEPTH_BUFFER_BIT)
2301                 {
2302                         qglClearDepth(depthvalue);CHECKGLERROR
2303                 }
2304                 if (mask & GL_STENCIL_BUFFER_BIT)
2305                 {
2306                         qglClearStencil(stencilvalue);CHECKGLERROR
2307                 }
2308                 qglClear(mask);CHECKGLERROR
2309                 break;
2310         case RENDERPATH_D3D9:
2311 #ifdef SUPPORTD3D
2312                 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);
2313 #endif
2314                 break;
2315         case RENDERPATH_D3D10:
2316                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2317                 break;
2318         case RENDERPATH_D3D11:
2319                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2320                 break;
2321         case RENDERPATH_SOFT:
2322                 if (mask & GL_COLOR_BUFFER_BIT)
2323                         DPSOFTRAST_ClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);
2324                 if (mask & GL_DEPTH_BUFFER_BIT)
2325                         DPSOFTRAST_ClearDepth(depthvalue);
2326                 break;
2327         }
2328 }
2329
2330 void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels)
2331 {
2332         switch(vid.renderpath)
2333         {
2334         case RENDERPATH_GL11:
2335         case RENDERPATH_GL13:
2336         case RENDERPATH_GL20:
2337         case RENDERPATH_CGGL:
2338                 CHECKGLERROR
2339                 qglReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, outpixels);CHECKGLERROR
2340                 break;
2341         case RENDERPATH_D3D9:
2342 #ifdef SUPPORTD3D
2343                 {
2344                         // LordHavoc: we can't directly download the backbuffer because it may be
2345                         // multisampled, and it may not be lockable, so we blit it to a lockable
2346                         // surface of the same dimensions (but without multisample) to resolve the
2347                         // multisample buffer to a normal image, and then lock that...
2348                         IDirect3DSurface9 *stretchsurface = NULL;
2349                         if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &stretchsurface, NULL)))
2350                         {
2351                                 D3DLOCKED_RECT lockedrect;
2352                                 if (!FAILED(IDirect3DDevice9_StretchRect(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, NULL, stretchsurface, NULL, D3DTEXF_POINT)))
2353                                 {
2354                                         if (!FAILED(IDirect3DSurface9_LockRect(stretchsurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2355                                         {
2356                                                 int line;
2357                                                 unsigned char *row = (unsigned char *)lockedrect.pBits + x * 4 + lockedrect.Pitch * (vid.height - 1 - y);
2358                                                 for (line = 0;line < height;line++, row -= lockedrect.Pitch)
2359                                                         memcpy(outpixels + line * width * 4, row, width * 4);
2360                                                 IDirect3DSurface9_UnlockRect(stretchsurface);
2361                                         }
2362                                 }
2363                                 IDirect3DSurface9_Release(stretchsurface);
2364                         }
2365                         // code scraps
2366                         //IDirect3DSurface9 *syssurface = NULL;
2367                         //if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &stretchsurface, NULL)))
2368                         //if (!FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &syssurface, NULL)))
2369                         //IDirect3DDevice9_GetRenderTargetData(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, syssurface);
2370                         //if (!FAILED(IDirect3DDevice9_GetFrontBufferData(vid_d3d9dev, 0, syssurface)))
2371                         //if (!FAILED(IDirect3DSurface9_LockRect(syssurface, &lockedrect, NULL, D3DLOCK_READONLY)))
2372                         //IDirect3DSurface9_UnlockRect(syssurface);
2373                         //IDirect3DSurface9_Release(syssurface);
2374                 }
2375 #endif
2376                 break;
2377         case RENDERPATH_D3D10:
2378                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2379                 break;
2380         case RENDERPATH_D3D11:
2381                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2382                 break;
2383         case RENDERPATH_SOFT:
2384                 DPSOFTRAST_GetPixelsBGRA(x, y, width, height, outpixels);
2385                 break;
2386         }
2387 }
2388
2389 // called at beginning of frame
2390 void R_Mesh_Start(void)
2391 {
2392         BACKENDACTIVECHECK
2393         R_Mesh_ResetRenderTargets();
2394         R_Mesh_SetUseVBO();
2395         if (gl_printcheckerror.integer && !gl_paranoid.integer)
2396         {
2397                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
2398                 Cvar_SetValueQuick(&gl_paranoid, 1);
2399         }
2400 }
2401
2402 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
2403 {
2404         int shaderobject;
2405         int shadercompiled;
2406         char compilelog[MAX_INPUTLINE];
2407         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
2408         if (!shaderobject)
2409                 return false;
2410         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
2411         qglCompileShaderARB(shaderobject);CHECKGLERROR
2412         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
2413         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
2414         if (compilelog[0] && (strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error") || strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")))
2415         {
2416                 int i, j, pretextlines = 0;
2417                 for (i = 0;i < numstrings - 1;i++)
2418                         for (j = 0;strings[i][j];j++)
2419                                 if (strings[i][j] == '\n')
2420                                         pretextlines++;
2421                 Con_Printf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
2422         }
2423         if (!shadercompiled)
2424         {
2425                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
2426                 return false;
2427         }
2428         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
2429         qglDeleteObjectARB(shaderobject);CHECKGLERROR
2430         return true;
2431 }
2432
2433 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)
2434 {
2435         GLint programlinked;
2436         GLuint programobject = 0;
2437         char linklog[MAX_INPUTLINE];
2438         CHECKGLERROR
2439
2440         programobject = qglCreateProgramObjectARB();CHECKGLERROR
2441         if (!programobject)
2442                 return 0;
2443
2444         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
2445                 goto cleanup;
2446
2447 #ifdef GL_GEOMETRY_SHADER_ARB
2448         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
2449                 goto cleanup;
2450 #endif
2451
2452         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
2453                 goto cleanup;
2454
2455         qglLinkProgramARB(programobject);CHECKGLERROR
2456         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
2457         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
2458         if (linklog[0])
2459         {
2460                 if (strstr(linklog, "error") || strstr(linklog, "ERROR") || strstr(linklog, "Error") || strstr(linklog, "WARNING") || strstr(linklog, "warning") || strstr(linklog, "Warning"))
2461                         Con_DPrintf("program link log:\n%s\n", linklog);
2462                 // software vertex shader is ok but software fragment shader is WAY
2463                 // too slow, fail program if so.
2464                 // NOTE: this string might be ATI specific, but that's ok because the
2465                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
2466                 // software fragment shader due to low instruction and dependent
2467                 // texture limits.
2468                 if (strstr(linklog, "fragment shader will run in software"))
2469                         programlinked = false;
2470         }
2471         if (!programlinked)
2472                 goto cleanup;
2473         return programobject;
2474 cleanup:
2475         qglDeleteObjectARB(programobject);CHECKGLERROR
2476         return 0;
2477 }
2478
2479 void GL_Backend_FreeProgram(unsigned int prog)
2480 {
2481         CHECKGLERROR
2482         qglDeleteObjectARB(prog);
2483         CHECKGLERROR
2484 }
2485
2486 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
2487 {
2488         int i;
2489         if (offset)
2490         {
2491                 for (i = 0;i < count;i++)
2492                         *out++ = *in++ + offset;
2493         }
2494         else
2495                 memcpy(out, in, sizeof(*out) * count);
2496 }
2497
2498 // renders triangles using vertices from the active arrays
2499 int paranoidblah = 0;
2500 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)
2501 {
2502         unsigned int numelements = numtriangles * 3;
2503         int bufferobject3i;
2504         size_t bufferoffset3i;
2505         int bufferobject3s;
2506         size_t bufferoffset3s;
2507         if (numvertices < 3 || numtriangles < 1)
2508         {
2509                 if (numvertices < 0 || numtriangles < 0 || developer_extra.integer)
2510                         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);
2511                 return;
2512         }
2513         if (!gl_mesh_prefer_short_elements.integer)
2514         {
2515                 if (element3i)
2516                         element3s = NULL;
2517                 if (element3i_indexbuffer)
2518                         element3i_indexbuffer = NULL;
2519         }
2520         // adjust the pointers for firsttriangle
2521         if (element3i)
2522                 element3i += firsttriangle * 3;
2523         if (element3i_indexbuffer)
2524                 element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i);
2525         if (element3s)
2526                 element3s += firsttriangle * 3;
2527         if (element3s_indexbuffer)
2528                 element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
2529         switch(vid.renderpath)
2530         {
2531         case RENDERPATH_GL11:
2532         case RENDERPATH_GL13:
2533         case RENDERPATH_GL20:
2534         case RENDERPATH_CGGL:
2535                 // check if the user specified to ignore static index buffers
2536                 if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset)))
2537                 {
2538                         element3i_indexbuffer = NULL;
2539                         element3s_indexbuffer = NULL;
2540                 }
2541                 break;
2542         case RENDERPATH_D3D9:
2543         case RENDERPATH_D3D10:
2544         case RENDERPATH_D3D11:
2545                 break;
2546         case RENDERPATH_SOFT:
2547                 break;
2548         }
2549         // upload a dynamic index buffer if needed
2550         if (element3s)
2551         {
2552                 if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex)
2553                 {
2554                         if (gl_state.draw_dynamicindexbuffer)
2555                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3s, numelements * sizeof(*element3s));
2556                         else
2557                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3s, numelements * sizeof(*element3s), "temporary", true, true, true);
2558                         element3s_indexbuffer = gl_state.draw_dynamicindexbuffer;
2559                         element3s_bufferoffset = 0;
2560                 }
2561         }
2562         else if (element3i)
2563         {
2564                 if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex)
2565                 {
2566                         if (gl_state.draw_dynamicindexbuffer)
2567                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3i, numelements * sizeof(*element3i));
2568                         else
2569                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3i, numelements * sizeof(*element3i), "temporary", true, true, false);
2570                         element3i_indexbuffer = gl_state.draw_dynamicindexbuffer;
2571                         element3i_bufferoffset = 0;
2572                 }
2573         }
2574         bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
2575         bufferoffset3i = element3i_bufferoffset;
2576         bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0;
2577         bufferoffset3s = element3s_bufferoffset;
2578         r_refdef.stats.draws++;
2579         r_refdef.stats.draws_vertices += numvertices;
2580         r_refdef.stats.draws_elements += numelements;
2581         if (gl_paranoid.integer)
2582         {
2583                 unsigned int i;
2584                 // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
2585 #if 0
2586                 unsigned int j, size;
2587                 const int *p;
2588                 // note: there's no validation done here on buffer objects because it
2589                 // is somewhat difficult to get at the data, and gl_paranoid can be
2590                 // used without buffer objects if the need arises
2591                 // (the data could be gotten using glMapBuffer but it would be very
2592                 //  slow due to uncachable video memory reads)
2593                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
2594                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
2595                 CHECKGLERROR
2596                 if (gl_state.pointer_vertex_pointer)
2597                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
2598                                 paranoidblah += *p;
2599                 if (gl_state.pointer_color_enabled)
2600                 {
2601                         if (!qglIsEnabled(GL_COLOR_ARRAY))
2602                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
2603                         CHECKGLERROR
2604                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
2605                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
2606                                         paranoidblah += *p;
2607                 }
2608                 for (i = 0;i < vid.texarrayunits;i++)
2609                 {
2610                         if (gl_state.units[i].arrayenabled)
2611                         {
2612                                 GL_ClientActiveTexture(i);
2613                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
2614                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
2615                                 CHECKGLERROR
2616                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
2617                                         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++)
2618                                                 paranoidblah += *p;
2619                         }
2620                 }
2621 #endif
2622                 if (element3i)
2623                 {
2624                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2625                         {
2626                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
2627                                 {
2628                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
2629                                         return;
2630                                 }
2631                         }
2632                 }
2633                 if (element3s)
2634                 {
2635                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2636                         {
2637                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
2638                                 {
2639                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
2640                                         return;
2641                                 }
2642                         }
2643                 }
2644         }
2645         if (r_render.integer || r_refdef.draw2dstage)
2646         {
2647                 switch(vid.renderpath)
2648                 {
2649                 case RENDERPATH_GL11:
2650                 case RENDERPATH_GL13:
2651                 case RENDERPATH_GL20:
2652                 case RENDERPATH_CGGL:
2653                         CHECKGLERROR
2654                         if (gl_mesh_testmanualfeeding.integer)
2655                         {
2656                                 unsigned int i, j, element;
2657                                 const GLfloat *p;
2658                                 qglBegin(GL_TRIANGLES);
2659                                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2660                                 {
2661                                         if (element3i)
2662                                                 element = element3i[i];
2663                                         else if (element3s)
2664                                                 element = element3s[i];
2665                                         else
2666                                                 element = firstvertex + i;
2667                                         for (j = 0;j < vid.texarrayunits;j++)
2668                                         {
2669                                                 if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
2670                                                 {
2671                                                         if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
2672                                                         {
2673                                                                 p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2674                                                                 if (vid.texarrayunits > 1)
2675                                                                 {
2676                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2677                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
2678                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2679                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
2680                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2681                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
2682                                                                         else
2683                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
2684                                                                 }
2685                                                                 else
2686                                                                 {
2687                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2688                                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
2689                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2690                                                                                 qglTexCoord3f(p[0], p[1], p[2]);
2691                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2692                                                                                 qglTexCoord2f(p[0], p[1]);
2693                                                                         else
2694                                                                                 qglTexCoord1f(p[0]);
2695                                                                 }
2696                                                         }
2697                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
2698                                                         {
2699                                                                 const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2700                                                                 if (vid.texarrayunits > 1)
2701                                                                 {
2702                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2703                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
2704                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2705                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]);
2706                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2707                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
2708                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2709                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
2710                                                                 }
2711                                                                 else
2712                                                                 {
2713                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2714                                                                                 qglTexCoord4f(s[0], s[1], s[2], s[3]);
2715                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2716                                                                                 qglTexCoord3f(s[0], s[1], s[2]);
2717                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2718                                                                                 qglTexCoord2f(s[0], s[1]);
2719                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2720                                                                                 qglTexCoord1f(s[0]);
2721                                                                 }
2722                                                         }
2723                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
2724                                                         {
2725                                                                 const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2726                                                                 if (vid.texarrayunits > 1)
2727                                                                 {
2728                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2729                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
2730                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2731                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]);
2732                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2733                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
2734                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2735                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
2736                                                                 }
2737                                                                 else
2738                                                                 {
2739                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2740                                                                                 qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
2741                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2742                                                                                 qglTexCoord3f(sb[0], sb[1], sb[2]);
2743                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2744                                                                                 qglTexCoord2f(sb[0], sb[1]);
2745                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2746                                                                                 qglTexCoord1f(sb[0]);
2747                                                                 }
2748                                                         }
2749                                                 }
2750                                         }
2751                                         if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
2752                                         {
2753                                                 if (gl_state.pointer_color_gltype == GL_FLOAT)
2754                                                 {
2755                                                         p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2756                                                         qglColor4f(p[0], p[1], p[2], p[3]);
2757                                                 }
2758                                                 else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
2759                                                 {
2760                                                         const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2761                                                         qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
2762                                                 }
2763                                         }
2764                                         if (gl_state.pointer_vertex_gltype == GL_FLOAT)
2765                                         {
2766                                                 p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
2767                                                 if (gl_state.pointer_vertex_components == 4)
2768                                                         qglVertex4f(p[0], p[1], p[2], p[3]);
2769                                                 else if (gl_state.pointer_vertex_components == 3)
2770                                                         qglVertex3f(p[0], p[1], p[2]);
2771                                                 else
2772                                                         qglVertex2f(p[0], p[1]);
2773                                         }
2774                                 }
2775                                 qglEnd();
2776                                 CHECKGLERROR
2777                         }
2778                         else if (bufferobject3s)
2779                         {
2780                                 GL_BindEBO(bufferobject3s);
2781                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2782                                 {
2783                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
2784                                         CHECKGLERROR
2785                                 }
2786                                 else
2787                                 {
2788                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
2789                                         CHECKGLERROR
2790                                 }
2791                         }
2792                         else if (bufferobject3i)
2793                         {
2794                                 GL_BindEBO(bufferobject3i);
2795                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2796                                 {
2797                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
2798                                         CHECKGLERROR
2799                                 }
2800                                 else
2801                                 {
2802                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
2803                                         CHECKGLERROR
2804                                 }
2805                         }
2806                         else if (element3s)
2807                         {
2808                                 GL_BindEBO(0);
2809                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2810                                 {
2811                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
2812                                         CHECKGLERROR
2813                                 }
2814                                 else
2815                                 {
2816                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
2817                                         CHECKGLERROR
2818                                 }
2819                         }
2820                         else if (element3i)
2821                         {
2822                                 GL_BindEBO(0);
2823                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2824                                 {
2825                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
2826                                         CHECKGLERROR
2827                                 }
2828                                 else
2829                                 {
2830                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
2831                                         CHECKGLERROR
2832                                 }
2833                         }
2834                         else
2835                         {
2836                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
2837                                 CHECKGLERROR
2838                         }
2839                         break;
2840                 case RENDERPATH_D3D9:
2841 #ifdef SUPPORTD3D
2842                         if (gl_state.d3dvertexbuffer && ((element3s && element3s_indexbuffer) || (element3i && element3i_indexbuffer)))
2843                         {
2844                                 if (element3s_indexbuffer)
2845                                 {
2846                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3s_indexbuffer->devicebuffer);
2847                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3s_bufferoffset>>1, numtriangles);
2848                                 }
2849                                 else if (element3i_indexbuffer)
2850                                 {
2851                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3i_indexbuffer->devicebuffer);
2852                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3i_bufferoffset>>2, numtriangles);
2853                                 }
2854                                 else
2855                                         IDirect3DDevice9_DrawPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices);
2856                         }
2857                         else
2858                         {
2859                                 if (element3s)
2860                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3s, D3DFMT_INDEX16, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2861                                 else if (element3i)
2862                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3i, D3DFMT_INDEX32, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2863                                 else
2864                                         IDirect3DDevice9_DrawPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, numvertices, (void *)gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2865                         }
2866 #endif
2867                         break;
2868                 case RENDERPATH_D3D10:
2869                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2870                         break;
2871                 case RENDERPATH_D3D11:
2872                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2873                         break;
2874                 case RENDERPATH_SOFT:
2875                         DPSOFTRAST_DrawTriangles(firstvertex, numvertices, numtriangles, element3i, element3s);
2876                         break;
2877                 }
2878         }
2879 }
2880
2881 // restores backend state, used when done with 3D rendering
2882 void R_Mesh_Finish(void)
2883 {
2884         R_Mesh_ResetRenderTargets();
2885 }
2886
2887 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic, qboolean isindex16)
2888 {
2889         r_meshbuffer_t *buffer;
2890         if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex)))
2891                 return NULL;
2892         buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
2893         memset(buffer, 0, sizeof(*buffer));
2894         buffer->bufferobject = 0;
2895         buffer->devicebuffer = NULL;
2896         buffer->size = 0;
2897         buffer->isindexbuffer = isindexbuffer;
2898         buffer->isdynamic = isdynamic;
2899         buffer->isindex16 = isindex16;
2900         strlcpy(buffer->name, name, sizeof(buffer->name));
2901         R_Mesh_UpdateMeshBuffer(buffer, data, size);
2902         return buffer;
2903 }
2904
2905 void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size)
2906 {
2907         if (!buffer)
2908                 return;
2909         if (buffer->isindexbuffer)
2910         {
2911                 r_refdef.stats.indexbufferuploadcount++;
2912                 r_refdef.stats.indexbufferuploadsize += size;
2913         }
2914         else
2915         {
2916                 r_refdef.stats.vertexbufferuploadcount++;
2917                 r_refdef.stats.vertexbufferuploadsize += size;
2918         }
2919         switch(vid.renderpath)
2920         {
2921         case RENDERPATH_GL11:
2922         case RENDERPATH_GL13:
2923         case RENDERPATH_GL20:
2924         case RENDERPATH_CGGL:
2925                 if (!buffer->bufferobject)
2926                         qglGenBuffersARB(1, (GLuint *)&buffer->bufferobject);
2927                 if (buffer->isindexbuffer)
2928                         GL_BindEBO(buffer->bufferobject);
2929                 else
2930                         GL_BindVBO(buffer->bufferobject);
2931                 qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
2932                 break;
2933         case RENDERPATH_D3D9:
2934 #ifdef SUPPORTD3D
2935                 {
2936                         int result;
2937                         void *datapointer = NULL;
2938                         if (buffer->isindexbuffer)
2939                         {
2940                                 IDirect3DIndexBuffer9 *d3d9indexbuffer = (IDirect3DIndexBuffer9 *)buffer->devicebuffer;
2941                                 if (size > buffer->size || !buffer->devicebuffer)
2942                                 {
2943                                         if (buffer->devicebuffer)
2944                                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer);
2945                                         buffer->devicebuffer = NULL;
2946                                         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)))
2947                                                 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);
2948                                         buffer->devicebuffer = (void *)d3d9indexbuffer;
2949                                         buffer->size = size;
2950                                 }
2951                                 if (!FAILED(IDirect3DIndexBuffer9_Lock(d3d9indexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
2952                                 {
2953                                         if (data)
2954                                                 memcpy(datapointer, data, size);
2955                                         else
2956                                                 memset(datapointer, 0, size);
2957                                         IDirect3DIndexBuffer9_Unlock(d3d9indexbuffer);
2958                                 }
2959                         }
2960                         else
2961                         {
2962                                 IDirect3DVertexBuffer9 *d3d9vertexbuffer = (IDirect3DVertexBuffer9 *)buffer->devicebuffer;
2963                                 if (size > buffer->size || !buffer->devicebuffer)
2964                                 {
2965                                         if (buffer->devicebuffer)
2966                                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer);
2967                                         buffer->devicebuffer = NULL;
2968                                         if (FAILED(result = IDirect3DDevice9_CreateVertexBuffer(vid_d3d9dev, size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9vertexbuffer, NULL)))
2969                                                 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);
2970                                         buffer->devicebuffer = (void *)d3d9vertexbuffer;
2971                                         buffer->size = size;
2972                                 }
2973                                 if (!FAILED(IDirect3DVertexBuffer9_Lock(d3d9vertexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
2974                                 {
2975                                         if (data)
2976                                                 memcpy(datapointer, data, size);
2977                                         else
2978                                                 memset(datapointer, 0, size);
2979                                         IDirect3DVertexBuffer9_Unlock(d3d9vertexbuffer);
2980                                 }
2981                         }
2982                 }
2983 #endif
2984                 break;
2985         case RENDERPATH_D3D10:
2986                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2987                 break;
2988         case RENDERPATH_D3D11:
2989                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2990                 break;
2991         case RENDERPATH_SOFT:
2992                 break;
2993         }
2994 }
2995
2996 void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
2997 {
2998         if (!buffer)
2999                 return;
3000         switch(vid.renderpath)
3001         {
3002         case RENDERPATH_GL11:
3003         case RENDERPATH_GL13:
3004         case RENDERPATH_GL20:
3005         case RENDERPATH_CGGL:
3006                 qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject);
3007                 break;
3008         case RENDERPATH_D3D9:
3009 #ifdef SUPPORTD3D
3010                 if (gl_state.d3dvertexbuffer == (void *)buffer)
3011                         gl_state.d3dvertexbuffer = NULL;
3012                 if (buffer->devicebuffer)
3013                 {
3014                         if (buffer->isindexbuffer)
3015                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9 *)buffer->devicebuffer);
3016                         else
3017                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9 *)buffer->devicebuffer);
3018                         buffer->devicebuffer = NULL;
3019                 }
3020 #endif
3021                 break;
3022         case RENDERPATH_D3D10:
3023                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3024                 break;
3025         case RENDERPATH_D3D11:
3026                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3027                 break;
3028         case RENDERPATH_SOFT:
3029                 break;
3030         }
3031         Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
3032 }
3033
3034 void GL_Mesh_ListVBOs(qboolean printeach)
3035 {
3036         int i, endindex;
3037         size_t ebocount = 0, ebomemory = 0;
3038         size_t vbocount = 0, vbomemory = 0;
3039         r_meshbuffer_t *buffer;
3040         endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
3041         for (i = 0;i < endindex;i++)
3042         {
3043                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
3044                 if (!buffer)
3045                         continue;
3046                 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)");}
3047                 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)");}
3048         }
3049         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);
3050 }
3051
3052
3053
3054 void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
3055 {
3056         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
3057         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)
3058         {
3059                 gl_state.pointer_vertex_components = components;
3060                 gl_state.pointer_vertex_gltype = gltype;
3061                 gl_state.pointer_vertex_stride = stride;
3062                 gl_state.pointer_vertex_pointer = pointer;
3063                 gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
3064                 gl_state.pointer_vertex_offset = bufferoffset;
3065                 CHECKGLERROR
3066                 GL_BindVBO(bufferobject);
3067                 qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3068         }
3069 }
3070
3071 void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
3072 {
3073         // note: vertexbuffer may be non-NULL even if pointer is NULL, so check
3074         // the pointer only.