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