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