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