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