]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
add DeviceLost and DeviceRestored functions to R_Modules system
[xonotic/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4
5 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
6 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)"};
7 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"};
8 cvar_t gl_mesh_separatearrays = {0, "gl_mesh_separatearrays", "1", "use several separate vertex arrays rather than one combined stream"};
9 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
10 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
11
12 cvar_t r_render = {0, "r_render", "1", "enables rendering 3D views (you want this on!)"};
13 cvar_t r_renderview = {0, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
14 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
15 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
16 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
17 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)"};
18 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"};
19 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"};
20 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"};
21
22 cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
23 qboolean v_flipped_state = false;
24
25 r_viewport_t gl_viewport;
26 matrix4x4_t gl_modelmatrix;
27 matrix4x4_t gl_viewmatrix;
28 matrix4x4_t gl_modelviewmatrix;
29 matrix4x4_t gl_projectionmatrix;
30 matrix4x4_t gl_modelviewprojectionmatrix;
31 float gl_modelview16f[16];
32 float gl_modelviewprojection16f[16];
33 qboolean gl_modelmatrixchanged;
34
35 int gl_maxdrawrangeelementsvertices;
36 int gl_maxdrawrangeelementsindices;
37
38 #ifdef DEBUGGL
39 int errornumber = 0;
40
41 void GL_PrintError(int errornumber, char *filename, int linenumber)
42 {
43         switch(errornumber)
44         {
45 #ifdef GL_INVALID_ENUM
46         case GL_INVALID_ENUM:
47                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
48                 break;
49 #endif
50 #ifdef GL_INVALID_VALUE
51         case GL_INVALID_VALUE:
52                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
53                 break;
54 #endif
55 #ifdef GL_INVALID_OPERATION
56         case GL_INVALID_OPERATION:
57                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
58                 break;
59 #endif
60 #ifdef GL_STACK_OVERFLOW
61         case GL_STACK_OVERFLOW:
62                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
63                 break;
64 #endif
65 #ifdef GL_STACK_UNDERFLOW
66         case GL_STACK_UNDERFLOW:
67                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
68                 break;
69 #endif
70 #ifdef GL_OUT_OF_MEMORY
71         case GL_OUT_OF_MEMORY:
72                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
73                 break;
74 #endif
75 #ifdef GL_TABLE_TOO_LARGE
76         case GL_TABLE_TOO_LARGE:
77                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
78                 break;
79 #endif
80 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
81         case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
82                 Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber);
83                 break;
84 #endif
85         default:
86                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
87                 break;
88         }
89 }
90 #endif
91
92 #define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active");
93
94 void SCR_ScreenShot_f (void);
95
96 typedef struct gltextureunit_s
97 {
98         int pointer_texcoord_components;
99         int pointer_texcoord_gltype;
100         size_t pointer_texcoord_stride;
101         const void *pointer_texcoord_pointer;
102         const r_meshbuffer_t *pointer_texcoord_vertexbuffer;
103         size_t pointer_texcoord_offset;
104
105         int t2d, t3d, tcubemap, trectangle;
106         int arrayenabled;
107         int rgbscale, alphascale;
108         int combine;
109         int combinergb, combinealpha;
110         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
111         int texmatrixenabled;
112         matrix4x4_t matrix;
113 }
114 gltextureunit_t;
115
116 typedef struct gl_state_s
117 {
118         int cullface;
119         int cullfaceenable;
120         int blendfunc1;
121         int blendfunc2;
122         int blend;
123         GLboolean depthmask;
124         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
125         int depthtest;
126         float depthrange[2];
127         float polygonoffset[2];
128         int alphatest;
129         int scissortest;
130         unsigned int unit;
131         unsigned int clientunit;
132         gltextureunit_t units[MAX_TEXTUREUNITS];
133         float color4f[4];
134         int lockrange_first;
135         int lockrange_count;
136         int vertexbufferobject;
137         int elementbufferobject;
138         qboolean pointer_color_enabled;
139
140         int pointer_vertex_components;
141         int pointer_vertex_gltype;
142         size_t pointer_vertex_stride;
143         const void *pointer_vertex_pointer;
144         const r_meshbuffer_t *pointer_vertex_vertexbuffer;
145         size_t pointer_vertex_offset;
146
147         int pointer_color_components;
148         int pointer_color_gltype;
149         size_t pointer_color_stride;
150         const void *pointer_color_pointer;
151         const r_meshbuffer_t *pointer_color_vertexbuffer;
152         size_t pointer_color_offset;
153
154         void *preparevertices_tempdata;
155         size_t preparevertices_tempdatamaxsize;
156         r_meshbuffer_t *preparevertices_dynamicvertexbuffer;
157         r_vertexposition_t *preparevertices_vertexposition;
158         r_vertexgeneric_t *preparevertices_vertexgeneric;
159         r_vertexmesh_t *preparevertices_vertexmesh;
160         int preparevertices_numvertices;
161
162         r_meshbuffer_t *draw_dynamicindexbuffer;
163
164         qboolean usevbo_staticvertex;
165         qboolean usevbo_staticindex;
166         qboolean usevbo_dynamicvertex;
167         qboolean usevbo_dynamicindex;
168
169         memexpandablearray_t meshbufferarray;
170
171         qboolean active;
172 }
173 gl_state_t;
174
175 static gl_state_t gl_state;
176
177
178 /*
179 note: here's strip order for a terrain row:
180 0--1--2--3--4
181 |\ |\ |\ |\ |
182 | \| \| \| \|
183 A--B--C--D--E
184 clockwise
185
186 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
187
188 *elements++ = i + row;
189 *elements++ = i;
190 *elements++ = i + row + 1;
191 *elements++ = i;
192 *elements++ = i + 1;
193 *elements++ = i + row + 1;
194
195
196 for (y = 0;y < rows - 1;y++)
197 {
198         for (x = 0;x < columns - 1;x++)
199         {
200                 i = y * rows + x;
201                 *elements++ = i + columns;
202                 *elements++ = i;
203                 *elements++ = i + columns + 1;
204                 *elements++ = i;
205                 *elements++ = i + 1;
206                 *elements++ = i + columns + 1;
207         }
208 }
209
210 alternative:
211 0--1--2--3--4
212 | /| /|\ | /|
213 |/ |/ | \|/ |
214 A--B--C--D--E
215 counterclockwise
216
217 for (y = 0;y < rows - 1;y++)
218 {
219         for (x = 0;x < columns - 1;x++)
220         {
221                 i = y * rows + x;
222                 *elements++ = i;
223                 *elements++ = i + columns;
224                 *elements++ = i + columns + 1;
225                 *elements++ = i + columns;
226                 *elements++ = i + columns + 1;
227                 *elements++ = i + 1;
228         }
229 }
230 */
231
232 int polygonelement3i[(POLYGONELEMENTS_MAXPOINTS-2)*3];
233 unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3];
234 int quadelement3i[QUADELEMENTS_MAXQUADS*6];
235 unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6];
236
237 void GL_VBOStats_f(void)
238 {
239         GL_Mesh_ListVBOs(true);
240 }
241
242 static void GL_Backend_ResetState(void);
243
244 static void gl_backend_start(void)
245 {
246         memset(&gl_state, 0, sizeof(gl_state));
247
248         gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
249         gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo;
250         gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
251         gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo;
252         Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128);
253
254         Con_DPrintf("OpenGL backend started.\n");
255
256         CHECKGLERROR
257
258         GL_Backend_ResetState();
259 }
260
261 static void gl_backend_shutdown(void)
262 {
263         Con_DPrint("OpenGL Backend shutting down\n");
264
265         if (gl_state.preparevertices_tempdata)
266                 Mem_Free(gl_state.preparevertices_tempdata);
267         if (gl_state.preparevertices_dynamicvertexbuffer)
268                 R_Mesh_DestroyMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer);
269
270         Mem_ExpandableArray_FreeArray(&gl_state.meshbufferarray);
271
272         memset(&gl_state, 0, sizeof(gl_state));
273 }
274
275 static void gl_backend_newmap(void)
276 {
277 }
278
279 void gl_backend_init(void)
280 {
281         int i;
282
283         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
284         {
285                 polygonelement3s[i * 3 + 0] = 0;
286                 polygonelement3s[i * 3 + 1] = i + 1;
287                 polygonelement3s[i * 3 + 2] = i + 2;
288         }
289         // elements for rendering a series of quads as triangles
290         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
291         {
292                 quadelement3s[i * 6 + 0] = i * 4;
293                 quadelement3s[i * 6 + 1] = i * 4 + 1;
294                 quadelement3s[i * 6 + 2] = i * 4 + 2;
295                 quadelement3s[i * 6 + 3] = i * 4;
296                 quadelement3s[i * 6 + 4] = i * 4 + 2;
297                 quadelement3s[i * 6 + 5] = i * 4 + 3;
298         }
299
300         for (i = 0;i < (POLYGONELEMENTS_MAXPOINTS - 2)*3;i++)
301                 polygonelement3i[i] = polygonelement3s[i];
302         for (i = 0;i < QUADELEMENTS_MAXQUADS*3;i++)
303                 quadelement3i[i] = quadelement3s[i];
304
305         Cvar_RegisterVariable(&r_render);
306         Cvar_RegisterVariable(&r_renderview);
307         Cvar_RegisterVariable(&r_waterwarp);
308         Cvar_RegisterVariable(&gl_polyblend);
309         Cvar_RegisterVariable(&v_flipped);
310         Cvar_RegisterVariable(&gl_dither);
311         Cvar_RegisterVariable(&gl_vbo);
312         Cvar_RegisterVariable(&gl_vbo_dynamicvertex);
313         Cvar_RegisterVariable(&gl_vbo_dynamicindex);
314         Cvar_RegisterVariable(&gl_paranoid);
315         Cvar_RegisterVariable(&gl_printcheckerror);
316
317         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
318         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
319         Cvar_RegisterVariable(&gl_mesh_prefer_short_elements);
320         Cvar_RegisterVariable(&gl_mesh_separatearrays);
321
322         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");
323
324         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap, NULL, NULL);
325 }
326
327 void GL_SetMirrorState(qboolean state);
328
329 void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out)
330 {
331         vec4_t temp;
332         float iw;
333         Matrix4x4_Transform4 (&v->viewmatrix, in, temp);
334         Matrix4x4_Transform4 (&v->projectmatrix, temp, out);
335         iw = 1.0f / out[3];
336         out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f;
337         out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f;
338         out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f;
339 }
340
341 static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m, float normalx, float normaly, float normalz, float dist)
342 {
343         float q[4];
344         float d;
345         float clipPlane[4], v3[3], v4[3];
346         float normal[3];
347
348         // This is inspired by Oblique Depth Projection from http://www.terathon.com/code/oblique.php
349
350         VectorSet(normal, normalx, normaly, normalz);
351         Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane);
352         VectorScale(normal, dist, v3);
353         Matrix4x4_Transform(&v->viewmatrix, v3, v4);
354         // FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique
355         clipPlane[3] = -DotProduct(v4, clipPlane);
356
357 #if 0
358 {
359         // testing code for comparing results
360         float clipPlane2[4];
361         VectorCopy4(clipPlane, clipPlane2);
362         R_EntityMatrix(&identitymatrix);
363         VectorSet(q, normal[0], normal[1], normal[2], -dist);
364         qglClipPlane(GL_CLIP_PLANE0, q);
365         qglGetClipPlane(GL_CLIP_PLANE0, q);
366         VectorCopy4(q, clipPlane);
367 }
368 #endif
369
370         // Calculate the clip-space corner point opposite the clipping plane
371         // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
372         // transform it into camera space by multiplying it
373         // by the inverse of the projection matrix
374         q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + m[8]) / m[0];
375         q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + m[9]) / m[5];
376         q[2] = -1.0f;
377         q[3] = (1.0f + m[10]) / m[14];
378
379         // Calculate the scaled plane vector
380         d = 2.0f / DotProduct4(clipPlane, q);
381
382         // Replace the third row of the projection matrix
383         m[2] = clipPlane[0] * d;
384         m[6] = clipPlane[1] * d;
385         m[10] = clipPlane[2] * d + 1.0f;
386         m[14] = clipPlane[3] * d;
387 }
388
389 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)
390 {
391         float left = x1, right = x2, bottom = y2, top = y1, zNear = nearclip, zFar = farclip;
392         float m[16];
393         memset(v, 0, sizeof(*v));
394         v->type = R_VIEWPORTTYPE_ORTHO;
395         v->cameramatrix = *cameramatrix;
396         v->x = x;
397         v->y = y;
398         v->z = 0;
399         v->width = width;
400         v->height = height;
401         v->depth = 1;
402         memset(m, 0, sizeof(m));
403         m[0]  = 2/(right - left);
404         m[5]  = 2/(top - bottom);
405         m[10] = -2/(zFar - zNear);
406         m[12] = - (right + left)/(right - left);
407         m[13] = - (top + bottom)/(top - bottom);
408         m[14] = - (zFar + zNear)/(zFar - zNear);
409         m[15] = 1;
410         v->screentodepth[0] = -farclip / (farclip - nearclip);
411         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
412
413         Matrix4x4_Invert_Full(&v->viewmatrix, &v->cameramatrix);
414
415         if (nearplane)
416                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
417
418         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
419
420 #if 0
421         {
422                 vec4_t test1;
423                 vec4_t test2;
424                 Vector4Set(test1, (x1+x2)*0.5f, (y1+y2)*0.5f, 0.0f, 1.0f);
425                 R_Viewport_TransformToScreen(v, test1, test2);
426                 Con_Printf("%f %f %f -> %f %f %f\n", test1[0], test1[1], test1[2], test2[0], test2[1], test2[2]);
427         }
428 #endif
429 }
430
431 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)
432 {
433         matrix4x4_t tempmatrix, basematrix;
434         float m[16];
435         memset(v, 0, sizeof(*v));
436
437         if(v_flipped.integer)
438                 frustumx = -frustumx;
439
440         v->type = R_VIEWPORTTYPE_PERSPECTIVE;
441         v->cameramatrix = *cameramatrix;
442         v->x = x;
443         v->y = y;
444         v->z = 0;
445         v->width = width;
446         v->height = height;
447         v->depth = 1;
448         memset(m, 0, sizeof(m));
449         m[0]  = 1.0 / frustumx;
450         m[5]  = 1.0 / frustumy;
451         m[10] = -(farclip + nearclip) / (farclip - nearclip);
452         m[11] = -1;
453         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
454         v->screentodepth[0] = -farclip / (farclip - nearclip);
455         v->screentodepth[1] = farclip * nearclip / (farclip - nearclip);
456
457         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
458         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
459         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
460         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
461
462         if (nearplane)
463                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
464
465         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
466 }
467
468 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)
469 {
470         matrix4x4_t tempmatrix, basematrix;
471         const float nudge = 1.0 - 1.0 / (1<<23);
472         float m[16];
473         memset(v, 0, sizeof(*v));
474
475         if(v_flipped.integer)
476                 frustumx = -frustumx;
477
478         v->type = R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP;
479         v->cameramatrix = *cameramatrix;
480         v->x = x;
481         v->y = y;
482         v->z = 0;
483         v->width = width;
484         v->height = height;
485         v->depth = 1;
486         memset(m, 0, sizeof(m));
487         m[ 0] = 1.0 / frustumx;
488         m[ 5] = 1.0 / frustumy;
489         m[10] = -nudge;
490         m[11] = -1;
491         m[14] = -2 * nearclip * nudge;
492         v->screentodepth[0] = (m[10] + 1) * 0.5 - 1;
493         v->screentodepth[1] = m[14] * -0.5;
494
495         Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
496         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
497         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
498         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
499
500         if (nearplane)
501                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
502
503         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
504 }
505
506 float cubeviewmatrix[6][16] =
507 {
508     // standard cubemap projections
509     { // +X
510          0, 0,-1, 0,
511          0,-1, 0, 0,
512         -1, 0, 0, 0,
513          0, 0, 0, 1,
514     },
515     { // -X
516          0, 0, 1, 0,
517          0,-1, 0, 0,
518          1, 0, 0, 0,
519          0, 0, 0, 1,
520     },
521     { // +Y
522          1, 0, 0, 0,
523          0, 0,-1, 0,
524          0, 1, 0, 0,
525          0, 0, 0, 1,
526     },
527     { // -Y
528          1, 0, 0, 0,
529          0, 0, 1, 0,
530          0,-1, 0, 0,
531          0, 0, 0, 1,
532     },
533     { // +Z
534          1, 0, 0, 0,
535          0,-1, 0, 0,
536          0, 0,-1, 0,
537          0, 0, 0, 1,
538     },
539     { // -Z
540         -1, 0, 0, 0,
541          0,-1, 0, 0,
542          0, 0, 1, 0,
543          0, 0, 0, 1,
544     },
545 };
546 float rectviewmatrix[6][16] =
547 {
548     // sign-preserving cubemap projections
549     { // +X
550          0, 0,-1, 0,
551          0, 1, 0, 0,
552          1, 0, 0, 0,
553          0, 0, 0, 1,
554     },
555     { // -X
556          0, 0, 1, 0,
557          0, 1, 0, 0,
558          1, 0, 0, 0,
559          0, 0, 0, 1,
560     },
561     { // +Y
562          1, 0, 0, 0,
563          0, 0,-1, 0,
564          0, 1, 0, 0,
565          0, 0, 0, 1,
566     },
567     { // -Y
568          1, 0, 0, 0,
569          0, 0, 1, 0,
570          0, 1, 0, 0,
571          0, 0, 0, 1,
572     },
573     { // +Z
574          1, 0, 0, 0,
575          0, 1, 0, 0,
576          0, 0,-1, 0,
577          0, 0, 0, 1,
578     },
579     { // -Z
580          1, 0, 0, 0,
581          0, 1, 0, 0,
582          0, 0, 1, 0,
583          0, 0, 0, 1,
584     },
585 };
586
587 void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane)
588 {
589         matrix4x4_t tempmatrix, basematrix;
590         float m[16];
591         memset(v, 0, sizeof(*v));
592         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
593         v->cameramatrix = *cameramatrix;
594         v->width = size;
595         v->height = size;
596         v->depth = 1;
597         memset(m, 0, sizeof(m));
598         m[0] = m[5] = 1.0f;
599         m[10] = -(farclip + nearclip) / (farclip - nearclip);
600         m[11] = -1;
601         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
602
603         Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]);
604         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
605         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
606
607         if (nearplane)
608                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
609
610         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
611 }
612
613 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)
614 {
615         matrix4x4_t tempmatrix, basematrix;
616         float m[16];
617         memset(v, 0, sizeof(*v));
618         v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
619         v->cameramatrix = *cameramatrix;
620         v->x = (side & 1) * size;
621         v->y = (side >> 1) * size;
622         v->width = size;
623         v->height = size;
624         v->depth = 1;
625         memset(m, 0, sizeof(m));
626         m[0] = m[5] = 1.0f * ((float)size - border) / size;
627         m[10] = -(farclip + nearclip) / (farclip - nearclip);
628         m[11] = -1;
629         m[14] = -2 * nearclip * farclip / (farclip - nearclip);
630
631         Matrix4x4_FromArrayFloatGL(&basematrix, rectviewmatrix[side]);
632         Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
633         Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
634
635         if (nearplane)
636                 R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
637
638         Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
639 }
640
641 void R_SetViewport(const r_viewport_t *v)
642 {
643         float m[16];
644         gl_viewport = *v;
645
646         CHECKGLERROR
647         qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
648
649         // FIXME: v_flipped_state is evil, this probably breaks somewhere
650         GL_SetMirrorState(v_flipped.integer && (v->type == R_VIEWPORTTYPE_PERSPECTIVE || v->type == R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP));
651
652         // copy over the matrices to our state
653         gl_viewmatrix = v->viewmatrix;
654         gl_projectionmatrix = v->projectmatrix;
655
656         switch(vid.renderpath)
657         {
658         case RENDERPATH_GL20:
659         case RENDERPATH_CGGL:
660 //              break;
661         case RENDERPATH_GL13:
662         case RENDERPATH_GL11:
663                 // Load the projection matrix into OpenGL
664                 qglMatrixMode(GL_PROJECTION);CHECKGLERROR
665                 Matrix4x4_ToArrayFloatGL(&gl_projectionmatrix, m);
666                 qglLoadMatrixf(m);CHECKGLERROR
667                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
668                 break;
669         }
670
671         // force an update of the derived matrices
672         gl_modelmatrixchanged = true;
673         R_EntityMatrix(&gl_modelmatrix);
674 }
675
676 void R_GetViewport(r_viewport_t *v)
677 {
678         *v = gl_viewport;
679 }
680
681 static void GL_BindVBO(int bufferobject)
682 {
683         if (gl_state.vertexbufferobject != bufferobject)
684         {
685                 gl_state.vertexbufferobject = bufferobject;
686                 CHECKGLERROR
687                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);
688                 CHECKGLERROR
689         }
690 }
691
692 static void GL_BindEBO(int bufferobject)
693 {
694         if (gl_state.elementbufferobject != bufferobject)
695         {
696                 gl_state.elementbufferobject = bufferobject;
697                 CHECKGLERROR
698                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);
699                 CHECKGLERROR
700         }
701 }
702
703 static void GL_Backend_ResetState(void)
704 {
705         unsigned int i;
706         gl_state.active = true;
707         gl_state.depthtest = true;
708         gl_state.alphatest = false;
709         gl_state.blendfunc1 = GL_ONE;
710         gl_state.blendfunc2 = GL_ZERO;
711         gl_state.blend = false;
712         gl_state.depthmask = GL_TRUE;
713         gl_state.colormask = 15;
714         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
715         gl_state.lockrange_first = 0;
716         gl_state.lockrange_count = 0;
717         gl_state.cullface = v_flipped_state ? GL_BACK : GL_FRONT; // quake is backwards, this culls back faces
718         gl_state.cullfaceenable = true;
719         gl_state.polygonoffset[0] = 0;
720         gl_state.polygonoffset[1] = 0;
721
722         CHECKGLERROR
723
724         qglColorMask(1, 1, 1, 1);
725         qglAlphaFunc(GL_GEQUAL, 0.5);CHECKGLERROR
726         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
727         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
728         qglDisable(GL_BLEND);CHECKGLERROR
729         qglCullFace(gl_state.cullface);CHECKGLERROR
730         qglEnable(GL_CULL_FACE);CHECKGLERROR
731         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
732         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
733         qglDepthMask(gl_state.depthmask);CHECKGLERROR
734         qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
735
736         if (vid.support.arb_vertex_buffer_object)
737         {
738                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
739                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
740         }
741
742         if (vid.support.ext_framebuffer_object)
743         {
744                 qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
745                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
746         }
747
748         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
749         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
750
751         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
752         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
753
754         GL_Color(0, 0, 0, 0);
755         GL_Color(1, 1, 1, 1);
756
757         gl_state.unit = MAX_TEXTUREUNITS;
758         gl_state.clientunit = MAX_TEXTUREUNITS;
759         switch(vid.renderpath)
760         {
761         case RENDERPATH_GL20:
762         case RENDERPATH_CGGL:
763                 for (i = 0;i < vid.teximageunits;i++)
764                 {
765                         GL_ActiveTexture(i);
766                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
767                         if (vid.support.ext_texture_3d)
768                         {
769                                 qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
770                         }
771                         if (vid.support.arb_texture_cube_map)
772                         {
773                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
774                         }
775                         if (vid.support.arb_texture_rectangle)
776                         {
777                                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
778                         }
779                 }
780
781                 for (i = 0;i < vid.texarrayunits;i++)
782                 {
783                         GL_ClientActiveTexture(i);
784                         GL_BindVBO(0);
785                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
786                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
787                 }
788                 CHECKGLERROR
789                 break;
790         case RENDERPATH_GL13:
791         case RENDERPATH_GL11:
792                 for (i = 0;i < vid.texunits;i++)
793                 {
794                         GL_ActiveTexture(i);
795                         GL_ClientActiveTexture(i);
796                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
797                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
798                         if (vid.support.ext_texture_3d)
799                         {
800                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
801                                 qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
802                         }
803                         if (vid.support.arb_texture_cube_map)
804                         {
805                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
806                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
807                         }
808                         if (vid.support.arb_texture_rectangle)
809                         {
810                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
811                                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
812                         }
813                         GL_BindVBO(0);
814                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
815                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
816                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
817                         qglLoadIdentity();CHECKGLERROR
818                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
819                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
820                 }
821                 CHECKGLERROR
822                 break;
823         }
824 }
825
826 void GL_ActiveTexture(unsigned int num)
827 {
828         if (gl_state.unit != num)
829         {
830                 gl_state.unit = num;
831                 if (qglActiveTexture)
832                 {
833                         CHECKGLERROR
834                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
835                         CHECKGLERROR
836                 }
837         }
838 }
839
840 void GL_ClientActiveTexture(unsigned int num)
841 {
842         if (gl_state.clientunit != num)
843         {
844                 gl_state.clientunit = num;
845                 if (qglActiveTexture)
846                 {
847                         CHECKGLERROR
848                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
849                         CHECKGLERROR
850                 }
851         }
852 }
853
854 void GL_BlendFunc(int blendfunc1, int blendfunc2)
855 {
856         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
857         {
858                 CHECKGLERROR
859                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
860                 if (gl_state.blendfunc2 == GL_ZERO)
861                 {
862                         if (gl_state.blendfunc1 == GL_ONE)
863                         {
864                                 if (gl_state.blend)
865                                 {
866                                         gl_state.blend = 0;
867                                         qglDisable(GL_BLEND);CHECKGLERROR
868                                 }
869                         }
870                         else
871                         {
872                                 if (!gl_state.blend)
873                                 {
874                                         gl_state.blend = 1;
875                                         qglEnable(GL_BLEND);CHECKGLERROR
876                                 }
877                         }
878                 }
879                 else
880                 {
881                         if (!gl_state.blend)
882                         {
883                                 gl_state.blend = 1;
884                                 qglEnable(GL_BLEND);CHECKGLERROR
885                         }
886                 }
887         }
888 }
889
890 void GL_DepthMask(int state)
891 {
892         if (gl_state.depthmask != state)
893         {
894                 CHECKGLERROR
895                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
896         }
897 }
898
899 void GL_DepthTest(int state)
900 {
901         if (gl_state.depthtest != state)
902         {
903                 gl_state.depthtest = state;
904                 CHECKGLERROR
905                 if (gl_state.depthtest)
906                 {
907                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
908                 }
909                 else
910                 {
911                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
912                 }
913         }
914 }
915
916 void GL_DepthRange(float nearfrac, float farfrac)
917 {
918         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
919         {
920                 gl_state.depthrange[0] = nearfrac;
921                 gl_state.depthrange[1] = farfrac;
922                 qglDepthRange(nearfrac, farfrac);
923         }
924 }
925
926 void GL_PolygonOffset(float planeoffset, float depthoffset)
927 {
928         if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset)
929         {
930                 gl_state.polygonoffset[0] = planeoffset;
931                 gl_state.polygonoffset[1] = depthoffset;
932                 qglPolygonOffset(planeoffset, depthoffset);
933         }
934 }
935
936 void GL_SetMirrorState(qboolean state)
937 {
938         if(!state != !v_flipped_state)
939         {
940                 // change cull face mode!
941                 if(gl_state.cullface == GL_BACK)
942                         qglCullFace((gl_state.cullface = GL_FRONT));
943                 else if(gl_state.cullface == GL_FRONT)
944                         qglCullFace((gl_state.cullface = GL_BACK));
945         }
946         v_flipped_state = state;
947 }
948
949 void GL_CullFace(int state)
950 {
951         CHECKGLERROR
952
953         if(v_flipped_state)
954         {
955                 if(state == GL_FRONT)
956                         state = GL_BACK;
957                 else if(state == GL_BACK)
958                         state = GL_FRONT;
959         }
960
961         if (state != GL_NONE)
962         {
963                 if (!gl_state.cullfaceenable)
964                 {
965                         gl_state.cullfaceenable = true;
966                         qglEnable(GL_CULL_FACE);CHECKGLERROR
967                 }
968                 if (gl_state.cullface != state)
969                 {
970                         gl_state.cullface = state;
971                         qglCullFace(gl_state.cullface);CHECKGLERROR
972                 }
973         }
974         else
975         {
976                 if (gl_state.cullfaceenable)
977                 {
978                         gl_state.cullfaceenable = false;
979                         qglDisable(GL_CULL_FACE);CHECKGLERROR
980                 }
981         }
982 }
983
984 void GL_AlphaTest(int state)
985 {
986         if (gl_state.alphatest != state)
987         {
988                 gl_state.alphatest = state;
989                 CHECKGLERROR
990                 if (gl_state.alphatest)
991                 {
992                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
993                 }
994                 else
995                 {
996                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
997                 }
998         }
999 }
1000
1001 void GL_ColorMask(int r, int g, int b, int a)
1002 {
1003         int state = r*8 + g*4 + b*2 + a*1;
1004         if (gl_state.colormask != state)
1005         {
1006                 gl_state.colormask = state;
1007                 CHECKGLERROR
1008                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
1009         }
1010 }
1011
1012 void GL_Color(float cr, float cg, float cb, float ca)
1013 {
1014         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)
1015         {
1016                 gl_state.color4f[0] = cr;
1017                 gl_state.color4f[1] = cg;
1018                 gl_state.color4f[2] = cb;
1019                 gl_state.color4f[3] = ca;
1020                 CHECKGLERROR
1021                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
1022                 CHECKGLERROR
1023         }
1024 }
1025
1026 void GL_Scissor (int x, int y, int width, int height)
1027 {
1028         CHECKGLERROR
1029         qglScissor(x, y,width,height);
1030         CHECKGLERROR
1031 }
1032
1033 void GL_ScissorTest(int state)
1034 {
1035         if(gl_state.scissortest == state)
1036                 return;
1037
1038         CHECKGLERROR
1039         if((gl_state.scissortest = state))
1040                 qglEnable(GL_SCISSOR_TEST);
1041         else
1042                 qglDisable(GL_SCISSOR_TEST);
1043         CHECKGLERROR
1044 }
1045
1046 void GL_Clear(int mask)
1047 {
1048         CHECKGLERROR
1049         qglClear(mask);CHECKGLERROR
1050 }
1051
1052 // called at beginning of frame
1053 void R_Mesh_Start(void)
1054 {
1055         BACKENDACTIVECHECK
1056         CHECKGLERROR
1057         gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
1058         gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo;
1059         gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
1060         gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo;
1061         if (gl_printcheckerror.integer && !gl_paranoid.integer)
1062         {
1063                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
1064                 Cvar_SetValueQuick(&gl_paranoid, 1);
1065         }
1066 }
1067
1068 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
1069 {
1070         int shaderobject;
1071         int shadercompiled;
1072         char compilelog[MAX_INPUTLINE];
1073         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
1074         if (!shaderobject)
1075                 return false;
1076         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
1077         qglCompileShaderARB(shaderobject);CHECKGLERROR
1078         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
1079         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
1080         if (compilelog[0] && (strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error") || strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")))
1081         {
1082                 int i, j, pretextlines = 0;
1083                 for (i = 0;i < numstrings - 1;i++)
1084                         for (j = 0;strings[i][j];j++)
1085                                 if (strings[i][j] == '\n')
1086                                         pretextlines++;
1087                 Con_Printf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines);
1088         }
1089         if (!shadercompiled)
1090         {
1091                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
1092                 return false;
1093         }
1094         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
1095         qglDeleteObjectARB(shaderobject);CHECKGLERROR
1096         return true;
1097 }
1098
1099 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)
1100 {
1101         GLint programlinked;
1102         GLuint programobject = 0;
1103         char linklog[MAX_INPUTLINE];
1104         CHECKGLERROR
1105
1106         programobject = qglCreateProgramObjectARB();CHECKGLERROR
1107         if (!programobject)
1108                 return 0;
1109
1110         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
1111                 goto cleanup;
1112
1113 #ifdef GL_GEOMETRY_SHADER_ARB
1114         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
1115                 goto cleanup;
1116 #endif
1117
1118         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
1119                 goto cleanup;
1120
1121         qglLinkProgramARB(programobject);CHECKGLERROR
1122         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
1123         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
1124         if (linklog[0])
1125         {
1126                 if (strstr(linklog, "error") || strstr(linklog, "ERROR") || strstr(linklog, "Error") || strstr(linklog, "WARNING") || strstr(linklog, "warning") || strstr(linklog, "Warning"))
1127                         Con_DPrintf("program link log:\n%s\n", linklog);
1128                 // software vertex shader is ok but software fragment shader is WAY
1129                 // too slow, fail program if so.
1130                 // NOTE: this string might be ATI specific, but that's ok because the
1131                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
1132                 // software fragment shader due to low instruction and dependent
1133                 // texture limits.
1134                 if (strstr(linklog, "fragment shader will run in software"))
1135                         programlinked = false;
1136         }
1137         if (!programlinked)
1138                 goto cleanup;
1139         return programobject;
1140 cleanup:
1141         qglDeleteObjectARB(programobject);CHECKGLERROR
1142         return 0;
1143 }
1144
1145 void GL_Backend_FreeProgram(unsigned int prog)
1146 {
1147         CHECKGLERROR
1148         qglDeleteObjectARB(prog);
1149         CHECKGLERROR
1150 }
1151
1152 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
1153 {
1154         int i;
1155         if (offset)
1156         {
1157                 for (i = 0;i < count;i++)
1158                         *out++ = *in++ + offset;
1159         }
1160         else
1161                 memcpy(out, in, sizeof(*out) * count);
1162 }
1163
1164 // renders triangles using vertices from the active arrays
1165 int paranoidblah = 0;
1166 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)
1167 {
1168         unsigned int numelements = numtriangles * 3;
1169         int bufferobject3i;
1170         size_t bufferoffset3i;
1171         int bufferobject3s;
1172         size_t bufferoffset3s;
1173         if (numvertices < 3 || numtriangles < 1)
1174         {
1175                 if (numvertices < 0 || numtriangles < 0 || developer_extra.integer)
1176                         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);
1177                 return;
1178         }
1179         if (gl_state.pointer_vertex_pointer == NULL)
1180         {
1181                 Con_DPrintf("R_Mesh_Draw with no vertex pointer!\n");
1182                 return;
1183         }
1184         if (!gl_mesh_prefer_short_elements.integer)
1185         {
1186                 if (element3i)
1187                         element3s = NULL;
1188                 if (element3i_indexbuffer)
1189                         element3i_indexbuffer = NULL;
1190         }
1191         // adjust the pointers for firsttriangle
1192         if (element3i)
1193                 element3i += firsttriangle * 3;
1194         if (element3i_indexbuffer)
1195                 element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i);
1196         if (element3s)
1197                 element3s += firsttriangle * 3;
1198         if (element3s_indexbuffer)
1199                 element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
1200         // check if the user specified to ignore static index buffers
1201         if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset)))
1202         {
1203                 element3i_indexbuffer = NULL;
1204                 element3s_indexbuffer = NULL;
1205         }
1206         // upload a dynamic index buffer if needed
1207         if (element3s)
1208         {
1209                 if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex)
1210                 {
1211                         if (gl_state.draw_dynamicindexbuffer)
1212                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3s, numelements * sizeof(*element3s));
1213                         else
1214                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3s, numelements * sizeof(*element3s), "temporary", true, true);
1215                         element3s_indexbuffer = gl_state.draw_dynamicindexbuffer;
1216                         element3s_bufferoffset = 0;
1217                 }
1218         }
1219         else if (element3i)
1220         {
1221                 if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex)
1222                 {
1223                         if (gl_state.draw_dynamicindexbuffer)
1224                                 R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3i, numelements * sizeof(*element3i));
1225                         else
1226                                 gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3i, numelements * sizeof(*element3i), "temporary", true, true);
1227                         element3i_indexbuffer = gl_state.draw_dynamicindexbuffer;
1228                         element3i_bufferoffset = 0;
1229                 }
1230         }
1231         bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
1232         bufferoffset3i = element3i_bufferoffset;
1233         bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0;
1234         bufferoffset3s = element3s_bufferoffset;
1235         CHECKGLERROR
1236         r_refdef.stats.meshes++;
1237         r_refdef.stats.meshes_elements += numelements;
1238         if (gl_paranoid.integer)
1239         {
1240                 unsigned int i;
1241                 // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
1242 #if 0
1243                 unsigned int j, size;
1244                 const int *p;
1245                 // note: there's no validation done here on buffer objects because it
1246                 // is somewhat difficult to get at the data, and gl_paranoid can be
1247                 // used without buffer objects if the need arises
1248                 // (the data could be gotten using glMapBuffer but it would be very
1249                 //  slow due to uncachable video memory reads)
1250                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
1251                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
1252                 CHECKGLERROR
1253                 if (gl_state.pointer_vertex_pointer)
1254                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
1255                                 paranoidblah += *p;
1256                 if (gl_state.pointer_color_enabled)
1257                 {
1258                         if (!qglIsEnabled(GL_COLOR_ARRAY))
1259                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
1260                         CHECKGLERROR
1261                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1262                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
1263                                         paranoidblah += *p;
1264                 }
1265                 for (i = 0;i < vid.texarrayunits;i++)
1266                 {
1267                         if (gl_state.units[i].arrayenabled)
1268                         {
1269                                 GL_ClientActiveTexture(i);
1270                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
1271                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
1272                                 CHECKGLERROR
1273                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
1274                                         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++)
1275                                                 paranoidblah += *p;
1276                         }
1277                 }
1278 #endif
1279                 if (element3i)
1280                 {
1281                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1282                         {
1283                                 if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
1284                                 {
1285                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
1286                                         return;
1287                                 }
1288                         }
1289                 }
1290                 if (element3s)
1291                 {
1292                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1293                         {
1294                                 if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
1295                                 {
1296                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
1297                                         return;
1298                                 }
1299                         }
1300                 }
1301                 CHECKGLERROR
1302         }
1303         if (r_render.integer || r_refdef.draw2dstage)
1304         {
1305                 CHECKGLERROR
1306                 if (gl_mesh_testmanualfeeding.integer)
1307                 {
1308                         unsigned int i, j, element;
1309                         const GLfloat *p;
1310                         qglBegin(GL_TRIANGLES);
1311                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
1312                         {
1313                                 if (element3i)
1314                                         element = element3i[i];
1315                                 else if (element3s)
1316                                         element = element3s[i];
1317                                 else
1318                                         element = firstvertex + i;
1319                                 for (j = 0;j < vid.texarrayunits;j++)
1320                                 {
1321                                         if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
1322                                         {
1323                                                 if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
1324                                                 {
1325                                                         p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
1326                                                         if (vid.texarrayunits > 1)
1327                                                         {
1328                                                                 if (gl_state.units[j].pointer_texcoord_components == 4)
1329                                                                         qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
1330                                                                 else if (gl_state.units[j].pointer_texcoord_components == 3)
1331                                                                         qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
1332                                                                 else if (gl_state.units[j].pointer_texcoord_components == 2)
1333                                                                         qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
1334                                                                 else
1335                                                                         qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
1336                                                         }
1337                                                         else
1338                                                         {
1339                                                                 if (gl_state.units[j].pointer_texcoord_components == 4)
1340                                                                         qglTexCoord4f(p[0], p[1], p[2], p[3]);
1341                                                                 else if (gl_state.units[j].pointer_texcoord_components == 3)
1342                                                                         qglTexCoord3f(p[0], p[1], p[2]);
1343                                                                 else if (gl_state.units[j].pointer_texcoord_components == 2)
1344                                                                         qglTexCoord2f(p[0], p[1]);
1345                                                                 else
1346                                                                         qglTexCoord1f(p[0]);
1347                                                         }
1348                                                 }
1349                                                 else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
1350                                                 {
1351                                                         const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
1352                                                         if (vid.texarrayunits > 1)
1353                                                         {
1354                                                                 if (gl_state.units[j].pointer_texcoord_components == 4)
1355                                                                         qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
1356                                                                 else if (gl_state.units[j].pointer_texcoord_components == 3)
1357                                                                         qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]);
1358                                                                 else if (gl_state.units[j].pointer_texcoord_components == 2)
1359                                                                         qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
1360                                                                 else if (gl_state.units[j].pointer_texcoord_components == 1)
1361                                                                         qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
1362                                                         }
1363                                                         else
1364                                                         {
1365                                                                 if (gl_state.units[j].pointer_texcoord_components == 4)
1366                                                                         qglTexCoord4f(s[0], s[1], s[2], s[3]);
1367                                                                 else if (gl_state.units[j].pointer_texcoord_components == 3)
1368                                                                         qglTexCoord3f(s[0], s[1], s[2]);
1369                                                                 else if (gl_state.units[j].pointer_texcoord_components == 2)
1370                                                                         qglTexCoord2f(s[0], s[1]);
1371                                                                 else if (gl_state.units[j].pointer_texcoord_components == 1)
1372                                                                         qglTexCoord1f(s[0]);
1373                                                         }
1374                                                 }
1375                                                 else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
1376                                                 {
1377                                                         const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
1378                                                         if (vid.texarrayunits > 1)
1379                                                         {
1380                                                                 if (gl_state.units[j].pointer_texcoord_components == 4)
1381                                                                         qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
1382                                                                 else if (gl_state.units[j].pointer_texcoord_components == 3)
1383                                                                         qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]);
1384                                                                 else if (gl_state.units[j].pointer_texcoord_components == 2)
1385                                                                         qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
1386                                                                 else if (gl_state.units[j].pointer_texcoord_components == 1)
1387                                                                         qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
1388                                                         }
1389                                                         else
1390                                                         {
1391                                                                 if (gl_state.units[j].pointer_texcoord_components == 4)
1392                                                                         qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
1393                                                                 else if (gl_state.units[j].pointer_texcoord_components == 3)
1394                                                                         qglTexCoord3f(sb[0], sb[1], sb[2]);
1395                                                                 else if (gl_state.units[j].pointer_texcoord_components == 2)
1396                                                                         qglTexCoord2f(sb[0], sb[1]);
1397                                                                 else if (gl_state.units[j].pointer_texcoord_components == 1)
1398                                                                         qglTexCoord1f(sb[0]);
1399                                                         }
1400                                                 }
1401                                         }
1402                                 }
1403                                 if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
1404                                 {
1405                                         if (gl_state.pointer_color_gltype == GL_FLOAT)
1406                                         {
1407                                                 p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
1408                                                 qglColor4f(p[0], p[1], p[2], p[3]);
1409                                         }
1410                                         else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
1411                                         {
1412                                                 const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
1413                                                 qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
1414                                         }
1415                                 }
1416                                 if (gl_state.pointer_vertex_gltype == GL_FLOAT)
1417                                 {
1418                                         p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
1419                                         if (gl_state.pointer_vertex_components == 4)
1420                                                 qglVertex4f(p[0], p[1], p[2], p[3]);
1421                                         else if (gl_state.pointer_vertex_components == 3)
1422                                                 qglVertex3f(p[0], p[1], p[2]);
1423                                         else
1424                                                 qglVertex2f(p[0], p[1]);
1425                                 }
1426                         }
1427                         qglEnd();
1428                         CHECKGLERROR
1429                 }
1430                 else if (bufferobject3s)
1431                 {
1432                         GL_BindEBO(bufferobject3s);
1433                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1434                         {
1435                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
1436                                 CHECKGLERROR
1437                         }
1438                         else
1439                         {
1440                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
1441                                 CHECKGLERROR
1442                         }
1443                 }
1444                 else if (bufferobject3i)
1445                 {
1446                         GL_BindEBO(bufferobject3i);
1447                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1448                         {
1449                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
1450                                 CHECKGLERROR
1451                         }
1452                         else
1453                         {
1454                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
1455                                 CHECKGLERROR
1456                         }
1457                 }
1458                 else if (element3s)
1459                 {
1460                         GL_BindEBO(0);
1461                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1462                         {
1463                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
1464                                 CHECKGLERROR
1465                         }
1466                         else
1467                         {
1468                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
1469                                 CHECKGLERROR
1470                         }
1471                 }
1472                 else if (element3i)
1473                 {
1474                         GL_BindEBO(0);
1475                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1476                         {
1477                                 qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
1478                                 CHECKGLERROR
1479                         }
1480                         else
1481                         {
1482                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
1483                                 CHECKGLERROR
1484                         }
1485                 }
1486                 else
1487                 {
1488                         qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
1489                         CHECKGLERROR
1490                 }
1491         }
1492 }
1493
1494 // restores backend state, used when done with 3D rendering
1495 void R_Mesh_Finish(void)
1496 {
1497 }
1498
1499 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic)
1500 {
1501         int bufferobject = 0;
1502         void *devicebuffer = NULL;
1503         r_meshbuffer_t *buffer;
1504         if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex)))
1505                 return NULL;
1506         if (isindexbuffer)
1507         {
1508                 r_refdef.stats.indexbufferuploadcount++;
1509                 r_refdef.stats.indexbufferuploadsize += size;
1510         }
1511         else
1512         {
1513                 r_refdef.stats.vertexbufferuploadcount++;
1514                 r_refdef.stats.vertexbufferuploadsize += size;
1515         }
1516         switch(vid.renderpath)
1517         {
1518         case RENDERPATH_GL11:
1519         case RENDERPATH_GL13:
1520         case RENDERPATH_GL20:
1521         case RENDERPATH_CGGL:
1522                 qglGenBuffersARB(1, (GLuint *)&bufferobject);
1523                 if (isindexbuffer)
1524                         GL_BindEBO(bufferobject);
1525                 else
1526                         GL_BindVBO(bufferobject);
1527                 qglBufferDataARB(isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
1528                 break;
1529         }
1530         buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
1531         memset(buffer, 0, sizeof(*buffer));
1532         buffer->bufferobject = bufferobject;
1533         buffer->devicebuffer = devicebuffer;
1534         buffer->size = size;
1535         buffer->isindexbuffer = isindexbuffer;
1536         buffer->isdynamic = isdynamic;
1537         strlcpy(buffer->name, name, sizeof(buffer->name));
1538         return buffer;
1539 }
1540
1541 void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size)
1542 {
1543         if (!buffer || (!buffer->bufferobject && !buffer->devicebuffer))
1544                 return;
1545         if (buffer->isindexbuffer)
1546         {
1547                 r_refdef.stats.indexbufferuploadcount++;
1548                 r_refdef.stats.indexbufferuploadsize += size;
1549         }
1550         else
1551         {
1552                 r_refdef.stats.vertexbufferuploadcount++;
1553                 r_refdef.stats.vertexbufferuploadsize += size;
1554         }
1555         switch(vid.renderpath)
1556         {
1557         case RENDERPATH_GL11:
1558         case RENDERPATH_GL13:
1559         case RENDERPATH_GL20:
1560         case RENDERPATH_CGGL:
1561                 if (buffer->isindexbuffer)
1562                         GL_BindEBO(buffer->bufferobject);
1563                 else
1564                         GL_BindVBO(buffer->bufferobject);
1565                 qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
1566                 break;
1567         }
1568 }
1569
1570 void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
1571 {
1572         if (!buffer)
1573                 return;
1574         switch(vid.renderpath)
1575         {
1576         case RENDERPATH_GL11:
1577         case RENDERPATH_GL13:
1578         case RENDERPATH_GL20:
1579         case RENDERPATH_CGGL:
1580                 qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject);
1581                 break;
1582         }
1583         Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
1584 }
1585
1586 void GL_Mesh_ListVBOs(qboolean printeach)
1587 {
1588         int i, endindex;
1589         size_t ebocount = 0, ebomemory = 0;
1590         size_t vbocount = 0, vbomemory = 0;
1591         r_meshbuffer_t *buffer;
1592         endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
1593         for (i = 0;i < endindex;i++)
1594         {
1595                 buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
1596                 if (!buffer)
1597                         continue;
1598                 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)");}
1599                 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)");}
1600         }
1601         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);
1602 }
1603
1604
1605
1606 void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
1607 {
1608         int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
1609         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)
1610         {
1611                 gl_state.pointer_vertex_components = components;
1612                 gl_state.pointer_vertex_gltype = gltype;
1613                 gl_state.pointer_vertex_stride = stride;
1614                 gl_state.pointer_vertex_pointer = pointer;
1615                 gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
1616                 gl_state.pointer_vertex_offset = bufferoffset;
1617                 CHECKGLERROR
1618                 GL_BindVBO(bufferobject);
1619                 qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
1620         }
1621 }
1622
1623 void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
1624 {
1625         // note: vertexbuffer may be non-NULL even if pointer is NULL, so check
1626         // the pointer only.
1627         if (pointer)
1628         {
1629                 int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
1630                 // caller wants color array enabled
1631                 if (!gl_state.pointer_color_enabled)
1632                 {
1633                         gl_state.pointer_color_enabled = true;
1634                         CHECKGLERROR
1635                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1636                 }
1637                 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)
1638                 {
1639                         gl_state.pointer_color_components = components;
1640                         gl_state.pointer_color_gltype = gltype;
1641                         gl_state.pointer_color_stride = stride;
1642                         gl_state.pointer_color_pointer = pointer;
1643                         gl_state.pointer_color_vertexbuffer = vertexbuffer;
1644                         gl_state.pointer_color_offset = bufferoffset;
1645                         CHECKGLERROR
1646                         GL_BindVBO(bufferobject);
1647                         qglColorPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
1648                 }
1649         }
1650         else
1651         {
1652                 // caller wants color array disabled
1653                 if (gl_state.pointer_color_enabled)
1654                 {
1655                         gl_state.pointer_color_enabled = false;
1656                         CHECKGLERROR
1657                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1658                         // when color array is on the glColor gets trashed, set it again
1659                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1660                 }
1661         }
1662 }
1663
1664 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)
1665 {
1666         gltextureunit_t *unit = gl_state.units + unitnum;
1667         // update array settings
1668         CHECKGLERROR
1669         // note: there is no need to check bufferobject here because all cases
1670         // that involve a valid bufferobject also supply a texcoord array
1671         if (pointer)
1672         {
1673                 int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
1674                 // texture array unit is enabled, enable the array
1675                 if (!unit->arrayenabled)
1676                 {
1677                         unit->arrayenabled = true;
1678                         GL_ClientActiveTexture(unitnum);
1679                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1680                 }
1681                 // texcoord array
1682                 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)
1683                 {
1684                         unit->pointer_texcoord_components = components;
1685                         unit->pointer_texcoord_gltype = gltype;
1686                         unit->pointer_texcoord_stride = stride;
1687                         unit->pointer_texcoord_pointer = pointer;
1688                         unit->pointer_texcoord_vertexbuffer = vertexbuffer;
1689                         unit->pointer_texcoord_offset = bufferoffset;
1690                         GL_ClientActiveTexture(unitnum);
1691                         GL_BindVBO(bufferobject);
1692                         qglTexCoordPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
1693                 }
1694         }
1695         else
1696         {
1697                 // texture array unit is disabled, disable the array
1698                 if (unit->arrayenabled)
1699                 {
1700                         unit->arrayenabled = false;
1701                         GL_ClientActiveTexture(unitnum);
1702                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1703                 }
1704         }
1705 }
1706
1707 int R_Mesh_TexBound(unsigned int unitnum, int id)
1708 {
1709         gltextureunit_t *unit = gl_state.units + unitnum;
1710         if (unitnum >= vid.teximageunits)
1711                 return 0;
1712         if (id == GL_TEXTURE_2D)
1713                 return unit->t2d;
1714         if (id == GL_TEXTURE_3D)
1715                 return unit->t3d;
1716         if (id == GL_TEXTURE_CUBE_MAP_ARB)
1717                 return unit->tcubemap;
1718         if (id == GL_TEXTURE_RECTANGLE_ARB)
1719                 return unit->trectangle;
1720         return 0;
1721 }
1722
1723 void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int width, int height)
1724 {
1725         R_Mesh_TexBind(0, tex);
1726         GL_ActiveTexture(0);CHECKGLERROR
1727         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, sx, sy, width, height);CHECKGLERROR
1728 }
1729
1730 void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
1731 {
1732         gltextureunit_t *unit = gl_state.units + unitnum;
1733         int tex2d, tex3d, texcubemap, texnum;
1734         if (unitnum >= vid.teximageunits)
1735                 return;
1736         switch(vid.renderpath)
1737         {
1738         case RENDERPATH_GL20:
1739         case RENDERPATH_CGGL:
1740                 if (!tex)
1741                         tex = r_texture_white;
1742                 texnum = R_GetTexture(tex);
1743                 switch(tex->gltexturetypeenum)
1744                 {
1745                 case GL_TEXTURE_2D: if (unit->t2d != texnum) {GL_ActiveTexture(unitnum);unit->t2d = texnum;qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR}break;
1746                 case GL_TEXTURE_3D: if (unit->t3d != texnum) {GL_ActiveTexture(unitnum);unit->t3d = texnum;qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR}break;
1747                 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;
1748                 case GL_TEXTURE_RECTANGLE_ARB: if (unit->trectangle != texnum) {GL_ActiveTexture(unitnum);unit->trectangle = texnum;qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR}break;
1749                 }
1750                 break;
1751         case RENDERPATH_GL13:
1752         case RENDERPATH_GL11:
1753                 tex2d = 0;
1754                 tex3d = 0;
1755                 texcubemap = 0;
1756                 if (tex)
1757                 {
1758                         texnum = R_GetTexture(tex);
1759                         switch(tex->gltexturetypeenum)
1760                         {
1761                         case GL_TEXTURE_2D:
1762                                 tex2d = texnum;
1763                                 break;
1764                         case GL_TEXTURE_3D:
1765                                 tex3d = texnum;
1766                                 break;
1767                         case GL_TEXTURE_CUBE_MAP_ARB:
1768                                 texcubemap = texnum;
1769                                 break;
1770                         }
1771                 }
1772                 // update 2d texture binding
1773                 if (unit->t2d != tex2d)
1774                 {
1775                         GL_ActiveTexture(unitnum);
1776                         if (tex2d)
1777                         {
1778                                 if (unit->t2d == 0)
1779                                 {
1780                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1781                                 }
1782                         }
1783                         else
1784                         {
1785                                 if (unit->t2d)
1786                                 {
1787                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1788                                 }
1789                         }
1790                         unit->t2d = tex2d;
1791                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1792                 }
1793                 // update 3d texture binding
1794                 if (unit->t3d != tex3d)
1795                 {
1796                         GL_ActiveTexture(unitnum);
1797                         if (tex3d)
1798                         {
1799                                 if (unit->t3d == 0)
1800                                 {
1801                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1802                                 }
1803                         }
1804                         else
1805                         {
1806                                 if (unit->t3d)
1807                                 {
1808                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1809                                 }
1810                         }
1811                         unit->t3d = tex3d;
1812                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1813                 }
1814                 // update cubemap texture binding
1815                 if (unit->tcubemap != texcubemap)
1816                 {
1817                         GL_ActiveTexture(unitnum);
1818                         if (texcubemap)
1819                         {
1820                                 if (unit->tcubemap == 0)
1821                                 {
1822                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1823                                 }
1824                         }
1825                         else
1826                         {
1827                                 if (unit->tcubemap)
1828                                 {
1829                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1830                                 }
1831                         }
1832                         unit->tcubemap = texcubemap;
1833                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1834                 }
1835                 break;
1836         }
1837 }
1838
1839 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1840 {
1841         gltextureunit_t *unit = gl_state.units + unitnum;
1842         if (matrix && matrix->m[3][3])
1843         {
1844                 // texmatrix specified, check if it is different
1845                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1846                 {
1847                         float glmatrix[16];
1848                         unit->texmatrixenabled = true;
1849                         unit->matrix = *matrix;
1850                         CHECKGLERROR
1851                         Matrix4x4_ToArrayFloatGL(&unit->matrix, glmatrix);
1852                         GL_ActiveTexture(unitnum);
1853                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1854                         qglLoadMatrixf(glmatrix);CHECKGLERROR
1855                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1856                 }
1857         }
1858         else
1859         {
1860                 // no texmatrix specified, revert to identity
1861                 if (unit->texmatrixenabled)
1862                 {
1863                         unit->texmatrixenabled = false;
1864                         unit->matrix = identitymatrix;
1865                         CHECKGLERROR
1866                         GL_ActiveTexture(unitnum);
1867                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1868                         qglLoadIdentity();CHECKGLERROR
1869                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1870                 }
1871         }
1872 }
1873
1874 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1875 {
1876         gltextureunit_t *unit = gl_state.units + unitnum;
1877         CHECKGLERROR
1878         switch(vid.renderpath)
1879         {
1880         case RENDERPATH_GL20:
1881         case RENDERPATH_CGGL:
1882                 // do nothing
1883                 break;
1884         case RENDERPATH_GL13:
1885                 // GL_ARB_texture_env_combine
1886                 if (!combinergb)
1887                         combinergb = GL_MODULATE;
1888                 if (!combinealpha)
1889                         combinealpha = GL_MODULATE;
1890                 if (!rgbscale)
1891                         rgbscale = 1;
1892                 if (!alphascale)
1893                         alphascale = 1;
1894                 if (combinergb != combinealpha || rgbscale != 1 || alphascale != 1)
1895                 {
1896                         if (combinergb == GL_DECAL)
1897                                 combinergb = GL_INTERPOLATE_ARB;
1898                         if (unit->combine != GL_COMBINE_ARB)
1899                         {
1900                                 unit->combine = GL_COMBINE_ARB;
1901                                 GL_ActiveTexture(unitnum);
1902                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
1903                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
1904                         }
1905                         if (unit->combinergb != combinergb)
1906                         {
1907                                 unit->combinergb = combinergb;
1908                                 GL_ActiveTexture(unitnum);
1909                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1910                         }
1911                         if (unit->combinealpha != combinealpha)
1912                         {
1913                                 unit->combinealpha = combinealpha;
1914                                 GL_ActiveTexture(unitnum);
1915                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1916                         }
1917                         if (unit->rgbscale != rgbscale)
1918                         {
1919                                 unit->rgbscale = rgbscale;
1920                                 GL_ActiveTexture(unitnum);
1921                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, unit->rgbscale);CHECKGLERROR
1922                         }
1923                         if (unit->alphascale != alphascale)
1924                         {
1925                                 unit->alphascale = alphascale;
1926                                 GL_ActiveTexture(unitnum);
1927                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, unit->alphascale);CHECKGLERROR
1928                         }
1929                 }
1930                 else
1931                 {
1932                         if (unit->combine != combinergb)
1933                         {
1934                                 unit->combine = combinergb;
1935                                 GL_ActiveTexture(unitnum);
1936                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
1937                         }
1938                 }
1939                 break;
1940         case RENDERPATH_GL11:
1941                 // normal GL texenv
1942                 if (!combinergb)
1943                         combinergb = GL_MODULATE;
1944                 if (unit->combine != combinergb)
1945                 {
1946                         unit->combine = combinergb;
1947                         GL_ActiveTexture(unitnum);
1948                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
1949                 }
1950                 break;
1951         }
1952 }
1953
1954 void R_Mesh_ResetTextureState(void)
1955 {
1956         unsigned int unitnum;
1957
1958         BACKENDACTIVECHECK
1959
1960         CHECKGLERROR
1961         switch(vid.renderpath)
1962         {
1963         case RENDERPATH_GL20:
1964         case RENDERPATH_CGGL:
1965                 for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
1966                 {
1967                         gltextureunit_t *unit = gl_state.units + unitnum;
1968                         if (unit->t2d)
1969                         {
1970                                 unit->t2d = 0;
1971                                 GL_ActiveTexture(unitnum);
1972                                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1973                         }
1974                         if (unit->t3d)
1975                         {
1976                                 unit->t3d = 0;
1977                                 GL_ActiveTexture(unitnum);
1978                                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1979                         }
1980                         if (unit->tcubemap)
1981                         {
1982                                 unit->tcubemap = 0;
1983                                 GL_ActiveTexture(unitnum);
1984                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1985                         }
1986                         if (unit->trectangle)
1987                         {
1988                                 unit->trectangle = 0;
1989                                 GL_ActiveTexture(unitnum);
1990                                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
1991                         }
1992                 }
1993                 for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++)
1994                 {
1995                         gltextureunit_t *unit = gl_state.units + unitnum;
1996                         if (unit->arrayenabled)
1997                         {
1998                                 unit->arrayenabled = false;
1999                                 GL_ClientActiveTexture(unitnum);
2000                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
2001                         }
2002                 }
2003                 for (unitnum = 0;unitnum < vid.texunits;unitnum++)
2004                 {
2005                         gltextureunit_t *unit = gl_state.units + unitnum;
2006                         if (unit->texmatrixenabled)
2007                         {
2008                                 unit->texmatrixenabled = false;
2009                                 unit->matrix = identitymatrix;
2010                                 CHECKGLERROR
2011                                 GL_ActiveTexture(unitnum);
2012                                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2013                                 qglLoadIdentity();CHECKGLERROR
2014                                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2015                         }
2016                 }
2017                 break;
2018         case RENDERPATH_GL13:
2019         case RENDERPATH_GL11:
2020                 for (unitnum = 0;unitnum < vid.texunits;unitnum++)
2021                 {
2022                         gltextureunit_t *unit = gl_state.units + unitnum;
2023                         if (unit->t2d)
2024                         {
2025                                 unit->t2d = 0;
2026                                 GL_ActiveTexture(unitnum);
2027                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
2028                                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
2029                         }
2030                         if (unit->t3d)
2031                         {
2032                                 unit->t3d = 0;
2033                                 GL_ActiveTexture(unitnum);
2034                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
2035                                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
2036                         }
2037                         if (unit->tcubemap)
2038                         {
2039                                 unit->tcubemap = 0;
2040                                 GL_ActiveTexture(unitnum);
2041                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
2042                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
2043                         }
2044                         if (unit->trectangle)
2045                         {
2046                                 unit->trectangle = 0;
2047                                 GL_ActiveTexture(unitnum);
2048                                 qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
2049                                 qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
2050                         }
2051                         if (unit->arrayenabled)
2052                         {
2053                                 unit->arrayenabled = false;
2054                                 GL_ClientActiveTexture(unitnum);
2055                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
2056                         }
2057                         if (unit->texmatrixenabled)
2058                         {
2059                                 unit->texmatrixenabled = false;
2060                                 unit->matrix = identitymatrix;
2061                                 CHECKGLERROR
2062                                 GL_ActiveTexture(unitnum);
2063                                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
2064                                 qglLoadIdentity();CHECKGLERROR
2065                                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
2066                         }
2067                         if (unit->combine != GL_MODULATE)
2068                         {
2069                                 unit->combine = GL_MODULATE;
2070                                 GL_ActiveTexture(unitnum);
2071                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
2072                         }
2073                 }
2074                 break;
2075         }
2076 }
2077
2078
2079
2080 r_vertexposition_t *R_Mesh_PrepareVertices_Position_Lock(int numvertices)
2081 {
2082         size_t size;
2083         size = sizeof(r_vertexposition_t) * numvertices;
2084         if (gl_state.preparevertices_tempdatamaxsize < size)
2085         {
2086                 gl_state.preparevertices_tempdatamaxsize = size;
2087                 gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
2088         }
2089         gl_state.preparevertices_vertexposition = (r_vertexposition_t *)gl_state.preparevertices_tempdata;
2090         gl_state.preparevertices_numvertices = numvertices;
2091         return gl_state.preparevertices_vertexposition;
2092 }
2093
2094 qboolean R_Mesh_PrepareVertices_Position_Unlock(void)
2095 {
2096         R_Mesh_PrepareVertices_Position(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexposition, NULL);
2097         gl_state.preparevertices_vertexposition = NULL;
2098         gl_state.preparevertices_numvertices = 0;
2099         return true;
2100 }
2101
2102 void R_Mesh_PrepareVertices_Position_Arrays(int numvertices, const float *vertex3f)
2103 {
2104         int i;
2105         r_vertexposition_t *vertex;
2106         switch(vid.renderpath)
2107         {
2108         case RENDERPATH_GL20:
2109         case RENDERPATH_CGGL:
2110                 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
2111                 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
2112                 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2113                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2114                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2115                 R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2116                 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2117                 break;
2118         case RENDERPATH_GL13:
2119         case RENDERPATH_GL11:
2120                 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
2121                 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
2122                 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2123                 if (vid.texunits >= 2)
2124                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2125                 if (vid.texunits >= 3)
2126                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2127                 break;
2128         }
2129
2130         // no quick path for this case, convert to vertex structs
2131         vertex = R_Mesh_PrepareVertices_Position_Lock(numvertices);
2132         for (i = 0;i < numvertices;i++)
2133                 VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
2134         R_Mesh_PrepareVertices_Position_Unlock();
2135         R_Mesh_PrepareVertices_Position(numvertices, vertex, NULL);
2136 }
2137
2138 void R_Mesh_PrepareVertices_Position(int numvertices, const r_vertexposition_t *vertex, const r_meshbuffer_t *vertexbuffer)
2139 {
2140         // upload temporary vertexbuffer for this rendering
2141         if (!gl_state.usevbo_staticvertex)
2142                 vertexbuffer = NULL;
2143         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
2144         {
2145                 if (gl_state.preparevertices_dynamicvertexbuffer)
2146                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
2147                 else
2148                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true);
2149                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
2150         }
2151         if (vertexbuffer)
2152         {
2153                 switch(vid.renderpath)
2154                 {
2155                 case RENDERPATH_GL20:
2156                 case RENDERPATH_CGGL:
2157                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2158                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2159                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2160                 case RENDERPATH_GL13:
2161                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2162                 case RENDERPATH_GL11:
2163                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
2164                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
2165                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2166                         break;
2167                 }
2168                 return;
2169         }
2170         switch(vid.renderpath)
2171         {
2172         case RENDERPATH_GL20:
2173         case RENDERPATH_CGGL:
2174                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2175                 R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2176                 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2177         case RENDERPATH_GL13:
2178                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2179         case RENDERPATH_GL11:
2180                 R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
2181                 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
2182                 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2183                 break;
2184         }
2185 }
2186
2187
2188
2189 r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices)
2190 {
2191         size_t size;
2192         size = sizeof(r_vertexgeneric_t) * numvertices;
2193         if (gl_state.preparevertices_tempdatamaxsize < size)
2194         {
2195                 gl_state.preparevertices_tempdatamaxsize = size;
2196                 gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
2197         }
2198         gl_state.preparevertices_vertexgeneric = (r_vertexgeneric_t *)gl_state.preparevertices_tempdata;
2199         gl_state.preparevertices_numvertices = numvertices;
2200         return gl_state.preparevertices_vertexgeneric;
2201 }
2202
2203 qboolean R_Mesh_PrepareVertices_Generic_Unlock(void)
2204 {
2205         R_Mesh_PrepareVertices_Generic(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexgeneric, NULL);
2206         gl_state.preparevertices_vertexgeneric = NULL;
2207         gl_state.preparevertices_numvertices = 0;
2208         return true;
2209 }
2210
2211 void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f)
2212 {
2213         int i;
2214         r_vertexgeneric_t *vertex;
2215         switch(vid.renderpath)
2216         {
2217         case RENDERPATH_GL20:
2218         case RENDERPATH_CGGL:
2219                 if (gl_mesh_separatearrays.integer)
2220                 {
2221                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
2222                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
2223                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
2224                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2225                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2226                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2227                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2228                         return;
2229                 }
2230                 break;
2231         case RENDERPATH_GL13:
2232         case RENDERPATH_GL11:
2233                 if (gl_mesh_separatearrays.integer)
2234                 {
2235                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
2236                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
2237                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
2238                         if (vid.texunits >= 2)
2239                                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2240                         if (vid.texunits >= 3)
2241                                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2242                         return;
2243                 }
2244                 break;
2245         }
2246
2247         // no quick path for this case, convert to vertex structs
2248         vertex = R_Mesh_PrepareVertices_Generic_Lock(numvertices);
2249         for (i = 0;i < numvertices;i++)
2250                 VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
2251         if (color4f)
2252         {
2253                 for (i = 0;i < numvertices;i++)
2254                         Vector4Scale(color4f + 4*i, 255.0f, vertex[i].color4ub);
2255         }
2256         else
2257         {
2258                 float tempcolor4f[4];
2259                 unsigned char tempcolor4ub[4];
2260                 Vector4Scale(gl_state.color4f, 255.0f, tempcolor4f);
2261                 tempcolor4ub[0] = (unsigned char)bound(0.0f, tempcolor4f[0], 255.0f);
2262                 tempcolor4ub[1] = (unsigned char)bound(0.0f, tempcolor4f[1], 255.0f);
2263                 tempcolor4ub[2] = (unsigned char)bound(0.0f, tempcolor4f[2], 255.0f);
2264                 tempcolor4ub[3] = (unsigned char)bound(0.0f, tempcolor4f[3], 255.0f);
2265                 for (i = 0;i < numvertices;i++)
2266                         Vector4Copy(tempcolor4ub, vertex[i].color4ub);
2267         }
2268         if (texcoord2f)
2269                 for (i = 0;i < numvertices;i++)
2270                         Vector2Copy(texcoord2f + 2*i, vertex[i].texcoord2f);
2271         R_Mesh_PrepareVertices_Generic_Unlock();
2272         R_Mesh_PrepareVertices_Generic(numvertices, vertex, NULL);
2273 }
2274
2275 void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer)
2276 {
2277         // upload temporary vertexbuffer for this rendering
2278         if (!gl_state.usevbo_staticvertex)
2279                 vertexbuffer = NULL;
2280         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
2281         {
2282                 if (gl_state.preparevertices_dynamicvertexbuffer)
2283                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
2284                 else
2285                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true);
2286                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
2287         }
2288         if (vertexbuffer)
2289         {
2290                 switch(vid.renderpath)
2291                 {
2292                 case RENDERPATH_GL20:
2293                 case RENDERPATH_CGGL:
2294                         R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2295                         R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2296                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2297                 case RENDERPATH_GL13:
2298                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2299                 case RENDERPATH_GL11:
2300                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
2301                         R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
2302                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
2303                         break;
2304                 }
2305                 return;
2306         }
2307         switch(vid.renderpath)
2308         {
2309         case RENDERPATH_GL20:
2310         case RENDERPATH_CGGL:
2311                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2312                 R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2313                 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2314         case RENDERPATH_GL13:
2315                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2316         case RENDERPATH_GL11:
2317                 R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
2318                 R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
2319                 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
2320                 break;
2321         }
2322 }
2323
2324
2325
2326 r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices)
2327 {
2328         size_t size;
2329         size = sizeof(r_vertexmesh_t) * numvertices;
2330         if (gl_state.preparevertices_tempdatamaxsize < size)
2331         {
2332                 gl_state.preparevertices_tempdatamaxsize = size;
2333                 gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
2334         }
2335         gl_state.preparevertices_vertexmesh = (r_vertexmesh_t *)gl_state.preparevertices_tempdata;
2336         gl_state.preparevertices_numvertices = numvertices;
2337         return gl_state.preparevertices_vertexmesh;
2338 }
2339
2340 qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void)
2341 {
2342         R_Mesh_PrepareVertices_Mesh(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexmesh, NULL);
2343         gl_state.preparevertices_vertexmesh = NULL;
2344         gl_state.preparevertices_numvertices = 0;
2345         return true;
2346 }
2347
2348 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)
2349 {
2350         int i;
2351         r_vertexmesh_t *vertex;
2352         switch(vid.renderpath)
2353         {
2354         case RENDERPATH_GL20:
2355         case RENDERPATH_CGGL:
2356                 if (gl_mesh_separatearrays.integer)
2357                 {
2358                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
2359                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
2360                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
2361                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), svector3f, NULL, 0);
2362                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), tvector3f, NULL, 0);
2363                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), normal3f, NULL, 0);
2364                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
2365                         return;
2366                 }
2367                 break;
2368         case RENDERPATH_GL13:
2369         case RENDERPATH_GL11:
2370                 if (gl_mesh_separatearrays.integer)
2371                 {
2372                         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
2373                         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
2374                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
2375                         if (vid.texunits >= 2)
2376                                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
2377                         if (vid.texunits >= 3)
2378                                 R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
2379                         return;
2380                 }
2381                 break;
2382         }
2383
2384         vertex = R_Mesh_PrepareVertices_Mesh_Lock(numvertices);
2385         for (i = 0;i < numvertices;i++)
2386                 VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
2387         if (svector3f)
2388                 for (i = 0;i < numvertices;i++)
2389                         VectorCopy(svector3f + 3*i, vertex[i].svector3f);
2390         if (tvector3f)
2391                 for (i = 0;i < numvertices;i++)
2392                         VectorCopy(tvector3f + 3*i, vertex[i].tvector3f);
2393         if (normal3f)
2394                 for (i = 0;i < numvertices;i++)
2395                         VectorCopy(normal3f + 3*i, vertex[i].normal3f);
2396         if (color4f)
2397         {
2398                 for (i = 0;i < numvertices;i++)
2399                         Vector4Scale(color4f + 4*i, 255.0f, vertex[i].color4ub);
2400         }
2401         else
2402         {
2403                 float tempcolor4f[4];
2404                 unsigned char tempcolor4ub[4];
2405                 Vector4Scale(gl_state.color4f, 255.0f, tempcolor4f);
2406                 tempcolor4ub[0] = (unsigned char)bound(0.0f, tempcolor4f[0], 255.0f);
2407                 tempcolor4ub[1] = (unsigned char)bound(0.0f, tempcolor4f[1], 255.0f);
2408                 tempcolor4ub[2] = (unsigned char)bound(0.0f, tempcolor4f[2], 255.0f);
2409                 tempcolor4ub[3] = (unsigned char)bound(0.0f, tempcolor4f[3], 255.0f);
2410                 for (i = 0;i < numvertices;i++)
2411                         Vector4Copy(tempcolor4ub, vertex[i].color4ub);
2412         }
2413         if (texcoordtexture2f)
2414                 for (i = 0;i < numvertices;i++)
2415                         Vector2Copy(texcoordtexture2f + 2*i, vertex[i].texcoordtexture2f);
2416         if (texcoordlightmap2f)
2417                 for (i = 0;i < numvertices;i++)
2418                         Vector2Copy(texcoordlightmap2f + 2*i, vertex[i].texcoordlightmap2f);
2419         R_Mesh_PrepareVertices_Mesh_Unlock();
2420         R_Mesh_PrepareVertices_Mesh(numvertices, vertex, NULL);
2421 }
2422
2423 void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *vertexbuffer)
2424 {
2425         // upload temporary vertexbuffer for this rendering
2426         if (!gl_state.usevbo_staticvertex)
2427                 vertexbuffer = NULL;
2428         if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
2429         {
2430                 if (gl_state.preparevertices_dynamicvertexbuffer)
2431                         R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
2432                 else
2433                         gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true);
2434                 vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
2435         }
2436         if (vertexbuffer)
2437         {
2438                 switch(vid.renderpath)
2439                 {
2440                 case RENDERPATH_GL20:
2441                 case RENDERPATH_CGGL:
2442                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
2443                         R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
2444                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
2445                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , vertexbuffer, (int)((unsigned char *)vertex->svector3f          - (unsigned char *)vertex));
2446                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , vertexbuffer, (int)((unsigned char *)vertex->tvector3f          - (unsigned char *)vertex));
2447                         R_Mesh_TexCoordPointer(3, 4, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , vertexbuffer, (int)((unsigned char *)vertex->normal3f           - (unsigned char *)vertex));
2448                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
2449                         break;
2450                 case RENDERPATH_GL13:
2451                         R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
2452                 case RENDERPATH_GL11:
2453                         R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
2454                         R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
2455                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
2456                         break;
2457                 }
2458                 return;
2459         }
2460         switch(vid.renderpath)
2461         {
2462         case RENDERPATH_GL20:
2463         case RENDERPATH_CGGL:
2464                 R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
2465                 R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
2466                 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
2467                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , NULL, 0);
2468                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , NULL, 0);
2469                 R_Mesh_TexCoordPointer(3, 4, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , NULL, 0);
2470                 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
2471                 break;
2472         case RENDERPATH_GL13:
2473                 R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
2474         case RENDERPATH_GL11:
2475                 R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
2476                 R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
2477                 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
2478                 break;
2479         }
2480 }