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