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