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