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