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