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