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