added gl_mesh_batching (default on) which merges several meshes in a row to reduce...
[xonotic/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5
6 //#define MESH_VAR
7 #define MESH_BATCH
8
9 // 65536 is the max addressable on a Geforce 256 up until Geforce3
10 // (excluding MX), seems a reasonable number...
11 cvar_t gl_mesh_maxverts = {0, "gl_mesh_maxverts", "65536"};
12 cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
13 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1"};
14 #ifdef MESH_VAR
15 cvar_t gl_mesh_vertex_array_range = {0, "gl_mesh_vertex_array_range", "0"};
16 cvar_t gl_mesh_vertex_array_range_readfrequency = {0, "gl_mesh_vertex_array_range_readfrequency", "0.2"};
17 cvar_t gl_mesh_vertex_array_range_writefrequency = {0, "gl_mesh_vertex_array_range_writefrequency", "0.2"};
18 cvar_t gl_mesh_vertex_array_range_priority = {0, "gl_mesh_vertex_array_range_priority", "0.7"};
19 #endif
20 #ifdef MESH_BATCH
21 cvar_t gl_mesh_batching = {0, "gl_mesh_batching", "1"};
22 #endif
23 cvar_t gl_mesh_copyarrays = {0, "gl_mesh_copyarrays", "1"};
24 cvar_t gl_delayfinish = {CVAR_SAVE, "gl_delayfinish", "0"};
25
26 cvar_t r_render = {0, "r_render", "1"};
27 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
28 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
29
30 int gl_maxdrawrangeelementsvertices;
31 int gl_maxdrawrangeelementsindices;
32
33 #ifdef DEBUGGL
34 int errornumber = 0;
35
36 void GL_PrintError(int errornumber, char *filename, int linenumber)
37 {
38         switch(errornumber)
39         {
40 #ifdef GL_INVALID_ENUM
41         case GL_INVALID_ENUM:
42                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
43                 break;
44 #endif
45 #ifdef GL_INVALID_VALUE
46         case GL_INVALID_VALUE:
47                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
48                 break;
49 #endif
50 #ifdef GL_INVALID_OPERATION
51         case GL_INVALID_OPERATION:
52                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
53                 break;
54 #endif
55 #ifdef GL_STACK_OVERFLOW
56         case GL_STACK_OVERFLOW:
57                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
58                 break;
59 #endif
60 #ifdef GL_STACK_UNDERFLOW
61         case GL_STACK_UNDERFLOW:
62                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
63                 break;
64 #endif
65 #ifdef GL_OUT_OF_MEMORY
66         case GL_OUT_OF_MEMORY:
67                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
68                 break;
69 #endif
70 #ifdef GL_TABLE_TOO_LARGE
71         case GL_TABLE_TOO_LARGE:
72                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
73                 break;
74 #endif
75         default:
76                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
77                 break;
78         }
79 }
80 #endif
81
82 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active\n");
83
84 int c_meshs, c_meshelements;
85
86 void SCR_ScreenShot_f (void);
87
88 // these are externally accessible
89 int r_lightmapscalebit;
90 float r_colorscale;
91 GLfloat *varray_vertex3f, *varray_buf_vertex3f;
92 GLfloat *varray_color4f, *varray_buf_color4f;
93 GLfloat *varray_texcoord3f[MAX_TEXTUREUNITS], *varray_buf_texcoord3f[MAX_TEXTUREUNITS];
94 GLfloat *varray_texcoord2f[MAX_TEXTUREUNITS], *varray_buf_texcoord2f[MAX_TEXTUREUNITS];
95 static qbyte *varray_buf_color4b;
96 int mesh_maxverts;
97 #ifdef MESH_VAR
98 int mesh_var;
99 float mesh_var_readfrequency;
100 float mesh_var_writefrequency;
101 float mesh_var_priority;
102 #endif
103 int varray_offset = 0, varray_offsetnext = 0;
104 GLuint *varray_buf_elements3i;
105 int mesh_maxelements = 32768;
106 #ifdef MESH_BATCH
107 int gl_batchvertexfirst = 0;
108 int gl_batchvertexcount = 0;
109 int gl_batchelementcount = 0;
110 #endif
111
112 static matrix4x4_t backend_viewmatrix;
113 static matrix4x4_t backend_modelmatrix;
114 static matrix4x4_t backend_modelviewmatrix;
115 static matrix4x4_t backend_glmodelviewmatrix;
116 static matrix4x4_t backend_projectmatrix;
117
118 static int backendunits, backendactive;
119 static mempool_t *gl_backend_mempool;
120
121 /*
122 note: here's strip order for a terrain row:
123 0--1--2--3--4
124 |\ |\ |\ |\ |
125 | \| \| \| \|
126 A--B--C--D--E
127
128 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
129
130 *elements++ = i + row;
131 *elements++ = i;
132 *elements++ = i + row + 1;
133 *elements++ = i;
134 *elements++ = i + 1;
135 *elements++ = i + row + 1;
136 */
137
138 void GL_Backend_AllocElementsArray(void)
139 {
140         if (varray_buf_elements3i)
141                 Mem_Free(varray_buf_elements3i);
142         varray_buf_elements3i = Mem_Alloc(gl_backend_mempool, mesh_maxelements * sizeof(GLuint));
143 }
144
145 void GL_Backend_FreeElementArray(void)
146 {
147         if (varray_buf_elements3i)
148                 Mem_Free(varray_buf_elements3i);
149         varray_buf_elements3i = NULL;
150 }
151
152 void GL_Backend_CheckCvars(void)
153 {
154         if (gl_mesh_maxverts.integer < 1024)
155                 Cvar_SetValueQuick(&gl_mesh_maxverts, 1024);
156         if (gl_mesh_maxverts.integer > 65536)
157                 Cvar_SetValueQuick(&gl_mesh_maxverts, 65536);
158 #ifdef MESH_VAR
159         if (gl_mesh_vertex_array_range.integer && !gl_support_var)
160                 Cvar_SetValueQuick(&gl_mesh_vertex_array_range, 0);
161         if (gl_mesh_vertex_array_range_readfrequency.value < 0)
162                 Cvar_SetValueQuick(&gl_mesh_vertex_array_range_readfrequency, 0);
163         if (gl_mesh_vertex_array_range_readfrequency.value > 1)
164                 Cvar_SetValueQuick(&gl_mesh_vertex_array_range_readfrequency, 1);
165         if (gl_mesh_vertex_array_range_writefrequency.value < 0)
166                 Cvar_SetValueQuick(&gl_mesh_vertex_array_range_writefrequency, 0);
167         if (gl_mesh_vertex_array_range_writefrequency.value > 1)
168                 Cvar_SetValueQuick(&gl_mesh_vertex_array_range_writefrequency, 1);
169         if (gl_mesh_vertex_array_range_priority.value < 0)
170                 Cvar_SetValueQuick(&gl_mesh_vertex_array_range_priority, 0);
171         if (gl_mesh_vertex_array_range_priority.value > 1)
172                 Cvar_SetValueQuick(&gl_mesh_vertex_array_range_priority, 1);
173 #endif
174 }
175
176 int polygonelements[768];
177
178 void GL_Backend_AllocArrays(void)
179 {
180         int i, size;
181         qbyte *data;
182
183         if (!gl_backend_mempool)
184         {
185                 gl_backend_mempool = Mem_AllocPool("GL_Backend");
186                 varray_buf_vertex3f = NULL;
187                 varray_buf_color4f = NULL;
188                 varray_buf_color4b = NULL;
189                 varray_buf_elements3i = NULL;
190                 for (i = 0;i < MAX_TEXTUREUNITS;i++)
191                         varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
192         }
193
194         if (varray_buf_vertex3f)
195 #ifdef MESH_VAR
196                 VID_FreeVertexArrays(varray_buf_vertex3f);
197 #else
198                 Mem_Free(varray_buf_vertex3f);
199 #endif
200         varray_buf_vertex3f = NULL;
201         varray_buf_color4f = NULL;
202         varray_buf_color4b = NULL;
203         for (i = 0;i < MAX_TEXTUREUNITS;i++)
204                 varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
205
206         mesh_maxverts = gl_mesh_maxverts.integer;
207         size = mesh_maxverts * (sizeof(float[3]) + sizeof(float[4]) + sizeof(qbyte[4]) + (sizeof(float[3]) + sizeof(float[2])) * backendunits);
208 #ifdef MESH_VAR
209         mesh_var = gl_mesh_vertex_array_range.integer && gl_support_var;
210         mesh_var_readfrequency = gl_mesh_vertex_array_range_readfrequency.value;
211         mesh_var_writefrequency = gl_mesh_vertex_array_range_writefrequency.value;
212         mesh_var_priority = gl_mesh_vertex_array_range_priority.value;
213         data = VID_AllocVertexArrays(gl_backend_mempool, size, gl_mesh_vertex_array_range.integer, gl_mesh_vertex_array_range_readfrequency.value, gl_mesh_vertex_array_range_writefrequency.value, gl_mesh_vertex_array_range_priority.value);
214 #else
215         data = Mem_Alloc(gl_backend_mempool, size);
216 #endif
217
218         varray_buf_vertex3f = (void *)data;data += sizeof(float[3]) * mesh_maxverts;
219         varray_buf_color4f = (void *)data;data += sizeof(float[4]) * mesh_maxverts;
220         for (i = 0;i < backendunits;i++)
221         {
222                 varray_buf_texcoord3f[i] = (void *)data;data += sizeof(float[3]) * mesh_maxverts;
223                 varray_buf_texcoord2f[i] = (void *)data;data += sizeof(float[2]) * mesh_maxverts;
224         }
225         for (;i < MAX_TEXTUREUNITS;i++)
226                 varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
227         varray_buf_color4b = (void *)data;data += sizeof(qbyte[4]) * mesh_maxverts;
228
229         GL_Backend_AllocElementsArray();
230
231 #ifdef MESH_VAR
232         if (mesh_var)
233         {
234                 CHECKGLERROR
235                 qglVertexArrayRangeNV(size, varray_buf_vertex3f);
236                 CHECKGLERROR
237         }
238 #endif
239 }
240
241 void GL_Backend_FreeArrays(void)
242 {
243         int i;
244
245 #ifdef MESH_VAR
246         if (mesh_var)
247         {
248                 CHECKGLERROR
249                 qglDisableClientState(GL_VERTEX_ARRAY_RANGE_NV);
250                 CHECKGLERROR
251         }
252 #endif
253
254         if (varray_buf_vertex3f)
255 #ifdef MESH_VAR
256                 VID_FreeVertexArrays(varray_buf_vertex3f);
257 #else
258                 Mem_Free(varray_buf_vertex3f);
259 #endif
260         varray_buf_vertex3f = NULL;
261         varray_buf_color4f = NULL;
262         varray_buf_color4b = NULL;
263         for (i = 0;i < MAX_TEXTUREUNITS;i++)
264                 varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
265         varray_buf_elements3i = NULL;
266
267         Mem_FreePool(&gl_backend_mempool);
268 }
269
270 static void gl_backend_start(void)
271 {
272         GL_Backend_CheckCvars();
273
274         Con_Printf("OpenGL Backend started with gl_mesh_maxverts %i\n", gl_mesh_maxverts.integer);
275         if (qglDrawRangeElements != NULL)
276         {
277                 CHECKGLERROR
278                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
279                 CHECKGLERROR
280                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
281                 CHECKGLERROR
282                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
283         }
284         if (strstr(gl_renderer, "3Dfx"))
285         {
286                 Con_Printf("3Dfx driver detected, forcing gl_mesh_floatcolors to 0 to prevent crashs\n");
287                 Cvar_SetValueQuick(&gl_mesh_floatcolors, 0);
288         }
289
290         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
291
292         GL_Backend_AllocArrays();
293
294 #ifdef MESH_VAR
295         if (mesh_var)
296         {
297                 CHECKGLERROR
298                 qglEnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
299                 CHECKGLERROR
300         }
301 #endif
302         varray_offset = varray_offsetnext = 0;
303 #ifdef MESH_BATCH
304         gl_batchvertexfirst = 0;
305         gl_batchvertexcount = 0;
306         gl_batchelementcount = 0;
307 #endif
308
309         backendactive = true;
310 }
311
312 static void gl_backend_shutdown(void)
313 {
314         backendunits = 0;
315         backendactive = false;
316
317         Con_Printf("OpenGL Backend shutting down\n");
318
319 #ifdef MESH_VAR
320         if (mesh_var)
321         {
322                 CHECKGLERROR
323                 qglDisableClientState(GL_VERTEX_ARRAY_RANGE_NV);
324                 CHECKGLERROR
325         }
326 #endif
327
328         GL_Backend_FreeArrays();
329 }
330
331 void GL_Backend_ResizeArrays(int numvertices)
332 {
333         Cvar_SetValueQuick(&gl_mesh_maxverts, numvertices);
334         GL_Backend_CheckCvars();
335         mesh_maxverts = gl_mesh_maxverts.integer;
336         GL_Backend_AllocArrays();
337 }
338
339 static void gl_backend_newmap(void)
340 {
341 }
342
343 void gl_backend_init(void)
344 {
345         int i;
346
347         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
348         {
349                 polygonelements[i * 3 + 0] = 0;
350                 polygonelements[i * 3 + 1] = i + 1;
351                 polygonelements[i * 3 + 2] = i + 2;
352         }
353
354         Cvar_RegisterVariable(&r_render);
355         Cvar_RegisterVariable(&gl_dither);
356         Cvar_RegisterVariable(&gl_lockarrays);
357         Cvar_RegisterVariable(&gl_delayfinish);
358 #ifdef NORENDER
359         Cvar_SetValue("r_render", 0);
360 #endif
361
362         Cvar_RegisterVariable(&gl_mesh_maxverts);
363         Cvar_RegisterVariable(&gl_mesh_floatcolors);
364         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
365 #ifdef MESH_VAR
366         Cvar_RegisterVariable(&gl_mesh_vertex_array_range);
367         Cvar_RegisterVariable(&gl_mesh_vertex_array_range_readfrequency);
368         Cvar_RegisterVariable(&gl_mesh_vertex_array_range_writefrequency);
369         Cvar_RegisterVariable(&gl_mesh_vertex_array_range_priority);
370 #endif
371 #ifdef MESH_BATCH
372         Cvar_RegisterVariable(&gl_mesh_batching);
373 #endif
374         Cvar_RegisterVariable(&gl_mesh_copyarrays);
375         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
376 }
377
378 void GL_SetupView_ViewPort (int x, int y, int width, int height)
379 {
380         if (!r_render.integer)
381                 return;
382
383         // y is weird beause OpenGL is bottom to top, we use top to bottom
384         qglViewport(x, vid.realheight - (y + height), width, height);
385         CHECKGLERROR
386 }
387
388 void GL_SetupView_Orientation_Identity (void)
389 {
390         Matrix4x4_CreateIdentity(&backend_viewmatrix);
391         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
392 }
393
394 void GL_SetupView_Orientation_FromEntity (vec3_t origin, vec3_t angles)
395 {
396         Matrix4x4_CreateRotate(&backend_viewmatrix, -90, 1, 0, 0);
397         Matrix4x4_ConcatRotate(&backend_viewmatrix, 90, 0, 0, 1);
398         Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
399         Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
400         Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
401         Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
402         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
403 }
404
405 void GL_SetupView_Mode_Perspective (double fovx, double fovy, double zNear, double zFar)
406 {
407         double xmax, ymax;
408
409         if (!r_render.integer)
410                 return;
411
412         // set up viewpoint
413         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
414         qglLoadIdentity();CHECKGLERROR
415         // pyramid slopes
416         xmax = zNear * tan(fovx * M_PI / 360.0);
417         ymax = zNear * tan(fovy * M_PI / 360.0);
418         // set view pyramid
419         qglFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
420         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
421         GL_SetupView_Orientation_Identity();
422 }
423
424 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double fovx, double fovy, double zNear)
425 {
426         float nudge, m[16];
427
428         if (!r_render.integer)
429                 return;
430
431         // set up viewpoint
432         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
433         qglLoadIdentity();CHECKGLERROR
434         // set view pyramid
435         nudge = 1.0 - 1.0 / (1<<23);
436         m[ 0] = 1.0 / tan(fovx * M_PI / 360.0);
437         m[ 1] = 0;
438         m[ 2] = 0;
439         m[ 3] = 0;
440         m[ 4] = 0;
441         m[ 5] = 1.0 / tan(fovy * M_PI / 360.0);
442         m[ 6] = 0;
443         m[ 7] = 0;
444         m[ 8] = 0;
445         m[ 9] = 0;
446         m[10] = -1 * nudge;
447         m[11] = -1 * nudge;
448         m[12] = 0;
449         m[13] = 0;
450         m[14] = -2 * zNear * nudge;
451         m[15] = 0;
452         qglLoadMatrixf(m);
453         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
454         GL_SetupView_Orientation_Identity();
455         backend_projectmatrix.m[0][0] = m[0];
456         backend_projectmatrix.m[1][0] = m[1];
457         backend_projectmatrix.m[2][0] = m[2];
458         backend_projectmatrix.m[3][0] = m[3];
459         backend_projectmatrix.m[0][1] = m[4];
460         backend_projectmatrix.m[1][1] = m[5];
461         backend_projectmatrix.m[2][1] = m[6];
462         backend_projectmatrix.m[3][1] = m[7];
463         backend_projectmatrix.m[0][2] = m[8];
464         backend_projectmatrix.m[1][2] = m[9];
465         backend_projectmatrix.m[2][2] = m[10];
466         backend_projectmatrix.m[3][2] = m[11];
467         backend_projectmatrix.m[0][3] = m[12];
468         backend_projectmatrix.m[1][3] = m[13];
469         backend_projectmatrix.m[2][3] = m[14];
470         backend_projectmatrix.m[3][3] = m[15];
471 }
472
473 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
474 {
475         if (!r_render.integer)
476                 return;
477
478         // set up viewpoint
479         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
480         qglLoadIdentity();CHECKGLERROR
481         qglOrtho(x1, x2, y2, y1, zNear, zFar);
482         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
483         GL_SetupView_Orientation_Identity();
484 }
485
486 typedef struct gltextureunit_s
487 {
488         int t1d, t2d, t3d, tcubemap;
489         int arrayenabled, arrayis3d;
490         void *pointer_texcoord;
491         float rgbscale, alphascale;
492         int combinergb, combinealpha;
493         // FIXME: add more combine stuff
494 }
495 gltextureunit_t;
496
497 static struct
498 {
499         int blendfunc1;
500         int blendfunc2;
501         int blend;
502         GLboolean depthmask;
503         int depthdisable;
504         int unit;
505         int clientunit;
506         gltextureunit_t units[MAX_TEXTUREUNITS];
507         int colorarray;
508         float color4f[4];
509         int lockrange_first;
510         int lockrange_count;
511         int pointervertexcount;
512         void *pointer_vertex;
513         void *pointer_color;
514 }
515 gl_state;
516
517 void GL_SetupTextureState(void)
518 {
519         int i;
520         gltextureunit_t *unit;
521         for (i = 0;i < backendunits;i++)
522         {
523                 if (qglActiveTexture)
524                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
525                 if (qglClientActiveTexture)
526                         qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
527                 unit = gl_state.units + i;
528                 unit->t1d = 0;
529                 unit->t2d = 0;
530                 unit->t3d = 0;
531                 unit->tcubemap = 0;
532                 unit->arrayenabled = false;
533                 unit->arrayis3d = false;
534                 unit->pointer_texcoord = NULL;
535                 unit->rgbscale = 1;
536                 unit->alphascale = 1;
537                 unit->combinergb = GL_MODULATE;
538                 unit->combinealpha = GL_MODULATE;
539                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
540                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), varray_buf_texcoord2f[i]);CHECKGLERROR
541                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
542                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
543                 if (gl_texture3d)
544                 {
545                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
546                 }
547                 if (gl_texturecubemap)
548                 {
549                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
550                 }
551                 if (gl_combine.integer)
552                 {
553                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
554                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
555                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
556                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
557                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);CHECKGLERROR
558                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
559                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
560                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
561                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
562                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
563                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
564                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
565                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
566                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
567                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
568                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
569                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
570                 }
571                 else
572                 {
573                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
574                 }
575         }
576 }
577
578 void GL_Backend_ResetState(void)
579 {
580         memset(&gl_state, 0, sizeof(gl_state));
581         gl_state.depthdisable = false;
582         gl_state.blendfunc1 = GL_ONE;
583         gl_state.blendfunc2 = GL_ZERO;
584         gl_state.blend = false;
585         gl_state.depthmask = GL_TRUE;
586         gl_state.colorarray = false;
587         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
588         gl_state.lockrange_first = 0;
589         gl_state.lockrange_count = 0;
590         gl_state.pointervertexcount = 0;
591         gl_state.pointer_vertex = NULL;
592         gl_state.pointer_color = NULL;
593
594         CHECKGLERROR
595         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
596         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
597
598         qglEnable(GL_CULL_FACE);CHECKGLERROR
599         qglCullFace(GL_FRONT);CHECKGLERROR
600         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
601         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
602         qglDisable(GL_BLEND);CHECKGLERROR
603         qglDepthMask(gl_state.depthmask);CHECKGLERROR
604         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), varray_buf_vertex3f);CHECKGLERROR
605         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
606         if (gl_mesh_floatcolors.integer)
607         {
608                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), varray_buf_color4f);CHECKGLERROR
609         }
610         else
611         {
612                 qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(qbyte[4]), varray_buf_color4b);CHECKGLERROR
613         }
614         GL_Color(0, 0, 0, 0);
615         GL_Color(1, 1, 1, 1);
616
617         GL_SetupTextureState();
618 }
619
620 void GL_UseColorArray(void)
621 {
622         if (!gl_state.colorarray)
623         {
624 #ifdef MESH_BATCH
625                 if (gl_batchelementcount)
626                         R_Mesh_EndBatch();
627 #endif
628                 gl_state.colorarray = true;
629                 qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
630         }
631 }
632
633 void GL_Color(float cr, float cg, float cb, float ca)
634 {
635         if (gl_state.colorarray)
636         {
637 #ifdef MESH_BATCH
638                 if (gl_batchelementcount)
639                         R_Mesh_EndBatch();
640 #endif
641                 gl_state.colorarray = false;
642                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
643                 gl_state.color4f[0] = cr;
644                 gl_state.color4f[1] = cg;
645                 gl_state.color4f[2] = cb;
646                 gl_state.color4f[3] = ca;
647                 qglColor4f(cr, cg, cb, ca);
648         }
649         else
650         {
651                 if (gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
652                 {
653 #ifdef MESH_BATCH
654                         if (gl_batchelementcount)
655                                 R_Mesh_EndBatch();
656 #endif
657                         gl_state.color4f[0] = cr;
658                         gl_state.color4f[1] = cg;
659                         gl_state.color4f[2] = cb;
660                         gl_state.color4f[3] = ca;
661                         qglColor4f(cr, cg, cb, ca);
662                 }
663         }
664 }
665
666 void GL_LockArrays(int first, int count)
667 {
668         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
669         {
670                 if (gl_state.lockrange_count)
671                 {
672                         gl_state.lockrange_count = 0;
673                         CHECKGLERROR
674                         qglUnlockArraysEXT();
675                         CHECKGLERROR
676                 }
677                 if (count && gl_supportslockarrays && gl_lockarrays.integer)
678                 {
679                         gl_state.lockrange_first = first;
680                         gl_state.lockrange_count = count;
681                         CHECKGLERROR
682                         qglLockArraysEXT(first, count);
683                         CHECKGLERROR
684                 }
685         }
686 }
687
688 void GL_TransformToScreen(const vec4_t in, vec4_t out)
689 {
690         vec4_t temp;
691         float iw;
692         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
693         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
694         iw = 1.0f / out[3];
695         out[0] = r_refdef.x + (out[0] * iw + 1.0f) * r_refdef.width * 0.5f;
696         out[1] = r_refdef.y + (out[1] * iw + 1.0f) * r_refdef.height * 0.5f;
697         out[2] = out[2] * iw;
698 }
699
700 // called at beginning of frame
701 void R_Mesh_Start(void)
702 {
703         BACKENDACTIVECHECK
704
705         CHECKGLERROR
706
707         GL_Backend_CheckCvars();
708         if (mesh_maxverts != gl_mesh_maxverts.integer
709 #ifdef MESH_VAR
710          || mesh_var != (gl_mesh_vertex_array_range.integer && gl_support_var)
711          || mesh_var_readfrequency != gl_mesh_vertex_array_range_readfrequency.value
712          || mesh_var_writefrequency != gl_mesh_vertex_array_range_writefrequency.value
713          || mesh_var_priority != gl_mesh_vertex_array_range_priority.value
714 #endif
715                 )
716                 GL_Backend_ResizeArrays(gl_mesh_maxverts.integer);
717
718         GL_Backend_ResetState();
719 #ifdef MESH_VAR
720         if (!mesh_var)
721         {
722                 gl_batchvertexfirst = gl_batchvertexcount = gl_batchelementcount = 0;
723                 varray_offset = varray_offsetnext = 0;
724         }
725 #else
726         varray_offset = varray_offsetnext = 0;
727 #endif
728 }
729
730 int gl_backend_rebindtextures;
731
732 void GL_ConvertColorsFloatToByte(int first, int count)
733 {
734         int i, k;
735         union {float f[4];int i[4];} *color4fi;
736         struct {GLubyte c[4];} *color4b;
737
738         // shift float to have 8bit fraction at base of number
739         color4fi = (void *)(varray_buf_color4f + first * 4);
740         for (i = 0;i < count;i++, color4fi++)
741         {
742                 color4fi->f[0] += 32768.0f;
743                 color4fi->f[1] += 32768.0f;
744                 color4fi->f[2] += 32768.0f;
745                 color4fi->f[3] += 32768.0f;
746         }
747
748         // then read as integer and kill float bits...
749         color4fi = (void *)(varray_buf_color4f + first * 4);
750         color4b = (void *)(varray_buf_color4b + first * 4);
751         for (i = 0;i < count;i++, color4fi++, color4b++)
752         {
753                 k = color4fi->i[0] & 0x7FFFFF;color4b->c[0] = (GLubyte) min(k, 255);
754                 k = color4fi->i[1] & 0x7FFFFF;color4b->c[1] = (GLubyte) min(k, 255);
755                 k = color4fi->i[2] & 0x7FFFFF;color4b->c[2] = (GLubyte) min(k, 255);
756                 k = color4fi->i[3] & 0x7FFFFF;color4b->c[3] = (GLubyte) min(k, 255);
757         }
758 }
759
760 /*
761 // enlarges geometry buffers if they are too small
762 void _R_Mesh_ResizeCheck(int numverts)
763 {
764         if (numverts > mesh_maxverts)
765         {
766                 BACKENDACTIVECHECK
767                 GL_Backend_ResizeArrays(numverts + 100);
768                 GL_Backend_ResetState();
769         }
770 }
771 */
772
773 void R_Mesh_EndBatch(void)
774 {
775 #ifdef MESH_BATCH
776         if (gl_batchelementcount)
777         {
778                 if (gl_state.pointervertexcount)
779                         Host_Error("R_Mesh_EndBatch: called with pointers enabled\n");
780
781                 if (gl_state.colorarray && !gl_mesh_floatcolors.integer && gl_state.pointer_color == NULL)
782                         GL_ConvertColorsFloatToByte(gl_batchvertexfirst, gl_batchvertexcount);
783                 if (r_render.integer)
784                 {
785                         //int i;for (i = 0;i < gl_batchelementcount;i++) if (varray_buf_elements3i[i] < gl_batchvertexfirst || varray_buf_elements3i[i] >= (gl_batchvertexfirst + gl_batchvertexcount)) Host_Error("R_Mesh_EndBatch: invalid element #%i (value %i) outside range %i-%i\n", i, varray_buf_elements3i[i], gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount);
786                         CHECKGLERROR
787                         GL_LockArrays(gl_batchvertexfirst, gl_batchvertexcount);
788                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
789                         {
790                                 qglDrawRangeElements(GL_TRIANGLES, gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount, gl_batchelementcount, GL_UNSIGNED_INT, (const GLuint *) varray_buf_elements3i);CHECKGLERROR
791                         }
792                         else
793                         {
794                                 qglDrawElements(GL_TRIANGLES, gl_batchelementcount, GL_UNSIGNED_INT, (const GLuint *) varray_buf_elements3i);CHECKGLERROR
795                         }
796                         GL_LockArrays(0, 0);
797                 }
798                 gl_batchelementcount = 0;
799                 gl_batchvertexcount = 0;
800         }
801 #endif
802 }
803
804 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
805 {
806         int i;
807         //if (offset)
808                 for (i = 0;i < count;i++)
809                         *out++ = *in++ + offset;
810         //else
811         //      memcpy(out, in, sizeof(*out) * count);
812 }
813
814 // gets vertex buffer space for use with a following R_Mesh_Draw
815 // (can be multiple Draw calls per GetSpace)
816 void R_Mesh_GetSpace(int numverts)
817 {
818         int i;
819
820         if (gl_state.pointervertexcount)
821                 Host_Error("R_Mesh_GetSpace: called with pointers enabled\n");
822         if (gl_state.lockrange_count)
823                 Host_Error("R_Mesh_GetSpace: called with arrays locked\n");
824
825         varray_offset = varray_offsetnext;
826         if (varray_offset + numverts > mesh_maxverts)
827         {
828                 //Con_Printf("R_Mesh_GetSpace: vertex buffer wrap\n");
829 #ifdef MESH_BATCH
830                 if (gl_batchelementcount)
831                         R_Mesh_EndBatch();
832 #endif
833                 varray_offset = 0;
834 #ifdef MESH_VAR
835                 if (mesh_var)
836                 {
837                         CHECKGLERROR
838                         qglFlushVertexArrayRangeNV();
839                         CHECKGLERROR
840                 }
841 #endif
842                 if (numverts > mesh_maxverts)
843                 {
844                         GL_Backend_ResizeArrays(numverts + 100);
845                         GL_Backend_ResetState();
846                 }
847         }
848
849 /*
850 #ifdef MESH_BATCH
851         if (gl_mesh_batching.integer)
852         {
853                 if (gl_batchvertexcount == 0)
854                         gl_batchvertexfirst = varray_offset;
855                 gl_batchvertexcount += numverts;
856         }
857 #endif
858 */
859         varray_vertex3f = varray_buf_vertex3f + varray_offset * 3;
860         varray_color4f = varray_buf_color4f + varray_offset * 4;
861         for (i = 0;i < backendunits;i++)
862         {
863                 varray_texcoord3f[i] = varray_buf_texcoord3f[i] + varray_offset * 3;
864                 varray_texcoord2f[i] = varray_buf_texcoord2f[i] + varray_offset * 2;
865         }
866
867         varray_offsetnext = varray_offset + numverts;
868 }
869
870 // renders triangles using vertices from the most recent GetSpace call
871 // (can be multiple Draw calls per GetSpace)
872 void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
873 {
874         int numelements = numtriangles * 3;
875         if (numtriangles == 0 || numverts == 0)
876         {
877                 Con_Printf("R_Mesh_Draw(%d, %d, %08p);\n", numverts, numtriangles, elements);
878                 return;
879         }
880         c_meshs++;
881         c_meshelements += numelements;
882         CHECKGLERROR
883         if (gl_state.pointervertexcount)
884         {
885 #ifdef MESH_BATCH
886                 if (gl_batchelementcount)
887                         R_Mesh_EndBatch();
888 #endif
889                 if (r_render.integer)
890                 {
891                         GL_LockArrays(0, gl_state.pointervertexcount);
892                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
893                         {
894                                 qglDrawRangeElements(GL_TRIANGLES, 0, gl_state.pointervertexcount, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
895                         }
896                         else
897                         {
898                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
899                         }
900                         GL_LockArrays(0, 0);
901                 }
902         }
903 #ifdef MESH_BATCH
904         else if (gl_mesh_batching.integer)
905         {
906                 if (mesh_maxelements < gl_batchelementcount + numelements)
907                 {
908                         //Con_Printf("R_Mesh_Draw: enlarging elements array\n");
909                         if (gl_batchelementcount)
910                                 R_Mesh_EndBatch();
911                         // round up to a multiple of 1024 and add another 1024 just for good measure
912                         mesh_maxelements = (gl_batchelementcount + numelements + 1024 + 1023) & ~1023;
913                         GL_Backend_AllocElementsArray();
914                 }
915                 if (varray_offset < gl_batchvertexfirst && gl_batchelementcount)
916                         R_Mesh_EndBatch();
917                 if (gl_batchelementcount == 0)
918                 {
919                         gl_batchvertexfirst = varray_offset;
920                         gl_batchvertexcount = 0;
921                 }
922                 if (gl_batchvertexcount < varray_offsetnext - gl_batchvertexfirst)
923                         gl_batchvertexcount = varray_offsetnext - gl_batchvertexfirst;
924                 GL_Backend_RenumberElements(varray_buf_elements3i + gl_batchelementcount, numelements, elements, varray_offset);
925                 //Con_Printf("off %i:%i, vertex %i:%i, element %i:%i\n", varray_offset, varray_offsetnext, gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount, gl_batchelementcount, gl_batchelementcount + numelements);
926                 gl_batchelementcount += numelements;
927                 //{int i;for (i = 0;i < gl_batchelementcount;i++) if (varray_buf_elements3i[i] < gl_batchvertexfirst || varray_buf_elements3i[i] >= (gl_batchvertexfirst + gl_batchvertexcount)) Host_Error("R_Mesh_EndBatch: invalid element #%i (value %i) outside range %i-%i, there were previously %i elements and there are now %i elements, varray_offset is %i\n", i, varray_buf_elements3i[i], gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount, gl_batchelementcount - numelements, gl_batchelementcount, varray_offset);}
928         }
929 #endif
930         else
931         {
932                 GL_Backend_RenumberElements(varray_buf_elements3i, numelements, elements, varray_offset);
933                 if (r_render.integer)
934                 {
935                         GL_LockArrays(varray_offset, numverts);
936                         if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
937                         {
938                                 qglDrawRangeElements(GL_TRIANGLES, varray_offset, varray_offset + numverts, numelements, GL_UNSIGNED_INT, varray_buf_elements3i);CHECKGLERROR
939                         }
940                         else
941                         {
942                                 qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, varray_buf_elements3i);CHECKGLERROR
943                         }
944                         GL_LockArrays(0, 0);
945                 }
946         }
947 }
948
949 // restores backend state, used when done with 3D rendering
950 void R_Mesh_Finish(void)
951 {
952         int i;
953         BACKENDACTIVECHECK
954 #ifdef MESH_BATCH
955         if (gl_batchelementcount)
956                 R_Mesh_EndBatch();
957 #endif
958         GL_LockArrays(0, 0);
959
960         for (i = backendunits - 1;i >= 0;i--)
961         {
962                 if (qglActiveTexture)
963                         qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
964                 if (qglClientActiveTexture)
965                         qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
966                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
967                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
968                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
969                 if (gl_texture3d)
970                 {
971                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
972                 }
973                 if (gl_texturecubemap)
974                 {
975                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
976                 }
977                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
978                 if (gl_combine.integer)
979                 {
980                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
981                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
982                 }
983         }
984         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
985         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
986
987         qglDisable(GL_BLEND);CHECKGLERROR
988         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
989         qglDepthMask(GL_TRUE);CHECKGLERROR
990         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
991 }
992
993 void R_Mesh_Matrix(const matrix4x4_t *matrix)
994 {
995         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
996         {
997 #ifdef MESH_BATCH
998                 if (gl_batchelementcount)
999                         R_Mesh_EndBatch();
1000 #endif
1001                 backend_modelmatrix = *matrix;
1002                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
1003                 Matrix4x4_Transpose(&backend_glmodelviewmatrix, &backend_modelviewmatrix);
1004                 qglLoadMatrixf(&backend_glmodelviewmatrix.m[0][0]);
1005         }
1006 }
1007
1008 // sets up the requested state
1009 void R_Mesh_MainState(const rmeshstate_t *m)
1010 {
1011         void *p;
1012         BACKENDACTIVECHECK
1013
1014         if (gl_state.blendfunc1 != m->blendfunc1 || gl_state.blendfunc2 != m->blendfunc2)
1015         {
1016 #ifdef MESH_BATCH
1017                 if (gl_batchelementcount)
1018                         R_Mesh_EndBatch();
1019 #endif
1020                 qglBlendFunc(gl_state.blendfunc1 = m->blendfunc1, gl_state.blendfunc2 = m->blendfunc2);CHECKGLERROR
1021                 if (gl_state.blendfunc2 == GL_ZERO)
1022                 {
1023                         if (gl_state.blendfunc1 == GL_ONE)
1024                         {
1025                                 if (gl_state.blend)
1026                                 {
1027                                         gl_state.blend = 0;
1028                                         qglDisable(GL_BLEND);CHECKGLERROR
1029                                 }
1030                         }
1031                         else
1032                         {
1033                                 if (!gl_state.blend)
1034                                 {
1035                                         gl_state.blend = 1;
1036                                         qglEnable(GL_BLEND);CHECKGLERROR
1037                                 }
1038                         }
1039                 }
1040                 else
1041                 {
1042                         if (!gl_state.blend)
1043                         {
1044                                 gl_state.blend = 1;
1045                                 qglEnable(GL_BLEND);CHECKGLERROR
1046                         }
1047                 }
1048         }
1049         if (gl_state.depthdisable != m->depthdisable)
1050         {
1051 #ifdef MESH_BATCH
1052                 if (gl_batchelementcount)
1053                         R_Mesh_EndBatch();
1054 #endif
1055                 gl_state.depthdisable = m->depthdisable;
1056                 if (gl_state.depthdisable)
1057                         qglDisable(GL_DEPTH_TEST);
1058                 else
1059                         qglEnable(GL_DEPTH_TEST);
1060         }
1061         if (gl_state.depthmask != (m->blendfunc2 == GL_ZERO || m->depthwrite))
1062         {
1063 #ifdef MESH_BATCH
1064                 if (gl_batchelementcount)
1065                         R_Mesh_EndBatch();
1066 #endif
1067                 qglDepthMask(gl_state.depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite));CHECKGLERROR
1068         }
1069
1070         if (gl_state.pointervertexcount != m->pointervertexcount)
1071         {
1072 #ifdef MESH_BATCH
1073                 if (gl_batchelementcount)
1074                         R_Mesh_EndBatch();
1075 #endif
1076                 gl_state.pointervertexcount = m->pointervertexcount;
1077         }
1078
1079         p = gl_state.pointervertexcount ? m->pointer_vertex : NULL;
1080         if (gl_state.pointer_vertex != p)
1081         {
1082 #ifdef MESH_BATCH
1083                 if (gl_batchelementcount)
1084                         R_Mesh_EndBatch();
1085 #endif
1086                 gl_state.pointer_vertex = p;
1087                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), p ? p : varray_buf_vertex3f);CHECKGLERROR
1088         }
1089
1090         if (gl_state.colorarray)
1091         {
1092                 p = gl_state.pointervertexcount ? m->pointer_color : NULL;
1093                 if (gl_state.pointer_color != p)
1094                 {
1095 #ifdef MESH_BATCH
1096                         if (gl_batchelementcount)
1097                                 R_Mesh_EndBatch();
1098 #endif
1099                         gl_state.pointer_color = p;
1100                         if (p != varray_buf_color4f || gl_mesh_floatcolors.integer)
1101                                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), p ? p : varray_buf_color4f);
1102                         else
1103                                 qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(GLubyte[4]), p ? p : varray_buf_color4b);
1104                         CHECKGLERROR
1105                 }
1106         }
1107 }
1108
1109 void R_Mesh_TextureState(const rmeshstate_t *m)
1110 {
1111         int i, combinergb, combinealpha;
1112         float scale;
1113         gltextureunit_t *unit;
1114         void *p;
1115
1116         BACKENDACTIVECHECK
1117
1118         if (gl_backend_rebindtextures)
1119         {
1120                 gl_backend_rebindtextures = false;
1121                 GL_SetupTextureState();
1122         }
1123
1124         for (i = 0;i < backendunits;i++)
1125         {
1126                 unit = gl_state.units + i;
1127                 if (unit->t1d != m->tex1d[i] || unit->t2d != m->tex[i] || unit->t3d != m->tex3d[i] || unit->tcubemap != m->texcubemap[i])
1128                 {
1129                         if (m->tex3d[i] || m->texcubemap[i])
1130                         {
1131                                 if (!unit->arrayis3d)
1132                                 {
1133 #ifdef MESH_BATCH
1134                                         if (gl_batchelementcount)
1135                                                 R_Mesh_EndBatch();
1136 #endif
1137                                         unit->arrayis3d = true;
1138                                         if (gl_state.clientunit != i)
1139                                         {
1140                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
1141                                         }
1142                                         qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), varray_buf_texcoord3f[i]);
1143                                 }
1144                                 if (!unit->arrayenabled)
1145                                 {
1146 #ifdef MESH_BATCH
1147                                         if (gl_batchelementcount)
1148                                                 R_Mesh_EndBatch();
1149 #endif
1150                                         unit->arrayenabled = true;
1151                                         if (gl_state.clientunit != i)
1152                                         {
1153                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
1154                                         }
1155                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1156                                 }
1157                         }
1158                         else if (m->tex1d[i] || m->tex[i])
1159                         {
1160                                 if (unit->arrayis3d)
1161                                 {
1162 #ifdef MESH_BATCH
1163                                         if (gl_batchelementcount)
1164                                                 R_Mesh_EndBatch();
1165 #endif
1166                                         unit->arrayis3d = false;
1167                                         if (gl_state.clientunit != i)
1168                                         {
1169                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
1170                                         }
1171                                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), varray_buf_texcoord2f[i]);
1172                                 }
1173                                 if (!unit->arrayenabled)
1174                                 {
1175 #ifdef MESH_BATCH
1176                                         if (gl_batchelementcount)
1177                                                 R_Mesh_EndBatch();
1178 #endif
1179                                         unit->arrayenabled = true;
1180                                         if (gl_state.clientunit != i)
1181                                         {
1182                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
1183                                         }
1184                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1185                                 }
1186                         }
1187                         else
1188                         {
1189                                 if (unit->arrayenabled)
1190                                 {
1191 #ifdef MESH_BATCH
1192                                         if (gl_batchelementcount)
1193                                                 R_Mesh_EndBatch();
1194 #endif
1195                                         unit->arrayenabled = false;
1196                                         if (gl_state.clientunit != i)
1197                                         {
1198                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
1199                                         }
1200                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1201                                 }
1202                         }
1203                         if (unit->t1d != m->tex1d[i])
1204                         {
1205 #ifdef MESH_BATCH
1206                                 if (gl_batchelementcount)
1207                                         R_Mesh_EndBatch();
1208 #endif
1209                                 if (gl_state.unit != i)
1210                                 {
1211                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1212                                 }
1213                                 if (m->tex1d[i])
1214                                 {
1215                                         if (unit->t1d == 0)
1216                                                 qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1217                                 }
1218                                 else
1219                                 {
1220                                         if (unit->t1d)
1221                                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1222                                 }
1223                                 qglBindTexture(GL_TEXTURE_1D, (unit->t1d = m->tex1d[i]));CHECKGLERROR
1224                         }
1225                         if (unit->t2d != m->tex[i])
1226                         {
1227 #ifdef MESH_BATCH
1228                                 if (gl_batchelementcount)
1229                                         R_Mesh_EndBatch();
1230 #endif
1231                                 if (gl_state.unit != i)
1232                                 {
1233                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1234                                 }
1235                                 if (m->tex[i])
1236                                 {
1237                                         if (unit->t2d == 0)
1238                                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1239                                 }
1240                                 else
1241                                 {
1242                                         if (unit->t2d)
1243                                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1244                                 }
1245                                 qglBindTexture(GL_TEXTURE_2D, (unit->t2d = m->tex[i]));CHECKGLERROR
1246                         }
1247                         if (unit->t3d != m->tex3d[i])
1248                         {
1249 #ifdef MESH_BATCH
1250                                 if (gl_batchelementcount)
1251                                         R_Mesh_EndBatch();
1252 #endif
1253                                 if (gl_state.unit != i)
1254                                 {
1255                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1256                                 }
1257                                 if (m->tex3d[i])
1258                                 {
1259                                         if (unit->t3d == 0)
1260                                                 qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1261                                 }
1262                                 else
1263                                 {
1264                                         if (unit->t3d)
1265                                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1266                                 }
1267                                 qglBindTexture(GL_TEXTURE_3D, (unit->t3d = m->tex3d[i]));CHECKGLERROR
1268                         }
1269                         if (unit->tcubemap != m->texcubemap[i])
1270                         {
1271 #ifdef MESH_BATCH
1272                                 if (gl_batchelementcount)
1273                                         R_Mesh_EndBatch();
1274 #endif
1275                                 if (gl_state.unit != i)
1276                                 {
1277                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1278                                 }
1279                                 if (m->texcubemap[i])
1280                                 {
1281                                         if (unit->tcubemap == 0)
1282                                                 qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1283                                 }
1284                                 else
1285                                 {
1286                                         if (unit->tcubemap)
1287                                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1288                                 }
1289                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, (unit->tcubemap = m->texcubemap[i]));CHECKGLERROR
1290                         }
1291                 }
1292                 combinergb = m->texcombinergb[i];
1293                 if (!combinergb)
1294                         combinergb = GL_MODULATE;
1295                 if (unit->combinergb != combinergb)
1296                 {
1297 #ifdef MESH_BATCH
1298                         if (gl_batchelementcount)
1299                                 R_Mesh_EndBatch();
1300 #endif
1301                         if (gl_state.unit != i)
1302                         {
1303                                 qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1304                         }
1305                         unit->combinergb = combinergb;
1306                         if (gl_combine.integer)
1307                         {
1308                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1309                         }
1310                         else
1311                         {
1312                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1313                         }
1314                 }
1315                 combinealpha = m->texcombinealpha[i];
1316                 if (!combinealpha)
1317                         combinealpha = GL_MODULATE;
1318                 if (unit->combinealpha != combinealpha)
1319                 {
1320 #ifdef MESH_BATCH
1321                         if (gl_batchelementcount)
1322                                 R_Mesh_EndBatch();
1323 #endif
1324                         if (gl_state.unit != i)
1325                         {
1326                                 qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1327                         }
1328                         unit->combinealpha = combinealpha;
1329                         if (gl_combine.integer)
1330                         {
1331                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1332                         }
1333                 }
1334                 scale = max(m->texrgbscale[i], 1);
1335                 if (gl_state.units[i].rgbscale != scale)
1336                 {
1337 #ifdef MESH_BATCH
1338                         if (gl_batchelementcount)
1339                                 R_Mesh_EndBatch();
1340 #endif
1341                         if (gl_state.unit != i)
1342                         {
1343                                 qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1344                         }
1345                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (gl_state.units[i].rgbscale = scale));CHECKGLERROR
1346                 }
1347                 scale = max(m->texalphascale[i], 1);
1348                 if (gl_state.units[i].alphascale != scale)
1349                 {
1350 #ifdef MESH_BATCH
1351                         if (gl_batchelementcount)
1352                                 R_Mesh_EndBatch();
1353 #endif
1354                         if (gl_state.unit != i)
1355                         {
1356                                 qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
1357                         }
1358                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (gl_state.units[i].alphascale = scale));CHECKGLERROR
1359                 }
1360                 if (unit->arrayenabled)
1361                 {
1362                         p = gl_state.pointervertexcount ? m->pointer_texcoord[i] : NULL;
1363                         if (unit->pointer_texcoord != p)
1364                         {
1365 #ifdef MESH_BATCH
1366                                 if (gl_batchelementcount)
1367                                         R_Mesh_EndBatch();
1368 #endif
1369                                 unit->pointer_texcoord = p;
1370                                 if (gl_state.clientunit != i)
1371                                 {
1372                                         qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
1373                                 }
1374                                 if (unit->arrayis3d)
1375                                         qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), p ? p : varray_buf_texcoord3f[i]);
1376                                 else
1377                                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), p ? p : varray_buf_texcoord2f[i]);
1378                                 CHECKGLERROR
1379                         }
1380                 }
1381         }
1382 }
1383
1384 void R_Mesh_State(const rmeshstate_t *m)
1385 {
1386         R_Mesh_MainState(m);
1387         R_Mesh_TextureState(m);
1388 }
1389
1390 /*
1391 ==============================================================================
1392
1393                                                 SCREEN SHOTS
1394
1395 ==============================================================================
1396 */
1397
1398 qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height, qboolean jpeg)
1399 {
1400         qboolean ret;
1401         int i, j;
1402         qbyte *buffer;
1403
1404         if (!r_render.integer)
1405                 return false;
1406
1407         buffer = Mem_Alloc(tempmempool, width*height*3);
1408         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
1409         CHECKGLERROR
1410
1411         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
1412         if (v_hwgamma.integer)
1413         {
1414                 for (i = 0;i < width * height * 3;i++)
1415                 {
1416                         j = buffer[i] << v_overbrightbits.integer;
1417                         buffer[i] = (qbyte) (bound(0, j, 255));
1418                 }
1419         }
1420
1421         if (jpeg)
1422                 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer);
1423         else
1424                 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer);
1425
1426         Mem_Free(buffer);
1427         return ret;
1428 }
1429
1430 //=============================================================================
1431
1432 void R_ClearScreen(void)
1433 {
1434         if (r_render.integer)
1435         {
1436                 // clear to black
1437                 qglClearColor(0,0,0,0);CHECKGLERROR
1438                 qglClearDepth(1);CHECKGLERROR
1439                 if (gl_stencil)
1440                 {
1441                         // LordHavoc: we use a stencil centered around 128 instead of 0,
1442                         // to avoid clamping interfering with strange shadow volume
1443                         // drawing orders
1444                         qglClearStencil(128);CHECKGLERROR
1445                 }
1446                 // clear the screen
1447                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));CHECKGLERROR
1448                 // set dithering mode
1449                 if (gl_dither.integer)
1450                 {
1451                         qglEnable(GL_DITHER);CHECKGLERROR
1452                 }
1453                 else
1454                 {
1455                         qglDisable(GL_DITHER);CHECKGLERROR
1456                 }
1457         }
1458 }
1459
1460 /*
1461 ==================
1462 SCR_UpdateScreen
1463
1464 This is called every frame, and can also be called explicitly to flush
1465 text to the screen.
1466 ==================
1467 */
1468 void SCR_UpdateScreen (void)
1469 {
1470         if (gl_delayfinish.integer)
1471         {
1472                 VID_Finish ();
1473
1474                 R_TimeReport("finish");
1475         }
1476
1477         if (r_textureunits.integer > gl_textureunits)
1478                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1479         if (r_textureunits.integer < 1)
1480                 Cvar_SetValueQuick(&r_textureunits, 1);
1481
1482         if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
1483                 Cvar_SetValueQuick(&gl_combine, 0);
1484
1485         // lighting scale
1486         r_colorscale = 1.0f / (float) (1 << v_overbrightbits.integer);
1487
1488         // lightmaps only
1489         r_lightmapscalebit = v_overbrightbits.integer;
1490         if (gl_combine.integer && r_textureunits.integer > 1)
1491                 r_lightmapscalebit += 2;
1492
1493         R_TimeReport("setup");
1494
1495         R_ClearScreen();
1496
1497         R_TimeReport("clear");
1498
1499         if (scr_conlines < vid.conheight && cls.signon == SIGNONS)
1500                 R_RenderView();
1501
1502         // draw 2D stuff
1503         R_DrawQueue();
1504
1505         if (gl_delayfinish.integer)
1506         {
1507                 // tell driver to commit it's partially full geometry queue to the rendering queue
1508                 // (this doesn't wait for the commands themselves to complete)
1509                 qglFlush();
1510         }
1511         else
1512         {
1513                 VID_Finish ();
1514
1515                 R_TimeReport("finish");
1516         }
1517 }
1518
1519 // utility functions
1520
1521 void R_Mesh_CopyVertex3f(const float *vertex3f, int numverts)
1522 {
1523 #ifdef MESH_VAR
1524         if (mesh_var)
1525         {
1526                 float *out = varray_vertex3f;
1527                 while (--numverts)
1528                 {
1529                         *out++ = *vertex3f++;
1530                         *out++ = *vertex3f++;
1531                         *out++ = *vertex3f++;
1532                 }
1533         }
1534         else
1535 #endif
1536                 memcpy(varray_vertex3f, vertex3f, numverts * sizeof(float[3]));
1537 }
1538
1539 void R_Mesh_CopyTexCoord2f(int tmu, const float *texcoord2f, int numverts)
1540 {
1541 #ifdef MESH_VAR
1542         if (mesh_var)
1543         {
1544                 float *out = varray_texcoord2f[tmu];
1545                 while (--numverts)
1546                 {
1547                         *out++ = *texcoord2f++;
1548                         *out++ = *texcoord2f++;
1549                 }
1550         }
1551         else
1552 #endif
1553                 memcpy(varray_texcoord2f[tmu], texcoord2f, numverts * sizeof(float[2]));
1554 }
1555
1556 void R_Mesh_CopyColor4f(const float *color4f, int numverts)
1557 {
1558 #ifdef MESH_VAR
1559         if (mesh_var)
1560         {
1561                 float *out = varray_color4f;
1562                 while (--numverts)
1563                 {
1564                         *out++ = *color4f++;
1565                         *out++ = *color4f++;
1566                         *out++ = *color4f++;
1567                         *out++ = *color4f++;
1568                 }
1569         }
1570         else
1571 #endif
1572                 memcpy(varray_color4f, color4f, numverts * sizeof(float[4]));
1573 }
1574