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