]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
forgot a m.transparent = in the last commit, and removed a comment
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3
4 cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "1024"};
5 cvar_t gl_mesh_transtriangles = {0, "gl_mesh_transtriangles", "16384"};
6 cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
7 cvar_t gl_mesh_drawmode = {CVAR_SAVE, "gl_mesh_drawmode", "3"};
8
9 cvar_t r_render = {0, "r_render", "1"};
10 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
11 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
12
13 // this is used to increase gl_mesh_maxtriangles automatically if a mesh was
14 // too large for the buffers in the previous frame
15 int overflowedverts = 0;
16 // increase transtriangles automatically too
17 int overflowedtransverts = 0;
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 float r_mesh_farclip;
72
73 static float viewdist;
74 // sign bits (true if negative) for vpn[] entries, so quick integer compares can be used instead of float compares
75 static int vpnbit0, vpnbit1, vpnbit2;
76
77 int c_meshs, c_meshtris, c_transmeshs, c_transtris;
78
79 int lightscalebit;
80 float lightscale;
81 float overbrightscale;
82
83 void SCR_ScreenShot_f (void);
84
85 static int max_meshs;
86 static int max_transmeshs;
87 static int max_verts; // always max_meshs * 3
88 static int max_transverts; // always max_transmeshs * 3
89 #define TRANSDEPTHRES 4096
90
91 typedef struct buf_mesh_s
92 {
93         int depthmask;
94         int depthtest;
95         int blendfunc1, blendfunc2;
96         int textures[MAX_TEXTUREUNITS];
97         int texturergbscale[MAX_TEXTUREUNITS];
98         int firsttriangle;
99         int triangles;
100         int firstvert;
101         int verts;
102         struct buf_mesh_s *chain;
103         struct buf_transtri_s *transchain;
104 }
105 buf_mesh_t;
106
107 typedef struct buf_transtri_s
108 {
109         struct buf_transtri_s *next;
110         struct buf_transtri_s *meshsortchain;
111         buf_mesh_t *mesh;
112         int index[3];
113 }
114 buf_transtri_t;
115
116 typedef struct buf_tri_s
117 {
118         int index[3];
119 }
120 buf_tri_t;
121
122 typedef struct
123 {
124         float v[4];
125 }
126 buf_vertex_t;
127
128 typedef struct
129 {
130         float c[4];
131 }
132 buf_fcolor_t;
133
134 typedef struct
135 {
136         qbyte c[4];
137 }
138 buf_bcolor_t;
139
140 typedef struct
141 {
142         float t[2];
143 }
144 buf_texcoord_t;
145
146 static int currentmesh, currenttriangle, currentvertex, backendunits, backendactive, transranout;
147 static buf_mesh_t *buf_mesh;
148 static buf_tri_t *buf_tri;
149 static buf_vertex_t *buf_vertex;
150 static buf_fcolor_t *buf_fcolor;
151 static buf_bcolor_t *buf_bcolor;
152 static buf_texcoord_t *buf_texcoord[MAX_TEXTUREUNITS];
153
154 static int currenttransmesh, currenttransvertex, currenttranstriangle;
155 static buf_mesh_t *buf_transmesh;
156 static buf_transtri_t *buf_sorttranstri;
157 static buf_transtri_t **buf_sorttranstri_list;
158 static buf_tri_t *buf_transtri;
159 static buf_vertex_t *buf_transvertex;
160 static buf_fcolor_t *buf_transfcolor;
161 static buf_texcoord_t *buf_transtexcoord[MAX_TEXTUREUNITS];
162
163 static mempool_t *gl_backend_mempool;
164 static int resizingbuffers = false;
165
166 static void gl_backend_start(void)
167 {
168         int i;
169
170         qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
171         qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
172
173         Con_Printf("OpenGL Backend started with gl_mesh_maxtriangles %i, gl_mesh_transtriangles %i\n", gl_mesh_maxtriangles.integer, gl_mesh_transtriangles.integer);
174         if (qglDrawRangeElements != NULL)
175                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
176         if (strstr(gl_renderer, "3Dfx"))
177         {
178                 Con_Printf("3Dfx driver detected, forcing gl_mesh_floatcolors to 0 to prevent crashs\n");
179                 Cvar_SetValueQuick(&gl_mesh_floatcolors, 0);
180         }
181         Con_Printf("\n");
182
183         max_verts = max_meshs * 3;
184         max_transverts = max_transmeshs * 3;
185
186         if (!gl_backend_mempool)
187                 gl_backend_mempool = Mem_AllocPool("GL_Backend");
188
189 #define BACKENDALLOC(var, count, sizeofstruct, varname)\
190         {\
191                 var = Mem_Alloc(gl_backend_mempool, count * sizeof(sizeofstruct));\
192                 if (var == NULL)\
193                         Sys_Error("gl_backend_start: unable to allocate memory for %s (%d bytes)\n", (varname), count * sizeof(sizeofstruct));\
194                 memset(var, 0, count * sizeof(sizeofstruct));\
195         }
196
197         BACKENDALLOC(buf_mesh, max_meshs, buf_mesh_t, "buf_mesh")
198         BACKENDALLOC(buf_tri, max_meshs, buf_tri_t, "buf_tri")
199         BACKENDALLOC(buf_vertex, max_verts, buf_vertex_t, "buf_vertex")
200         BACKENDALLOC(buf_fcolor, max_verts, buf_fcolor_t, "buf_fcolor")
201         BACKENDALLOC(buf_bcolor, max_verts, buf_bcolor_t, "buf_bcolor")
202
203         BACKENDALLOC(buf_transmesh, max_transmeshs, buf_mesh_t, "buf_transmesh")
204         BACKENDALLOC(buf_sorttranstri, max_transmeshs, buf_transtri_t, "buf_sorttranstri")
205         BACKENDALLOC(buf_sorttranstri_list, TRANSDEPTHRES, buf_transtri_t *, "buf_sorttranstri_list")
206         BACKENDALLOC(buf_transtri, max_transmeshs, buf_tri_t, "buf_transtri")
207         BACKENDALLOC(buf_transvertex, max_transverts, buf_vertex_t, "buf_vertex")
208         BACKENDALLOC(buf_transfcolor, max_transverts, buf_fcolor_t, "buf_fcolor")
209
210         for (i = 0;i < MAX_TEXTUREUNITS;i++)
211         {
212                 // only allocate as many texcoord arrays as we need
213                 if (i < gl_textureunits)
214                 {
215                         BACKENDALLOC(buf_texcoord[i], max_verts, buf_texcoord_t, va("buf_texcoord[%d]", i))
216                         BACKENDALLOC(buf_transtexcoord[i], max_transverts, buf_texcoord_t, va("buf_transtexcoord[%d]", i))
217                 }
218                 else
219                 {
220                         buf_texcoord[i] = NULL;
221                         buf_transtexcoord[i] = NULL;
222                 }
223         }
224         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
225         backendactive = true;
226 }
227
228 static void gl_backend_shutdown(void)
229 {
230         Con_Printf("OpenGL Backend shutting down\n");
231
232         if (resizingbuffers)
233                 Mem_EmptyPool(gl_backend_mempool);
234         else
235                 Mem_FreePool(&gl_backend_mempool);
236
237         backendunits = 0;
238         backendactive = false;
239 }
240
241 static void gl_backend_bufferchanges(int init)
242 {
243         if (overflowedverts > gl_mesh_maxtriangles.integer * 3)
244                 Cvar_SetValueQuick(&gl_mesh_maxtriangles, (int) ((overflowedverts + 2) / 3));
245         overflowedverts = 0;
246
247         if (overflowedtransverts > gl_mesh_transtriangles.integer * 3)
248                 Cvar_SetValueQuick(&gl_mesh_transtriangles, (int) ((overflowedtransverts + 2) / 3));
249         overflowedtransverts = 0;
250
251         if (gl_mesh_drawmode.integer < 0)
252                 Cvar_SetValueQuick(&gl_mesh_drawmode, 0);
253         if (gl_mesh_drawmode.integer > 3)
254                 Cvar_SetValueQuick(&gl_mesh_drawmode, 3);
255
256         if (gl_mesh_drawmode.integer >= 3 && qglDrawRangeElements == NULL)
257         {
258                 // change drawmode 3 to 2 if 3 won't work at all
259                 Cvar_SetValueQuick(&gl_mesh_drawmode, 2);
260         }
261
262         // 21760 is (65536 / 3) rounded off to a multiple of 128
263         if (gl_mesh_maxtriangles.integer < 1024)
264                 Cvar_SetValueQuick(&gl_mesh_maxtriangles, 1024);
265         if (gl_mesh_maxtriangles.integer > 21760)
266                 Cvar_SetValueQuick(&gl_mesh_maxtriangles, 21760);
267
268         if (gl_mesh_transtriangles.integer < 1024)
269                 Cvar_SetValueQuick(&gl_mesh_transtriangles, 1024);
270         if (gl_mesh_transtriangles.integer > 65536)
271                 Cvar_SetValueQuick(&gl_mesh_transtriangles, 65536);
272
273         if (max_meshs != gl_mesh_maxtriangles.integer || max_transmeshs != gl_mesh_transtriangles.integer)
274         {
275                 max_meshs = gl_mesh_maxtriangles.integer;
276                 max_transmeshs = gl_mesh_transtriangles.integer;
277
278                 if (!init)
279                 {
280                         resizingbuffers = true;
281                         gl_backend_shutdown();
282                         gl_backend_start();
283                         resizingbuffers = false;
284                 }
285         }
286 }
287
288 static void gl_backend_newmap(void)
289 {
290 }
291
292 void gl_backend_init(void)
293 {
294         Cvar_RegisterVariable(&r_render);
295         Cvar_RegisterVariable(&gl_dither);
296         Cvar_RegisterVariable(&gl_lockarrays);
297 #ifdef NORENDER
298         Cvar_SetValue("r_render", 0);
299 #endif
300
301         Cvar_RegisterVariable(&gl_mesh_maxtriangles);
302         Cvar_RegisterVariable(&gl_mesh_transtriangles);
303         Cvar_RegisterVariable(&gl_mesh_floatcolors);
304         Cvar_RegisterVariable(&gl_mesh_drawmode);
305         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
306         gl_backend_bufferchanges(true);
307 }
308
309 int arraylocked = false;
310
311 void GL_LockArray(int first, int count)
312 {
313         if (!arraylocked && gl_supportslockarrays && gl_lockarrays.integer && gl_mesh_drawmode.integer > 0)
314         {
315                 qglLockArraysEXT(first, count);
316                 CHECKGLERROR
317                 arraylocked = true;
318         }
319 }
320
321 void GL_UnlockArray(void)
322 {
323         if (arraylocked)
324         {
325                 qglUnlockArraysEXT();
326                 CHECKGLERROR
327                 arraylocked = false;
328         }
329 }
330
331 /*
332 =============
333 GL_SetupFrame
334 =============
335 */
336 static void GL_SetupFrame (void)
337 {
338         double xmax, ymax;
339         double fovx, fovy, zNear, zFar, aspect;
340
341         if (!r_render.integer)
342                 return;
343
344         qglDepthFunc (GL_LEQUAL);CHECKGLERROR
345
346         // set up viewpoint
347         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
348         qglLoadIdentity ();CHECKGLERROR
349
350         // y is weird beause OpenGL is bottom to top, we use top to bottom
351         qglViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);CHECKGLERROR
352
353         // depth range
354         zNear = 1.0;
355         zFar = r_mesh_farclip;
356
357         // fov angles
358         fovx = r_refdef.fov_x;
359         fovy = r_refdef.fov_y;
360         aspect = r_refdef.width / r_refdef.height;
361
362         // pyramid slopes
363         xmax = zNear * tan(fovx * M_PI / 360.0) * aspect;
364         ymax = zNear * tan(fovy * M_PI / 360.0);
365
366         // set view pyramid
367         qglFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
368
369         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
370         qglLoadIdentity ();CHECKGLERROR
371
372         // put Z going up
373         qglRotatef (-90,  1, 0, 0);CHECKGLERROR
374         qglRotatef (90,  0, 0, 1);CHECKGLERROR
375         // camera rotation
376         qglRotatef (-r_refdef.viewangles[2],  1, 0, 0);CHECKGLERROR
377         qglRotatef (-r_refdef.viewangles[0],  0, 1, 0);CHECKGLERROR
378         qglRotatef (-r_refdef.viewangles[1],  0, 0, 1);CHECKGLERROR
379         // camera location
380         qglTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);CHECKGLERROR
381 }
382
383 static struct
384 {
385         int blendfunc1;
386         int blendfunc2;
387         int blend;
388         GLboolean depthmask;
389         int depthtest;
390         int unit;
391         int clientunit;
392         int texture[MAX_TEXTUREUNITS];
393         float texturergbscale[MAX_TEXTUREUNITS];
394 }
395 gl_state;
396
397 void GL_SetupTextureState(void)
398 {
399         int i;
400         if (backendunits > 1)
401         {
402                 for (i = 0;i < backendunits;i++)
403                 {
404                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
405                         qglBindTexture(GL_TEXTURE_2D, gl_state.texture[i]);CHECKGLERROR
406                         if (gl_combine.integer)
407                         {
408                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
409                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
410                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
411                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
412                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);CHECKGLERROR
413                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
414                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
415                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
416                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
417                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
418                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
419                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
420                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
421                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
422                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
423                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, gl_state.texturergbscale[i]);CHECKGLERROR
424                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
425                         }
426                         else
427                         {
428                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
429                         }
430                         if (gl_state.texture[i])
431                         {
432                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
433                         }
434                         else
435                         {
436                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
437                         }
438                         if (gl_mesh_drawmode.integer > 0)
439                         {
440                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
441                                 qglTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[i]);CHECKGLERROR
442                                 if (gl_state.texture[i])
443                                 {
444                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
445                                 }
446                                 else
447                                 {
448                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
449                                 }
450                         }
451                 }
452         }
453         else
454         {
455                 qglBindTexture(GL_TEXTURE_2D, gl_state.texture[0]);CHECKGLERROR
456                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
457                 if (gl_state.texture[0])
458                 {
459                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
460                 }
461                 else
462                 {
463                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
464                 }
465                 if (gl_mesh_drawmode.integer > 0)
466                 {
467                         qglTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[0]);CHECKGLERROR
468                         if (gl_state.texture[0])
469                         {
470                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
471                         }
472                         else
473                         {
474                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
475                         }
476                 }
477         }
478 }
479
480 // called at beginning of frame
481 int usedarrays;
482 void R_Mesh_Start(float farclip)
483 {
484         int i;
485         if (!backendactive)
486                 Sys_Error("R_Mesh_Clear: called when backend is not active\n");
487
488         CHECKGLERROR
489
490         gl_backend_bufferchanges(false);
491
492         currentmesh = 0;
493         currenttriangle = 0;
494         currentvertex = 0;
495         currenttransmesh = 0;
496         currenttranstriangle = 0;
497         currenttransvertex = 0;
498         transranout = false;
499         r_mesh_farclip = farclip;
500         viewdist = DotProduct(r_origin, vpn);
501         vpnbit0 = vpn[0] < 0;
502         vpnbit1 = vpn[1] < 0;
503         vpnbit2 = vpn[2] < 0;
504
505         c_meshs = 0;
506         c_meshtris = 0;
507         c_transmeshs = 0;
508         c_transtris = 0;
509
510         GL_SetupFrame();
511
512         gl_state.unit = 0;
513         gl_state.clientunit = 0;
514
515         for (i = 0;i < backendunits;i++)
516         {
517                 gl_state.texture[i] = 0;
518                 gl_state.texturergbscale[i] = 1;
519         }
520
521         qglEnable(GL_CULL_FACE);CHECKGLERROR
522         qglCullFace(GL_FRONT);CHECKGLERROR
523
524         gl_state.depthtest = true;
525         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
526
527         gl_state.blendfunc1 = GL_ONE;
528         gl_state.blendfunc2 = GL_ZERO;
529         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
530
531         gl_state.blend = 0;
532         qglDisable(GL_BLEND);CHECKGLERROR
533
534         gl_state.depthmask = GL_TRUE;
535         qglDepthMask(gl_state.depthmask);CHECKGLERROR
536
537         usedarrays = false;
538         if (gl_mesh_drawmode.integer > 0)
539         {
540                 usedarrays = true;
541                 qglVertexPointer(3, GL_FLOAT, sizeof(buf_vertex_t), &buf_vertex[0].v[0]);CHECKGLERROR
542                 qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
543                 if (gl_mesh_floatcolors.integer)
544                 {
545                         qglColorPointer(4, GL_FLOAT, sizeof(buf_fcolor_t), &buf_fcolor[0].c[0]);CHECKGLERROR
546                 }
547                 else
548                 {
549                         qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(buf_bcolor_t), &buf_bcolor[0].c[0]);CHECKGLERROR
550                 }
551                 qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
552         }
553
554         GL_SetupTextureState();
555 }
556
557 int gl_backend_rebindtextures;
558
559 void GL_ConvertColorsFloatToByte(void)
560 {
561         int i, k, total;
562         // LordHavoc: to avoid problems with aliasing (treating memory as two
563         // different types - exactly what this is doing), these must be volatile
564         // (or a union)
565         volatile int *icolor;
566         volatile float *fcolor;
567         qbyte *bcolor;
568
569         total = currentvertex * 4;
570
571         // shift float to have 8bit fraction at base of number
572         fcolor = &buf_fcolor->c[0];
573         for (i = 0;i < total;)
574         {
575                 fcolor[i    ] += 32768.0f;
576                 fcolor[i + 1] += 32768.0f;
577                 fcolor[i + 2] += 32768.0f;
578                 fcolor[i + 3] += 32768.0f;
579                 i += 4;
580         }
581
582         // then read as integer and kill float bits...
583         icolor = (int *)&buf_fcolor->c[0];
584         bcolor = &buf_bcolor->c[0];
585         for (i = 0;i < total;)
586         {
587                 k = icolor[i    ] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i    ] = (qbyte) k;
588                 k = icolor[i + 1] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 1] = (qbyte) k;
589                 k = icolor[i + 2] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 2] = (qbyte) k;
590                 k = icolor[i + 3] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 3] = (qbyte) k;
591                 i += 4;
592         }
593 }
594
595 void GL_MeshState(buf_mesh_t *mesh)
596 {
597         int i;
598         if (backendunits > 1)
599         {
600                 for (i = 0;i < backendunits;i++)
601                 {
602                         if (gl_state.texture[i] != mesh->textures[i])
603                         {
604                                 if (gl_state.unit != i)
605                                 {
606                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
607                                 }
608                                 if (gl_state.texture[i] == 0)
609                                 {
610                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
611                                         // have to disable texcoord array on disabled texture
612                                         // units due to NVIDIA driver bug with
613                                         // compiled_vertex_array
614                                         if (gl_state.clientunit != i)
615                                         {
616                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
617                                         }
618                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
619                                 }
620                                 qglBindTexture(GL_TEXTURE_2D, (gl_state.texture[i] = mesh->textures[i]));CHECKGLERROR
621                                 if (gl_state.texture[i] == 0)
622                                 {
623                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
624                                         // have to disable texcoord array on disabled texture
625                                         // units due to NVIDIA driver bug with
626                                         // compiled_vertex_array
627                                         if (gl_state.clientunit != i)
628                                         {
629                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
630                                         }
631                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
632                                 }
633                         }
634                         if (gl_state.texturergbscale[i] != mesh->texturergbscale[i])
635                         {
636                                 if (gl_state.unit != i)
637                                 {
638                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
639                                 }
640                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (gl_state.texturergbscale[i] = mesh->texturergbscale[i]));CHECKGLERROR
641                         }
642                 }
643         }
644         else
645         {
646                 if (gl_state.texture[0] != mesh->textures[0])
647                 {
648                         if (gl_state.texture[0] == 0)
649                         {
650                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
651                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
652                         }
653                         qglBindTexture(GL_TEXTURE_2D, (gl_state.texture[0] = mesh->textures[0]));CHECKGLERROR
654                         if (gl_state.texture[0] == 0)
655                         {
656                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
657                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
658                         }
659                 }
660         }
661         if (gl_state.blendfunc1 != mesh->blendfunc1 || gl_state.blendfunc2 != mesh->blendfunc2)
662         {
663                 qglBlendFunc(gl_state.blendfunc1 = mesh->blendfunc1, gl_state.blendfunc2 = mesh->blendfunc2);CHECKGLERROR
664                 if (gl_state.blendfunc2 == GL_ZERO)
665                 {
666                         if (gl_state.blendfunc1 == GL_ONE)
667                         {
668                                 if (gl_state.blend)
669                                 {
670                                         gl_state.blend = 0;
671                                         qglDisable(GL_BLEND);CHECKGLERROR
672                                 }
673                         }
674                         else
675                         {
676                                 if (!gl_state.blend)
677                                 {
678                                         gl_state.blend = 1;
679                                         qglEnable(GL_BLEND);CHECKGLERROR
680                                 }
681                         }
682                 }
683                 else
684                 {
685                         if (!gl_state.blend)
686                         {
687                                 gl_state.blend = 1;
688                                 qglEnable(GL_BLEND);CHECKGLERROR
689                         }
690                 }
691         }
692         if (gl_state.depthtest != mesh->depthtest)
693         {
694                 gl_state.depthtest = mesh->depthtest;
695                 if (gl_state.depthtest)
696                         qglEnable(GL_DEPTH_TEST);
697                 else
698                         qglDisable(GL_DEPTH_TEST);
699         }
700         if (gl_state.depthmask != mesh->depthmask)
701         {
702                 qglDepthMask(gl_state.depthmask = mesh->depthmask);CHECKGLERROR
703         }
704 }
705
706 void GL_DrawRangeElements(int firstvert, int endvert, int indexcount, GLuint *index)
707 {
708         unsigned int i, j, in;
709         if (gl_mesh_drawmode.integer >= 3/* && (endvert - firstvert) <= gl_maxdrawrangeelementsvertices && (indexcount) <= gl_maxdrawrangeelementsindices*/)
710         {
711                 // GL 1.2 or GL 1.1 with extension
712                 qglDrawRangeElements(GL_TRIANGLES, firstvert, endvert, indexcount, GL_UNSIGNED_INT, index);
713         }
714         else if (gl_mesh_drawmode.integer >= 2)
715         {
716                 // GL 1.1
717                 qglDrawElements(GL_TRIANGLES, indexcount, GL_UNSIGNED_INT, index);
718         }
719         else if (gl_mesh_drawmode.integer >= 1)
720         {
721                 // GL 1.1
722                 // feed it manually using glArrayElement
723                 qglBegin(GL_TRIANGLES);
724                 for (i = 0;i < indexcount;i++)
725                         qglArrayElement(index[i]);
726                 qglEnd();
727         }
728         else
729         {
730                 // GL 1.1 but not using vertex arrays - 3dfx glquake minigl driver
731                 // feed it manually
732                 qglBegin(GL_TRIANGLES);
733                 if (gl_state.texture[1]) // if the mesh uses multiple textures
734                 {
735                         // the minigl doesn't have this (because it does not have ARB_multitexture)
736                         for (i = 0;i < indexcount;i++)
737                         {
738                                 in = index[i];
739                                 qglColor4ub(buf_bcolor[in].c[0], buf_bcolor[in].c[1], buf_bcolor[in].c[2], buf_bcolor[in].c[3]);
740                                 for (j = 0;j < backendunits;j++)
741                                         if (gl_state.texture[j])
742                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, buf_texcoord[j][in].t[0], buf_texcoord[j][in].t[1]);
743                                 qglVertex3f(buf_vertex[in].v[0], buf_vertex[in].v[1], buf_vertex[in].v[2]);
744                         }
745                 }
746                 else
747                 {
748                         for (i = 0;i < indexcount;i++)
749                         {
750                                 in = index[i];
751                                 qglColor4ub(buf_bcolor[in].c[0], buf_bcolor[in].c[1], buf_bcolor[in].c[2], buf_bcolor[in].c[3]);
752                                 if (gl_state.texture[0])
753                                         qglTexCoord2f(buf_texcoord[0][in].t[0], buf_texcoord[0][in].t[1]);
754                                 qglVertex3f(buf_vertex[in].v[0], buf_vertex[in].v[1], buf_vertex[in].v[2]);
755                         }
756                 }
757                 qglEnd();
758         }
759 }
760
761 // renders mesh buffers, called to flush buffers when full
762 void R_Mesh_Render(void)
763 {
764         int k;
765         buf_mesh_t *mesh;
766
767         if (!backendactive)
768                 Sys_Error("R_Mesh_Render: called when backend is not active\n");
769
770         if (!currentmesh)
771                 return;
772
773         if (!r_render.integer)
774         {
775                 currentmesh = 0;
776                 currenttriangle = 0;
777                 currentvertex = 0;
778                 return;
779         }
780
781         CHECKGLERROR
782
783         // drawmode 0 always uses byte colors
784         if (!gl_mesh_floatcolors.integer || gl_mesh_drawmode.integer <= 0)
785                 GL_ConvertColorsFloatToByte();
786
787         if (gl_backend_rebindtextures)
788         {
789                 gl_backend_rebindtextures = false;
790                 GL_SetupTextureState();
791         }
792
793         GL_MeshState(buf_mesh);
794         GL_LockArray(0, currentvertex);
795         GL_DrawRangeElements(buf_mesh->firstvert, buf_mesh->firstvert + buf_mesh->verts, buf_mesh->triangles * 3, (unsigned int *)&buf_tri[buf_mesh->firsttriangle].index[0]);CHECKGLERROR
796
797         if (currentmesh >= 2)
798         {
799                 for (k = 1, mesh = buf_mesh + k;k < currentmesh;k++, mesh++)
800                 {
801                         GL_MeshState(mesh);
802                         GL_DrawRangeElements(mesh->firstvert, mesh->firstvert + mesh->verts, mesh->triangles * 3, buf_tri[mesh->firsttriangle].index);CHECKGLERROR
803                 }
804         }
805
806         currentmesh = 0;
807         currenttriangle = 0;
808         currentvertex = 0;
809
810         GL_UnlockArray();CHECKGLERROR
811 }
812
813 // restores backend state, used when done with 3D rendering
814 void R_Mesh_Finish(void)
815 {
816         int i;
817         // flush any queued meshs
818         if (currentmesh)
819                 R_Mesh_Render();
820
821         if (backendunits > 1)
822         {
823                 for (i = backendunits - 1;i >= 0;i--)
824                 {
825                         qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
826                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
827                         if (gl_combine.integer)
828                         {
829                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
830                         }
831                         if (i > 0)
832                         {
833                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
834                         }
835                         else
836                         {
837                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
838                         }
839                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
840
841                         if (usedarrays)
842                         {
843                                 qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
844                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
845                         }
846                 }
847         }
848         else
849         {
850                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
851                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
852                 if (usedarrays)
853                 {
854                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
855                 }
856         }
857         if (usedarrays)
858         {
859                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
860                 qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
861         }
862
863         qglDisable(GL_BLEND);CHECKGLERROR
864         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
865         qglDepthMask(GL_TRUE);CHECKGLERROR
866         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
867 }
868
869 void R_Mesh_ClearDepth(void)
870 {
871         if (currenttransmesh)
872                 R_Mesh_AddTransparent();
873         if (currentmesh)
874                 R_Mesh_Render();
875         R_Mesh_Finish();
876         qglClear(GL_DEPTH_BUFFER_BIT);
877         R_Mesh_Start(r_mesh_farclip);
878 }
879
880 void R_Mesh_AddTransparent(void)
881 {
882         int i, j, k, *index;
883         float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
884         buf_vertex_t *vert1, *vert2, *vert3;
885         buf_transtri_t *tri;
886         buf_mesh_t *mesh, *transmesh;
887
888         if (!currenttransmesh)
889                 return;
890
891         // convert index data to transtris for sorting
892         for (j = 0;j < currenttransmesh;j++)
893         {
894                 mesh = buf_transmesh + j;
895                 k = mesh->firsttriangle;
896                 index = &buf_transtri[k].index[0];
897                 for (i = 0;i < mesh->triangles;i++)
898                 {
899                         tri = &buf_sorttranstri[k++];
900                         tri->mesh = mesh;
901                         tri->index[0] = *index++;
902                         tri->index[1] = *index++;
903                         tri->index[2] = *index++;
904                 }
905         }
906
907         // map farclip to 0-4095 list range
908         centerscaler = (TRANSDEPTHRES / r_mesh_farclip) * (1.0f / 3.0f);
909         viewdistcompare = viewdist + 4.0f;
910
911         memset(buf_sorttranstri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
912
913         k = 0;
914         for (j = 0;j < currenttranstriangle;j++)
915         {
916                 tri = &buf_sorttranstri[j];
917                 i = tri->mesh->firstvert;
918
919                 vert1 = &buf_transvertex[tri->index[0] + i];
920                 vert2 = &buf_transvertex[tri->index[1] + i];
921                 vert3 = &buf_transvertex[tri->index[2] + i];
922
923                 dist1 = DotProduct(vert1->v, vpn);
924                 dist2 = DotProduct(vert2->v, vpn);
925                 dist3 = DotProduct(vert3->v, vpn);
926
927                 maxdist = max(dist1, max(dist2, dist3));
928                 if (maxdist < viewdistcompare)
929                         continue;
930
931                 center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
932 #if SLOWMATH
933                 i = (int) center;
934                 i = bound(0, i, (TRANSDEPTHRES - 1));
935 #else
936                 if (center < 0.0f)
937                         center = 0.0f;
938                 center += 8388608.0f;
939                 i = *((int *)&center) & 0x7FFFFF;
940                 i = min(i, (TRANSDEPTHRES - 1));
941 #endif
942                 tri->next = buf_sorttranstri_list[i];
943                 buf_sorttranstri_list[i] = tri;
944                 k++;
945         }
946
947         for (i = 0;i < currenttransmesh;i++)
948                 buf_transmesh[i].transchain = NULL;
949         transmesh = NULL;
950         for (j = 0;j < TRANSDEPTHRES;j++)
951         {
952                 if ((tri = buf_sorttranstri_list[j]))
953                 {
954                         for (;tri;tri = tri->next)
955                         {
956                                 if (!tri->mesh->transchain)
957                                 {
958                                         tri->mesh->chain = transmesh;
959                                         transmesh = tri->mesh;
960                                 }
961                                 tri->meshsortchain = tri->mesh->transchain;
962                                 tri->mesh->transchain = tri;
963                         }
964                 }
965         }
966
967         R_Mesh_Render();
968         for (;transmesh;transmesh = transmesh->chain)
969         {
970                 mesh = &buf_mesh[currentmesh++];
971                 *mesh = *transmesh; // copy mesh properties
972
973                 mesh->firstvert = currentvertex;
974                 memcpy(&buf_vertex[currentvertex], &buf_transvertex[transmesh->firstvert], transmesh->verts * sizeof(buf_vertex_t));
975                 memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[transmesh->firstvert], transmesh->verts * sizeof(buf_fcolor_t));
976                 for (i = 0;i < backendunits && transmesh->textures[i];i++)
977                         memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][transmesh->firstvert], transmesh->verts * sizeof(buf_texcoord_t));
978                 currentvertex += mesh->verts;
979
980                 mesh->firsttriangle = currenttriangle;
981                 for (tri = transmesh->transchain;tri;tri = tri->meshsortchain)
982                 {
983                         buf_tri[currenttriangle].index[0] = tri->index[0];
984                         buf_tri[currenttriangle].index[1] = tri->index[1];
985                         buf_tri[currenttriangle].index[2] = tri->index[2];
986                         currenttriangle++;
987                 }
988                 mesh->triangles = currenttriangle - mesh->firsttriangle;
989                 R_Mesh_Render();
990         }
991
992         currenttransmesh = 0;
993         currenttranstriangle = 0;
994         currenttransvertex = 0;
995 }
996
997 // allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
998 // (this is used for very high speed rendering, no copying)
999 int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m, int wantoverbright)
1000 {
1001         // these are static because gcc runs out of virtual registers otherwise
1002         int i, j, overbright;
1003         float scaler;
1004         buf_mesh_t *mesh;
1005
1006         if (!backendactive)
1007                 Sys_Error("R_Mesh_Draw_GetBuffer: called when backend is not active\n");
1008
1009         if (!m->numtriangles
1010          || !m->numverts)
1011                 Host_Error("R_Mesh_Draw_GetBuffer: no triangles or verts\n");
1012
1013         // LordHavoc: removed this error condition because with floatcolors 0,
1014         // the 3DFX driver works with very large meshs
1015         // FIXME: we can work around this by falling back on non-array renderer if buffers are too big
1016         //if (m->numtriangles > 1024 || m->numverts > 3072)
1017         //{
1018         //      Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for 3DFX drivers, rejected\n");
1019         //      return false;
1020         //}
1021
1022         i = max(m->numtriangles * 3, m->numverts);
1023         if (overflowedverts < i)
1024                 overflowedverts = i;
1025
1026         if (m->numtriangles > max_meshs || m->numverts > max_verts)
1027         {
1028                 Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for current gl_mesh_maxtriangles setting, increasing limits\n");
1029                 return false;
1030         }
1031
1032         if (m->transparent)
1033         {
1034                 overflowedtransverts += max(m->numtriangles * 3, m->numverts);
1035                 if (currenttransmesh >= max_transmeshs || (currenttranstriangle + m->numtriangles) > max_transmeshs || (currenttransvertex + m->numverts) > max_transverts)
1036                 {
1037                         if (!transranout)
1038                         {
1039                                 Con_Printf("R_Mesh_Draw_GetBuffer: ran out of room for transparent meshs\n");
1040                                 transranout = true;
1041                         }
1042                         return false;
1043                 }
1044
1045                 c_transmeshs++;
1046                 c_transtris += m->numtriangles;
1047                 m->index = &buf_transtri[currenttranstriangle].index[0];
1048                 m->vertex = &buf_transvertex[currenttransvertex].v[0];
1049                 m->color = &buf_transfcolor[currenttransvertex].c[0];
1050                 for (i = 0;i < backendunits;i++)
1051                         m->texcoords[i] = &buf_transtexcoord[i][currenttransvertex].t[0];
1052
1053                 // transmesh is only for storage of transparent meshs until they
1054                 // are inserted into the main mesh array
1055                 mesh = &buf_transmesh[currenttransmesh++];
1056                 mesh->firsttriangle = currenttranstriangle;
1057                 mesh->firstvert = currenttransvertex;
1058                 currenttranstriangle += m->numtriangles;
1059                 currenttransvertex += m->numverts;
1060         }
1061         else
1062         {
1063                 if (currentmesh)
1064                 {
1065                         R_Mesh_Render();
1066                         Con_Printf("mesh queue not empty, flushing.\n");
1067                 }
1068
1069                 c_meshs++;
1070                 c_meshtris += m->numtriangles;
1071                 m->index = &buf_tri[currenttriangle].index[0];
1072                 m->vertex = &buf_vertex[currentvertex].v[0];
1073                 m->color = &buf_fcolor[currentvertex].c[0];
1074                 for (i = 0;i < backendunits;i++)
1075                         m->texcoords[i] = &buf_texcoord[i][currentvertex].t[0];
1076
1077                 // opaque meshs are rendered directly
1078                 mesh = &buf_mesh[currentmesh++];
1079                 mesh->firsttriangle = currenttriangle;
1080                 mesh->firstvert = currentvertex;
1081                 currenttriangle += m->numtriangles;
1082                 currentvertex += m->numverts;
1083         }
1084
1085         // code shared for transparent and opaque meshs
1086         mesh->blendfunc1 = m->blendfunc1;
1087         mesh->blendfunc2 = m->blendfunc2;
1088         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1089         mesh->depthtest = !m->depthdisable;
1090         mesh->triangles = m->numtriangles;
1091         mesh->verts = m->numverts;
1092
1093         overbright = false;
1094         scaler = 1;
1095         if (m->blendfunc1 == GL_DST_COLOR)
1096         {
1097                 // check if it is a 2x modulate with framebuffer
1098                 if (m->blendfunc2 == GL_SRC_COLOR)
1099                         scaler *= 0.5f;
1100         }
1101         else if (m->blendfunc2 != GL_SRC_COLOR)
1102         {
1103                 if (m->tex[0])
1104                 {
1105                         overbright = wantoverbright && gl_combine.integer;
1106                         if (overbright)
1107                                 scaler *= 0.25f;
1108                 }
1109                 scaler *= overbrightscale;
1110         }
1111         m->colorscale = scaler;
1112
1113         j = -1;
1114         for (i = 0;i < MAX_TEXTUREUNITS;i++)
1115         {
1116                 if ((mesh->textures[i] = m->tex[i]))
1117                 {
1118                         j = i;
1119                         if (i >= backendunits)
1120                                 Sys_Error("R_Mesh_Draw_GetBuffer: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1121                 }
1122                 mesh->texturergbscale[i] = m->texrgbscale[i];
1123                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1124                         mesh->texturergbscale[i] = 1;
1125         }
1126         if (overbright && j >= 0)
1127                 mesh->texturergbscale[j] = 4;
1128
1129         return true;
1130 }
1131
1132 /*
1133 ==============================================================================
1134
1135                                                 SCREEN SHOTS
1136
1137 ==============================================================================
1138 */
1139
1140 qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height)
1141 {
1142         qboolean ret;
1143         int i;
1144         qbyte *buffer;
1145
1146         if (!r_render.integer)
1147                 return false;
1148
1149         buffer = Mem_Alloc(tempmempool, width*height*3);
1150         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
1151         CHECKGLERROR
1152
1153         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
1154         if (v_hwgamma.integer)
1155                 for (i = 0;i < width * height * 3;i++)
1156                         buffer[i] <<= v_overbrightbits.integer;
1157
1158         ret = Image_WriteTGARGB_preflipped(filename, width, height, buffer);
1159
1160         Mem_Free(buffer);
1161         return ret;
1162 }
1163
1164 //=============================================================================
1165
1166 void R_ClearScreen(void)
1167 {
1168         if (r_render.integer)
1169         {
1170                 // clear to black
1171                 qglClearColor(0,0,0,0);CHECKGLERROR
1172                 // clear the screen
1173                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);CHECKGLERROR
1174                 // set dithering mode
1175                 if (gl_dither.integer)
1176                 {
1177                         qglEnable(GL_DITHER);CHECKGLERROR
1178                 }
1179                 else
1180                 {
1181                         qglDisable(GL_DITHER);CHECKGLERROR
1182                 }
1183         }
1184 }
1185
1186 /*
1187 ==================
1188 SCR_UpdateScreen
1189
1190 This is called every frame, and can also be called explicitly to flush
1191 text to the screen.
1192 ==================
1193 */
1194 void SCR_UpdateScreen (void)
1195 {
1196         VID_Finish ();
1197
1198         R_TimeReport("finish");
1199
1200         if (r_textureunits.integer > gl_textureunits)
1201                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1202         if (r_textureunits.integer < 1)
1203                 Cvar_SetValueQuick(&r_textureunits, 1);
1204
1205         if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
1206                 Cvar_SetValueQuick(&gl_combine, 0);
1207
1208         // lighting scale
1209         overbrightscale = 1.0f / (float) (1 << v_overbrightbits.integer);
1210
1211         // lightmaps only
1212         lightscalebit = v_overbrightbits.integer;
1213         if (gl_combine.integer && r_textureunits.integer > 1)
1214                 lightscalebit += 2;
1215         lightscale = 1.0f / (float) (1 << lightscalebit);
1216
1217         R_TimeReport("setup");
1218
1219         R_ClearScreen();
1220
1221         R_TimeReport("clear");
1222
1223         if (scr_conlines < vid.conheight)
1224                 R_RenderView();
1225
1226         // draw 2D stuff
1227         R_DrawQueue();
1228
1229         // tell driver to commit it's partially full geometry queue to the rendering queue
1230         // (this doesn't wait for the commands themselves to complete)
1231         qglFlush();
1232 }
1233