shut up a gcc warning
[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.meshes++;
2463         r_refdef.stats.meshes_elements += numelements;
2464         if (gl_paranoid.integer)
2465         {
2466                 unsigned int i;
2467                 // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
2468 #if 0
2469                 unsigned int j, size;
2470                 const int *p;
2471                 // note: there's no validation done here on buffer objects because it
2472                 // is somewhat difficult to get at the data, and gl_paranoid can be
2473                 // used without buffer objects if the need arises
2474                 // (the data could be gotten using glMapBuffer but it would be very
2475                 //  slow due to uncachable video memory reads)
2476                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
2477                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
2478                 CHECKGLERROR
2479                 if (gl_state.pointer_vertex_pointer)
2480                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
2481                                 paranoidblah += *p;
2482                 if (gl_state.pointer_color_enabled)
2483                 {
2484                         if (!qglIsEnabled(GL_COLOR_ARRAY))
2485                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
2486                         CHECKGLERROR
2487                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
2488                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
2489                                         paranoidblah += *p;
2490                 }
2491                 for (i = 0;i < vid.texarrayunits;i++)
2492                 {
2493                         if (gl_state.units[i].arrayenabled)
2494                         {
2495                                 GL_ClientActiveTexture(i);
2496                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
2497                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
2498                                 CHECKGLERROR
2499                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
2500                                         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++)
2501                                                 paranoidblah += *p;
2502                         }
2503                 }
2504 #endif
2505                 if (element3i)
2506                 {
2507                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2508                         {
2509                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
2510                                 {
2511                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
2512                                         return;
2513                                 }
2514                         }
2515                 }
2516                 if (element3s)
2517                 {
2518                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2519                         {
2520                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
2521                                 {
2522                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
2523                                         return;
2524                                 }
2525                         }
2526                 }
2527         }
2528         if (r_render.integer || r_refdef.draw2dstage)
2529         {
2530                 switch(vid.renderpath)
2531                 {
2532                 case RENDERPATH_GL11:
2533                 case RENDERPATH_GL13:
2534                 case RENDERPATH_GL20:
2535                 case RENDERPATH_CGGL:
2536                         CHECKGLERROR
2537                         if (gl_mesh_testmanualfeeding.integer)
2538                         {
2539                                 unsigned int i, j, element;
2540                                 const GLfloat *p;
2541                                 qglBegin(GL_TRIANGLES);
2542                                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
2543                                 {
2544                                         if (element3i)
2545                                                 element = element3i[i];
2546                                         else if (element3s)
2547                                                 element = element3s[i];
2548                                         else
2549                                                 element = firstvertex + i;
2550                                         for (j = 0;j < vid.texarrayunits;j++)
2551                                         {
2552                                                 if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
2553                                                 {
2554                                                         if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
2555                                                         {
2556                                                                 p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2557                                                                 if (vid.texarrayunits > 1)
2558                                                                 {
2559                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2560                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
2561                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2562                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
2563                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2564                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
2565                                                                         else
2566                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
2567                                                                 }
2568                                                                 else
2569                                                                 {
2570                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2571                                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
2572                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2573                                                                                 qglTexCoord3f(p[0], p[1], p[2]);
2574                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2575                                                                                 qglTexCoord2f(p[0], p[1]);
2576                                                                         else
2577                                                                                 qglTexCoord1f(p[0]);
2578                                                                 }
2579                                                         }
2580                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
2581                                                         {
2582                                                                 const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2583                                                                 if (vid.texarrayunits > 1)
2584                                                                 {
2585                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2586                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
2587                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2588                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]);
2589                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2590                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
2591                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2592                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
2593                                                                 }
2594                                                                 else
2595                                                                 {
2596                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2597                                                                                 qglTexCoord4f(s[0], s[1], s[2], s[3]);
2598                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2599                                                                                 qglTexCoord3f(s[0], s[1], s[2]);
2600                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2601                                                                                 qglTexCoord2f(s[0], s[1]);
2602                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2603                                                                                 qglTexCoord1f(s[0]);
2604                                                                 }
2605                                                         }
2606                                                         else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
2607                                                         {
2608                                                                 const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
2609                                                                 if (vid.texarrayunits > 1)
2610                                                                 {
2611                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2612                                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
2613                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2614                                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]);
2615                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2616                                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
2617                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2618                                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
2619                                                                 }
2620                                                                 else
2621                                                                 {
2622                                                                         if (gl_state.units[j].pointer_texcoord_components == 4)
2623                                                                                 qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
2624                                                                         else if (gl_state.units[j].pointer_texcoord_components == 3)
2625                                                                                 qglTexCoord3f(sb[0], sb[1], sb[2]);
2626                                                                         else if (gl_state.units[j].pointer_texcoord_components == 2)
2627                                                                                 qglTexCoord2f(sb[0], sb[1]);
2628                                                                         else if (gl_state.units[j].pointer_texcoord_components == 1)
2629                                                                                 qglTexCoord1f(sb[0]);
2630                                                                 }
2631                                                         }
2632                                                 }
2633                                         }
2634                                         if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
2635                                         {
2636                                                 if (gl_state.pointer_color_gltype == GL_FLOAT)
2637                                                 {
2638                                                         p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2639                                                         qglColor4f(p[0], p[1], p[2], p[3]);
2640                                                 }
2641                                                 else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
2642                                                 {
2643                                                         const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
2644                                                         qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
2645                                                 }
2646                                         }
2647                                         if (gl_state.pointer_vertex_gltype == GL_FLOAT)
2648                                         {
2649                                                 p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
2650                                                 if (gl_state.pointer_vertex_components == 4)
2651                                                         qglVertex4f(p[0], p[1], p[2], p[3]);
2652                                                 else if (gl_state.pointer_vertex_components == 3)
2653                                                         qglVertex3f(p[0], p[1], p[2]);
2654                                                 else
2655                                                         qglVertex2f(p[0], p[1]);
2656                                         }
2657                                 }
2658                                 qglEnd();
2659                                 CHECKGLERROR
2660                         }
2661                         else if (bufferobject3s)
2662                         {
2663                                 GL_BindEBO(bufferobject3s);
2664                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2665                                 {
2666                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
2667                                         CHECKGLERROR
2668                                 }
2669                                 else
2670                                 {
2671                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
2672                                         CHECKGLERROR
2673                                 }
2674                         }
2675                         else if (bufferobject3i)
2676                         {
2677                                 GL_BindEBO(bufferobject3i);
2678                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2679                                 {
2680                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
2681                                         CHECKGLERROR
2682                                 }
2683                                 else
2684                                 {
2685                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
2686                                         CHECKGLERROR
2687                                 }
2688                         }
2689                         else if (element3s)
2690                         {
2691                                 GL_BindEBO(0);
2692                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2693                                 {
2694                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
2695                                         CHECKGLERROR
2696                                 }
2697                                 else
2698                                 {
2699                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
2700                                         CHECKGLERROR
2701                                 }
2702                         }
2703                         else if (element3i)
2704                         {
2705                                 GL_BindEBO(0);
2706                                 if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
2707                                 {
2708                                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
2709                                         CHECKGLERROR
2710                                 }
2711                                 else
2712                                 {
2713                                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
2714                                         CHECKGLERROR
2715                                 }
2716                         }
2717                         else
2718                         {
2719                                 qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
2720                                 CHECKGLERROR
2721                         }
2722                         break;
2723                 case RENDERPATH_D3D9:
2724 #ifdef SUPPORTD3D
2725                         if (gl_state.d3dvertexbuffer && ((element3s && element3s_indexbuffer) || (element3i && element3i_indexbuffer)))
2726                         {
2727                                 if (element3s_indexbuffer)
2728                                 {
2729                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3s_indexbuffer->devicebuffer);
2730                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3s_bufferoffset>>1, numtriangles);
2731                                 }
2732                                 else if (element3i_indexbuffer)
2733                                 {
2734                                         IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3i_indexbuffer->devicebuffer);
2735                                         IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3i_bufferoffset>>2, numtriangles);
2736                                 }
2737                                 else
2738                                         IDirect3DDevice9_DrawPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices);
2739                         }
2740                         else
2741                         {
2742                                 if (element3s)
2743                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3s + firsttriangle*3, D3DFMT_INDEX16, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2744                                 else if (element3i)
2745                                         IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3i + firsttriangle*3, D3DFMT_INDEX32, gl_state.d3dvertexdata, gl_state.d3dvertexsize);
2746                                 else
2747                                         IDirect3DDevice9_DrawPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, numvertices, (void *) ((byte *) gl_state.d3dvertexdata + (numvertices * gl_state.d3dvertexsize)), gl_state.d3dvertexsize);
2748                         }
2749 #endif
2750                         break;
2751                 case RENDERPATH_D3D10:
2752                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2753                         break;
2754                 case RENDERPATH_D3D11:
2755                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2756                         break;
2757                 }
2758         }
2759 }
2760
2761 // restores backend state, used when done with 3D rendering
2762 void R_Mesh_Finish(void)
2763 {
2764         R_Mesh_ResetRenderTargets();
2765 }
2766
2767 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic, qboolean isindex16)
2768 {
2769         r_meshbuffer_t *buffer;
2770         if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex)))
2771                 return NULL;
2772         buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
2773         memset(buffer, 0, sizeof(*buffer));
2774         buffer->bufferobject = 0;
2775         buffer->devicebuffer = NULL;
2776         buffer->size = 0;
2777         buffer->isindexbuffer = isindexbuffer;
2778         buffer->isdynamic = isdynamic;
2779         buffer->isindex16 = isindex16;
2780         strlcpy(buffer->name, name, sizeof(buffer->name));
2781         R_Mesh_UpdateMeshBuffer(buffer, data, size);
2782         return buffer;
2783 }
2784
2785 void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size)
2786 {
2787         if (!buffer)
2788                 return;
2789         if (buffer->isindexbuffer)
2790         {
2791                 r_refdef.stats.indexbufferuploadcount++;
2792                 r_refdef.stats.indexbufferuploadsize += size;
2793         }
2794         else
2795         {
2796                 r_refdef.stats.vertexbufferuploadcount++;
2797                 r_refdef.stats.vertexbufferuploadsize += size;
2798         }
2799         switch(vid.renderpath)
2800         {
2801         case RENDERPATH_GL11:
2802         case RENDERPATH_GL13:
2803         case RENDERPATH_GL20:
2804         case RENDERPATH_CGGL:
2805                 if (!buffer->bufferobject)
2806                         qglGenBuffersARB(1, (GLuint *)&buffer->bufferobject);
2807                 if (buffer->isindexbuffer)
2808                         GL_BindEBO(buffer->bufferobject);
2809                 else
2810                         GL_BindVBO(buffer->bufferobject);
2811                 qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
2812                 break;
2813         case RENDERPATH_D3D9:
2814 #ifdef SUPPORTD3D
2815                 {
2816                         int result;
2817                         void *datapointer = NULL;
2818                         if (buffer->isindexbuffer)
2819                         {
2820                                 IDirect3DIndexBuffer9 *d3d9indexbuffer = (IDirect3DIndexBuffer9 *)buffer->devicebuffer;
2821                                 if (size > buffer->size || !buffer->devicebuffer)
2822                                 {
2823                                         if (buffer->devicebuffer)
2824                                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer);
2825                                         buffer->devicebuffer = NULL;
2826                                         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)))
2827                                                 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);
2828                                         buffer->devicebuffer = (void *)d3d9indexbuffer;
2829                                         buffer->size = size;
2830                                 }
2831                                 if (!FAILED(IDirect3DIndexBuffer9_Lock(d3d9indexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
2832                                 {
2833                                         if (data)
2834                                                 memcpy(datapointer, data, size);
2835                                         else
2836                                                 memset(datapointer, 0, size);
2837                                         IDirect3DIndexBuffer9_Unlock(d3d9indexbuffer);
2838                                 }
2839                         }
2840                         else
2841                         {
2842                                 IDirect3DVertexBuffer9 *d3d9vertexbuffer = (IDirect3DVertexBuffer9 *)buffer->devicebuffer;
2843                                 if (size > buffer->size || !buffer->devicebuffer)
2844                                 {
2845                                         if (buffer->devicebuffer)
2846                                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer);
2847                                         buffer->devicebuffer = NULL;
2848                                         if (FAILED(result = IDirect3DDevice9_CreateVertexBuffer(vid_d3d9dev, size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9vertexbuffer, NULL)))
2849                                                 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);
2850                                         buffer->devicebuffer = (void *)d3d9vertexbuffer;
2851                                         buffer->size = size;
2852                                 }
2853                                 if (!FAILED(IDirect3DVertexBuffer9_Lock(d3d9vertexbuffer, 0, 0, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0)))
2854                                 {
2855                                         if (data)
2856                                                 memcpy(datapointer, data, size);
2857                                         else
2858                                                 memset(datapointer, 0, size);
2859                                         IDirect3DVertexBuffer9_Unlock(d3d9vertexbuffer);
2860                                 }
2861                         }
2862                 }
2863 #endif
2864                 break;
2865         case RENDERPATH_D3D10:
2866                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2867                 break;
2868         case RENDERPATH_D3D11:
2869                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2870                 break;
2871         }
2872 }
2873
2874 void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
2875 {
2876         if (!buffer)
2877                 return;
2878         switch(vid.renderpath)
2879         {
2880         case RENDERPATH_GL11:
2881         case RENDERPATH_GL13:
2882         case RENDERPATH_GL20:
2883         case RENDERPATH_CGGL:
2884                 qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject);
2885                 break;
2886         case RENDERPATH_D3D9:
2887 #ifdef SUPPORTD3D
2888                 if (gl_state.d3dvertexbuffer == (void *)buffer)
2889                         gl_state.d3dvertexbuffer = NULL;
2890                 if (buffer->devicebuffer)
2891                 {
2892                         if (buffer->isindexbuffer)
2893                                 IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9 *)buffer->devicebuffer);
2894                         else
2895                                 IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9 *)buffer->devicebuffer);
2896                         buffer->devicebuffer = NULL;
2897                 }
2898 #endif
2899                 break;
2900         case RENDERPATH_D3D10:
2901                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2902                 break;
2903         case RENDERPATH_D3D11:
2904                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2905                 break;
2906         }
2907         Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
2908 }
2909
2910 void GL_Mesh_ListVBOs(qboolean printeach)
2911 {
2912         int i, endindex;
2913         size_t ebocount = 0, ebomemory = 0;
2914         size_t vbocount = 0, vbomemory = 0;
2915         r_meshbuffer_t *buffer;
2916         endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
2917         for (i = 0;i < endindex;i++)
2918         {
2919                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
2920                 if (!buffer)
2921                         continue;
2922                 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)");}
2923                 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)");}
2924         }
2925         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);
2926 }
2927
2928
2929
2930 void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
2931 {
2932         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
2933         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)
2934         {
2935                 gl_state.pointer_vertex_components = components;
2936                 gl_state.pointer_vertex_gltype = gltype;
2937                 gl_state.pointer_vertex_stride = stride;
2938                 gl_state.pointer_vertex_pointer = pointer;
2939                 gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
2940                 gl_state.pointer_vertex_offset = bufferoffset;
2941                 CHECKGLERROR
2942                 GL_BindVBO(bufferobject);
2943                 qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
2944         }
2945 }
2946
2947 void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
2948 {
2949         // note: vertexbuffer may be non-NULL even if pointer is NULL, so check
2950         // the pointer only.
2951         if (pointer)
2952         {
2953                 int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
2954                 // caller wants color array enabled
2955                 if (!gl_state.pointer_color_enabled)
2956                 {
2957                         gl_state.pointer_color_enabled = true;
2958                         CHECKGLERROR
2959                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
2960                 }
2961                 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)
2962                 {
2963                         gl_state.pointer_color_components = components;
2964                         gl_state.pointer_color_gltype = gltype;
2965                         gl_state.pointer_color_stride = stride;
2966                         gl_state.pointer_color_pointer = pointer;
2967                         gl_state.pointer_color_vertexbuffer = vertexbuffer;
2968                         gl_state.pointer_color_offset = bufferoffset;
2969                         CHECKGLERROR
2970                         GL_BindVBO(bufferobject);
2971                         qglColorPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
2972                 }
2973         }
2974         else
2975         {
2976                 // caller wants color array disabled
2977                 if (gl_state.pointer_color_enabled)
2978                 {
2979                         gl_state.pointer_color_enabled = false;
2980                         CHECKGLERROR
2981                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
2982                         // when color array is on the glColor gets trashed, set it again
2983                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
2984                 }
2985         }
2986 }
2987
2988 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)
2989 {
2990         gltextureunit_t *unit = gl_state.units + unitnum;
2991         // update array settings
2992         CHECKGLERROR
2993         // note: there is no need to check bufferobject here because all cases
2994         // that involve a valid bufferobject also supply a texcoord array
2995         if (pointer)
2996         {
2997                 int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
2998                 // texture array unit is enabled, enable the array
2999                 if (!unit->arrayenabled)
3000                 {
3001                         unit->arrayenabled = true;
3002                         GL_ClientActiveTexture(unitnum);
3003                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
3004                 }
3005                 // texcoord array
3006                 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)
3007                 {
3008                         unit->pointer_texcoord_components = components;
3009                         unit->pointer_texcoord_gltype = gltype;
3010                         unit->pointer_texcoord_stride = stride;
3011                         unit->pointer_texcoord_pointer = pointer;
3012                         unit->pointer_texcoord_vertexbuffer = vertexbuffer;
3013                         unit->pointer_texcoord_offset = bufferoffset;
3014                         GL_ClientActiveTexture(unitnum);
3015                         GL_BindVBO(bufferobject);
3016                         qglTexCoordPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
3017                 }
3018         }
3019         else
3020         {
3021                 // texture array unit is disabled, disable the array
3022                 if (unit->arrayenabled)
3023                 {
3024                         unit->arrayenabled = false;
3025                         GL_ClientActiveTexture(unitnum);
3026                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
3027                 }
3028         }
3029 }
3030
3031 int R_Mesh_TexBound(unsigned int unitnum, int id)
3032 {
3033         gltextureunit_t *unit = gl_state.units + unitnum;
3034         if (unitnum >= vid.teximageunits)
3035                 return 0;
3036         if (id == GL_TEXTURE_2D)
3037                 return unit->t2d;
3038         if (id == GL_TEXTURE_3D)
3039                 return unit->t3d;
3040         if (id == GL_TEXTURE_CUBE_MAP_ARB)
3041                 return unit->tcubemap;
3042         return 0;
3043 }
3044
3045 void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int width, int height)
3046 {
3047         switch(vid.renderpath)
3048         {
3049         case RENDERPATH_GL11:
3050         case RENDERPATH_GL13:
3051         case RENDERPATH_GL20:
3052         case RENDERPATH_CGGL:
3053                 R_Mesh_TexBind(0, tex);
3054                 GL_ActiveTexture(0);CHECKGLERROR
3055                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, sx, sy, width, height);CHECKGLERROR
3056         &nbs