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