]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
0c7c31507d74c4e7ccd6209957375cd879f4365e
[xonotic/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 int mesh_blendfunc1;
384 static int mesh_blendfunc2;
385 static int mesh_blend;
386 static GLboolean mesh_depthmask;
387 static int mesh_depthtest;
388 static int mesh_unit;
389 static int mesh_clientunit;
390 static int mesh_texture[MAX_TEXTUREUNITS];
391 static float mesh_texturergbscale[MAX_TEXTUREUNITS];
392
393 void GL_SetupTextureState(void)
394 {
395         int i;
396         if (backendunits > 1)
397         {
398                 for (i = 0;i < backendunits;i++)
399                 {
400                         qglActiveTexture(GL_TEXTURE0_ARB + (mesh_unit = i));CHECKGLERROR
401                         qglBindTexture(GL_TEXTURE_2D, mesh_texture[i]);CHECKGLERROR
402                         if (gl_combine.integer)
403                         {
404                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
405                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
406                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
407                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
408                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);CHECKGLERROR
409                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
410                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
411                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
412                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
413                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
414                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
415                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
416                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
417                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
418                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
419                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, mesh_texturergbscale[i]);CHECKGLERROR
420                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
421                         }
422                         else
423                         {
424                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
425                         }
426                         if (mesh_texture[i])
427                         {
428                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
429                         }
430                         else
431                         {
432                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
433                         }
434                         if (gl_mesh_drawmode.integer > 0)
435                         {
436                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (mesh_clientunit = i));CHECKGLERROR
437                                 qglTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[i]);CHECKGLERROR
438                                 if (mesh_texture[i])
439                                 {
440                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
441                                 }
442                                 else
443                                 {
444                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
445                                 }
446                         }
447                 }
448         }
449         else
450         {
451                 qglBindTexture(GL_TEXTURE_2D, mesh_texture[0]);CHECKGLERROR
452                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
453                 if (mesh_texture[0])
454                 {
455                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
456                 }
457                 else
458                 {
459                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
460                 }
461                 if (gl_mesh_drawmode.integer > 0)
462                 {
463                         qglTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[0]);CHECKGLERROR
464                         if (mesh_texture[0])
465                         {
466                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
467                         }
468                         else
469                         {
470                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
471                         }
472                 }
473         }
474 }
475
476 // called at beginning of frame
477 int usedarrays;
478 void R_Mesh_Start(float farclip)
479 {
480         int i;
481         if (!backendactive)
482                 Sys_Error("R_Mesh_Clear: called when backend is not active\n");
483
484         CHECKGLERROR
485
486         gl_backend_bufferchanges(false);
487
488         currentmesh = 0;
489         currenttriangle = 0;
490         currentvertex = 0;
491         currenttransmesh = 0;
492         currenttranstriangle = 0;
493         currenttransvertex = 0;
494         transranout = false;
495         r_mesh_farclip = farclip;
496         viewdist = DotProduct(r_origin, vpn);
497         vpnbit0 = vpn[0] < 0;
498         vpnbit1 = vpn[1] < 0;
499         vpnbit2 = vpn[2] < 0;
500
501         c_meshs = 0;
502         c_meshtris = 0;
503         c_transmeshs = 0;
504         c_transtris = 0;
505
506         GL_SetupFrame();
507
508         mesh_unit = 0;
509         mesh_clientunit = 0;
510
511         for (i = 0;i < backendunits;i++)
512         {
513                 mesh_texture[i] = 0;
514                 mesh_texturergbscale[i] = 1;
515         }
516
517         qglEnable(GL_CULL_FACE);CHECKGLERROR
518         qglCullFace(GL_FRONT);CHECKGLERROR
519
520         mesh_depthtest = true;
521         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
522
523         mesh_blendfunc1 = GL_ONE;
524         mesh_blendfunc2 = GL_ZERO;
525         qglBlendFunc(mesh_blendfunc1, mesh_blendfunc2);CHECKGLERROR
526
527         mesh_blend = 0;
528         qglDisable(GL_BLEND);CHECKGLERROR
529
530         mesh_depthmask = GL_TRUE;
531         qglDepthMask(mesh_depthmask);CHECKGLERROR
532
533         usedarrays = false;
534         if (gl_mesh_drawmode.integer > 0)
535         {
536                 usedarrays = true;
537                 qglVertexPointer(3, GL_FLOAT, sizeof(buf_vertex_t), &buf_vertex[0].v[0]);CHECKGLERROR
538                 qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
539                 if (gl_mesh_floatcolors.integer)
540                 {
541                         qglColorPointer(4, GL_FLOAT, sizeof(buf_fcolor_t), &buf_fcolor[0].c[0]);CHECKGLERROR
542                 }
543                 else
544                 {
545                         qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(buf_bcolor_t), &buf_bcolor[0].c[0]);CHECKGLERROR
546                 }
547                 qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
548         }
549
550         GL_SetupTextureState();
551 }
552
553 int gl_backend_rebindtextures;
554
555 void GL_ConvertColorsFloatToByte(void)
556 {
557         int i, k, total;
558         // LordHavoc: to avoid problems with aliasing (treating memory as two
559         // different types - exactly what this is doing), these must be volatile
560         // (or a union)
561         volatile int *icolor;
562         volatile float *fcolor;
563         qbyte *bcolor;
564
565         total = currentvertex * 4;
566
567         // shift float to have 8bit fraction at base of number
568         fcolor = &buf_fcolor->c[0];
569         for (i = 0;i < total;)
570         {
571                 fcolor[i    ] += 32768.0f;
572                 fcolor[i + 1] += 32768.0f;
573                 fcolor[i + 2] += 32768.0f;
574                 fcolor[i + 3] += 32768.0f;
575                 i += 4;
576         }
577
578         // then read as integer and kill float bits...
579         icolor = (int *)&buf_fcolor->c[0];
580         bcolor = &buf_bcolor->c[0];
581         for (i = 0;i < total;)
582         {
583                 k = icolor[i    ] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i    ] = (qbyte) k;
584                 k = icolor[i + 1] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 1] = (qbyte) k;
585                 k = icolor[i + 2] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 2] = (qbyte) k;
586                 k = icolor[i + 3] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 3] = (qbyte) k;
587                 i += 4;
588         }
589 }
590
591 void GL_MeshState(buf_mesh_t *mesh)
592 {
593         int i;
594         if (backendunits > 1)
595         {
596                 for (i = 0;i < backendunits;i++)
597                 {
598                         if (mesh_texture[i] != mesh->textures[i])
599                         {
600                                 if (mesh_unit != i)
601                                 {
602                                         qglActiveTexture(GL_TEXTURE0_ARB + (mesh_unit = i));CHECKGLERROR
603                                 }
604                                 if (mesh_texture[i] == 0)
605                                 {
606                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
607                                         // have to disable texcoord array on disabled texture
608                                         // units due to NVIDIA driver bug with
609                                         // compiled_vertex_array
610                                         if (mesh_clientunit != i)
611                                         {
612                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (mesh_clientunit = i));CHECKGLERROR
613                                         }
614                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
615                                 }
616                                 qglBindTexture(GL_TEXTURE_2D, (mesh_texture[i] = mesh->textures[i]));CHECKGLERROR
617                                 if (mesh_texture[i] == 0)
618                                 {
619                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
620                                         // have to disable texcoord array on disabled texture
621                                         // units due to NVIDIA driver bug with
622                                         // compiled_vertex_array
623                                         if (mesh_clientunit != i)
624                                         {
625                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (mesh_clientunit = i));CHECKGLERROR
626                                         }
627                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
628                                 }
629                         }
630                         if (mesh_texturergbscale[i] != mesh->texturergbscale[i])
631                         {
632                                 if (mesh_unit != i)
633                                 {
634                                         qglActiveTexture(GL_TEXTURE0_ARB + (mesh_unit = i));CHECKGLERROR
635                                 }
636                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (mesh_texturergbscale[i] = mesh->texturergbscale[i]));CHECKGLERROR
637                         }
638                 }
639         }
640         else
641         {
642                 if (mesh_texture[0] != mesh->textures[0])
643                 {
644                         if (mesh_texture[0] == 0)
645                         {
646                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
647                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
648                         }
649                         qglBindTexture(GL_TEXTURE_2D, (mesh_texture[0] = mesh->textures[0]));CHECKGLERROR
650                         if (mesh_texture[0] == 0)
651                         {
652                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
653                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
654                         }
655                 }
656         }
657         if (mesh_blendfunc1 != mesh->blendfunc1 || mesh_blendfunc2 != mesh->blendfunc2)
658         {
659                 qglBlendFunc(mesh_blendfunc1 = mesh->blendfunc1, mesh_blendfunc2 = mesh->blendfunc2);CHECKGLERROR
660                 if (mesh_blendfunc2 == GL_ZERO)
661                 {
662                         if (mesh_blendfunc1 == GL_ONE)
663                         {
664                                 if (mesh_blend)
665                                 {
666                                         mesh_blend = 0;
667                                         qglDisable(GL_BLEND);CHECKGLERROR
668                                 }
669                         }
670                         else
671                         {
672                                 if (!mesh_blend)
673                                 {
674                                         mesh_blend = 1;
675                                         qglEnable(GL_BLEND);CHECKGLERROR
676                                 }
677                         }
678                 }
679                 else
680                 {
681                         if (!mesh_blend)
682                         {
683                                 mesh_blend = 1;
684                                 qglEnable(GL_BLEND);CHECKGLERROR
685                         }
686                 }
687         }
688         if (mesh_depthtest != mesh->depthtest)
689         {
690                 mesh_depthtest = mesh->depthtest;
691                 if (mesh_depthtest)
692                         qglEnable(GL_DEPTH_TEST);
693                 else
694                         qglDisable(GL_DEPTH_TEST);
695         }
696         if (mesh_depthmask != mesh->depthmask)
697         {
698                 qglDepthMask(mesh_depthmask = mesh->depthmask);CHECKGLERROR
699         }
700 }
701
702 void GL_DrawRangeElements(int firstvert, int endvert, int indexcount, GLuint *index)
703 {
704         unsigned int i, j, in;
705         if (gl_mesh_drawmode.integer >= 3/* && (endvert - firstvert) <= gl_maxdrawrangeelementsvertices && (indexcount) <= gl_maxdrawrangeelementsindices*/)
706         {
707                 // GL 1.2 or GL 1.1 with extension
708                 qglDrawRangeElements(GL_TRIANGLES, firstvert, endvert, indexcount, GL_UNSIGNED_INT, index);
709         }
710         else if (gl_mesh_drawmode.integer >= 2)
711         {
712                 // GL 1.1
713                 qglDrawElements(GL_TRIANGLES, indexcount, GL_UNSIGNED_INT, index);
714         }
715         else if (gl_mesh_drawmode.integer >= 1)
716         {
717                 // GL 1.1
718                 // feed it manually using glArrayElement
719                 qglBegin(GL_TRIANGLES);
720                 for (i = 0;i < indexcount;i++)
721                         qglArrayElement(index[i]);
722                 qglEnd();
723         }
724         else
725         {
726                 // GL 1.1 but not using vertex arrays - 3dfx glquake minigl driver
727                 // feed it manually
728                 qglBegin(GL_TRIANGLES);
729                 if (mesh_texture[1]) // if the mesh uses multiple textures
730                 {
731                         // the minigl doesn't have this (because it does not have ARB_multitexture)
732                         for (i = 0;i < indexcount;i++)
733                         {
734                                 in = index[i];
735                                 qglColor4ub(buf_bcolor[in].c[0], buf_bcolor[in].c[1], buf_bcolor[in].c[2], buf_bcolor[in].c[3]);
736                                 for (j = 0;j < backendunits;j++)
737                                         if (mesh_texture[j])
738                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, buf_texcoord[j][in].t[0], buf_texcoord[j][in].t[1]);
739                                 qglVertex3f(buf_vertex[in].v[0], buf_vertex[in].v[1], buf_vertex[in].v[2]);
740                         }
741                 }
742                 else
743                 {
744                         for (i = 0;i < indexcount;i++)
745                         {
746                                 in = index[i];
747                                 qglColor4ub(buf_bcolor[in].c[0], buf_bcolor[in].c[1], buf_bcolor[in].c[2], buf_bcolor[in].c[3]);
748                                 if (mesh_texture[0])
749                                         qglTexCoord2f(buf_texcoord[0][in].t[0], buf_texcoord[0][in].t[1]);
750                                 qglVertex3f(buf_vertex[in].v[0], buf_vertex[in].v[1], buf_vertex[in].v[2]);
751                         }
752                 }
753                 qglEnd();
754         }
755 }
756
757 // renders mesh buffers, called to flush buffers when full
758 void R_Mesh_Render(void)
759 {
760         int k;
761         buf_mesh_t *mesh;
762
763         if (!backendactive)
764                 Sys_Error("R_Mesh_Render: called when backend is not active\n");
765
766         if (!currentmesh)
767                 return;
768
769         if (!r_render.integer)
770         {
771                 currentmesh = 0;
772                 currenttriangle = 0;
773                 currentvertex = 0;
774                 return;
775         }
776
777         CHECKGLERROR
778
779         // drawmode 0 always uses byte colors
780         if (!gl_mesh_floatcolors.integer || gl_mesh_drawmode.integer <= 0)
781                 GL_ConvertColorsFloatToByte();
782
783         if (gl_backend_rebindtextures)
784         {
785                 gl_backend_rebindtextures = false;
786                 GL_SetupTextureState();
787         }
788
789         GL_MeshState(buf_mesh);
790         GL_LockArray(0, currentvertex);
791         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
792
793         if (currentmesh >= 2)
794         {
795                 for (k = 1, mesh = buf_mesh + k;k < currentmesh;k++, mesh++)
796                 {
797                         GL_MeshState(mesh);
798                         GL_DrawRangeElements(mesh->firstvert, mesh->firstvert + mesh->verts, mesh->triangles * 3, buf_tri[mesh->firsttriangle].index);CHECKGLERROR
799                 }
800         }
801
802         currentmesh = 0;
803         currenttriangle = 0;
804         currentvertex = 0;
805
806         GL_UnlockArray();CHECKGLERROR
807 }
808
809 // restores backend state, used when done with 3D rendering
810 void R_Mesh_Finish(void)
811 {
812         int i;
813         // flush any queued meshs
814         if (currentmesh)
815                 R_Mesh_Render();
816
817         if (backendunits > 1)
818         {
819                 for (i = backendunits - 1;i >= 0;i--)
820                 {
821                         qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
822                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
823                         if (gl_combine.integer)
824                         {
825                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
826                         }
827                         if (i > 0)
828                         {
829                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
830                         }
831                         else
832                         {
833                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
834                         }
835                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
836
837                         if (usedarrays)
838                         {
839                                 qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
840                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
841                         }
842                 }
843         }
844         else
845         {
846                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
847                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
848                 if (usedarrays)
849                 {
850                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
851                 }
852         }
853         if (usedarrays)
854         {
855                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
856                 qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
857         }
858
859         qglDisable(GL_BLEND);CHECKGLERROR
860         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
861         qglDepthMask(GL_TRUE);CHECKGLERROR
862         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
863 }
864
865 void R_Mesh_ClearDepth(void)
866 {
867         if (currenttransmesh)
868                 R_Mesh_AddTransparent();
869         if (currentmesh)
870                 R_Mesh_Render();
871         R_Mesh_Finish();
872         qglClear(GL_DEPTH_BUFFER_BIT);
873         R_Mesh_Start(r_mesh_farclip);
874 }
875
876 void R_Mesh_AddTransparent(void)
877 {
878         int i, j, k, *index;
879         float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
880         buf_vertex_t *vert1, *vert2, *vert3;
881         buf_transtri_t *tri;
882         buf_mesh_t *mesh, *transmesh;
883
884         if (!currenttransmesh)
885                 return;
886
887         // convert index data to transtris for sorting
888         for (j = 0;j < currenttransmesh;j++)
889         {
890                 mesh = buf_transmesh + j;
891                 k = mesh->firsttriangle;
892                 index = &buf_transtri[k].index[0];
893                 for (i = 0;i < mesh->triangles;i++)
894                 {
895                         tri = &buf_sorttranstri[k++];
896                         tri->mesh = mesh;
897                         tri->index[0] = *index++;
898                         tri->index[1] = *index++;
899                         tri->index[2] = *index++;
900                 }
901         }
902
903         // map farclip to 0-4095 list range
904         centerscaler = (TRANSDEPTHRES / r_mesh_farclip) * (1.0f / 3.0f);
905         viewdistcompare = viewdist + 4.0f;
906
907         memset(buf_sorttranstri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
908
909         k = 0;
910         for (j = 0;j < currenttranstriangle;j++)
911         {
912                 tri = &buf_sorttranstri[j];
913                 i = tri->mesh->firstvert;
914
915                 vert1 = &buf_transvertex[tri->index[0] + i];
916                 vert2 = &buf_transvertex[tri->index[1] + i];
917                 vert3 = &buf_transvertex[tri->index[2] + i];
918
919                 dist1 = DotProduct(vert1->v, vpn);
920                 dist2 = DotProduct(vert2->v, vpn);
921                 dist3 = DotProduct(vert3->v, vpn);
922
923                 maxdist = max(dist1, max(dist2, dist3));
924                 if (maxdist < viewdistcompare)
925                         continue;
926
927                 center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
928 #if SLOWMATH
929                 i = (int) center;
930                 i = bound(0, i, (TRANSDEPTHRES - 1));
931 #else
932                 if (center < 0.0f)
933                         center = 0.0f;
934                 center += 8388608.0f;
935                 i = *((int *)&center) & 0x7FFFFF;
936                 i = min(i, (TRANSDEPTHRES - 1));
937 #endif
938                 tri->next = buf_sorttranstri_list[i];
939                 buf_sorttranstri_list[i] = tri;
940                 k++;
941         }
942
943         for (i = 0;i < currenttransmesh;i++)
944                 buf_transmesh[i].transchain = NULL;
945         transmesh = NULL;
946         for (j = 0;j < TRANSDEPTHRES;j++)
947         {
948                 if ((tri = buf_sorttranstri_list[j]))
949                 {
950                         for (;tri;tri = tri->next)
951                         {
952                                 if (!tri->mesh->transchain)
953                                 {
954                                         tri->mesh->chain = transmesh;
955                                         transmesh = tri->mesh;
956                                 }
957                                 tri->meshsortchain = tri->mesh->transchain;
958                                 tri->mesh->transchain = tri;
959                         }
960                 }
961         }
962
963         R_Mesh_Render();
964         for (;transmesh;transmesh = transmesh->chain)
965         {
966                 mesh = &buf_mesh[currentmesh++];
967                 *mesh = *transmesh; // copy mesh properties
968
969                 mesh->firstvert = currentvertex;
970                 memcpy(&buf_vertex[currentvertex], &buf_transvertex[transmesh->firstvert], transmesh->verts * sizeof(buf_vertex_t));
971                 memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[transmesh->firstvert], transmesh->verts * sizeof(buf_fcolor_t));
972                 for (i = 0;i < backendunits && transmesh->textures[i];i++)
973                         memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][transmesh->firstvert], transmesh->verts * sizeof(buf_texcoord_t));
974                 currentvertex += mesh->verts;
975
976                 mesh->firsttriangle = currenttriangle;
977                 for (tri = transmesh->transchain;tri;tri = tri->meshsortchain)
978                 {
979                         buf_tri[currenttriangle].index[0] = tri->index[0];
980                         buf_tri[currenttriangle].index[1] = tri->index[1];
981                         buf_tri[currenttriangle].index[2] = tri->index[2];
982                         currenttriangle++;
983                 }
984                 mesh->triangles = currenttriangle - mesh->firsttriangle;
985                 R_Mesh_Render();
986         }
987
988         currenttransmesh = 0;
989         currenttranstriangle = 0;
990         currenttransvertex = 0;
991 }
992
993 // allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
994 // (this is used for very high speed rendering, no copying)
995 int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m, int wantoverbright)
996 {
997         // these are static because gcc runs out of virtual registers otherwise
998         int i, j, overbright;
999         float scaler;
1000         buf_mesh_t *mesh;
1001
1002         if (!backendactive)
1003                 Sys_Error("R_Mesh_Draw_GetBuffer: called when backend is not active\n");
1004
1005         if (!m->numtriangles
1006          || !m->numverts)
1007                 Host_Error("R_Mesh_Draw_GetBuffer: no triangles or verts\n");
1008
1009         // LordHavoc: removed this error condition because with floatcolors 0,
1010         // the 3DFX driver works with very large meshs
1011         // FIXME: we can work around this by falling back on non-array renderer if buffers are too big
1012         //if (m->numtriangles > 1024 || m->numverts > 3072)
1013         //{
1014         //      Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for 3DFX drivers, rejected\n");
1015         //      return false;
1016         //}
1017
1018         i = max(m->numtriangles * 3, m->numverts);
1019         if (overflowedverts < i)
1020                 overflowedverts = i;
1021
1022         if (m->numtriangles > max_meshs || m->numverts > max_verts)
1023         {
1024                 Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for current gl_mesh_maxtriangles setting, increasing limits\n");
1025                 return false;
1026         }
1027
1028         if (m->transparent)
1029         {
1030                 overflowedtransverts += max(m->numtriangles * 3, m->numverts);
1031                 if (currenttransmesh >= max_transmeshs || (currenttranstriangle + m->numtriangles) > max_transmeshs || (currenttransvertex + m->numverts) > max_transverts)
1032                 {
1033                         if (!transranout)
1034                         {
1035                                 Con_Printf("R_Mesh_Draw_GetBuffer: ran out of room for transparent meshs\n");
1036                                 transranout = true;
1037                         }
1038                         return false;
1039                 }
1040
1041                 c_transmeshs++;
1042                 c_transtris += m->numtriangles;
1043                 m->index = &buf_transtri[currenttranstriangle].index[0];
1044                 m->vertex = &buf_transvertex[currenttransvertex].v[0];
1045                 m->color = &buf_transfcolor[currenttransvertex].c[0];
1046                 for (i = 0;i < backendunits;i++)
1047                         m->texcoords[i] = &buf_transtexcoord[i][currenttransvertex].t[0];
1048
1049                 // transmesh is only for storage of transparent meshs until they
1050                 // are inserted into the main mesh array
1051                 mesh = &buf_transmesh[currenttransmesh++];
1052                 mesh->firsttriangle = currenttranstriangle;
1053                 mesh->firstvert = currenttransvertex;
1054                 currenttranstriangle += m->numtriangles;
1055                 currenttransvertex += m->numverts;
1056         }
1057         else
1058         {
1059                 if (currentmesh)
1060                 {
1061                         R_Mesh_Render();
1062                         Con_Printf("mesh queue not empty, flushing.\n");
1063                 }
1064
1065                 c_meshs++;
1066                 c_meshtris += m->numtriangles;
1067                 m->index = &buf_tri[currenttriangle].index[0];
1068                 m->vertex = &buf_vertex[currentvertex].v[0];
1069                 m->color = &buf_fcolor[currentvertex].c[0];
1070                 for (i = 0;i < backendunits;i++)
1071                         m->texcoords[i] = &buf_texcoord[i][currentvertex].t[0];
1072
1073                 // opaque meshs are rendered directly
1074                 mesh = &buf_mesh[currentmesh++];
1075                 mesh->firsttriangle = currenttriangle;
1076                 mesh->firstvert = currentvertex;
1077                 currenttriangle += m->numtriangles;
1078                 currentvertex += m->numverts;
1079         }
1080
1081         // code shared for transparent and opaque meshs
1082         mesh->blendfunc1 = m->blendfunc1;
1083         mesh->blendfunc2 = m->blendfunc2;
1084         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1085         mesh->depthtest = !m->depthdisable;
1086         mesh->triangles = m->numtriangles;
1087         mesh->verts = m->numverts;
1088
1089         overbright = false;
1090         scaler = 1;
1091         if (m->blendfunc1 == GL_DST_COLOR)
1092         {
1093                 // check if it is a 2x modulate with framebuffer
1094                 if (m->blendfunc2 == GL_SRC_COLOR)
1095                         scaler *= 0.5f;
1096         }
1097         else if (m->blendfunc2 != GL_SRC_COLOR)
1098         {
1099                 if (m->tex[0])
1100                 {
1101                         overbright = wantoverbright && gl_combine.integer;
1102                         if (overbright)
1103                                 scaler *= 0.25f;
1104                 }
1105                 scaler *= overbrightscale;
1106         }
1107         m->colorscale = scaler;
1108
1109         j = -1;
1110         for (i = 0;i < MAX_TEXTUREUNITS;i++)
1111         {
1112                 if ((mesh->textures[i] = m->tex[i]))
1113                 {
1114                         j = i;
1115                         if (i >= backendunits)
1116                                 Sys_Error("R_Mesh_Draw_GetBuffer: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1117                 }
1118                 mesh->texturergbscale[i] = m->texrgbscale[i];
1119                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1120                         mesh->texturergbscale[i] = 1;
1121         }
1122         if (overbright && j >= 0)
1123                 mesh->texturergbscale[j] = 4;
1124
1125         return true;
1126 }
1127
1128 /*
1129 ==============================================================================
1130
1131                                                 SCREEN SHOTS
1132
1133 ==============================================================================
1134 */
1135
1136 qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height)
1137 {
1138         qboolean ret;
1139         int i;
1140         qbyte *buffer;
1141
1142         if (!r_render.integer)
1143                 return false;
1144
1145         buffer = Mem_Alloc(tempmempool, width*height*3);
1146         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
1147         CHECKGLERROR
1148
1149         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
1150         if (v_hwgamma.integer)
1151                 for (i = 0;i < width * height * 3;i++)
1152                         buffer[i] <<= v_overbrightbits.integer;
1153
1154         ret = Image_WriteTGARGB_preflipped(filename, width, height, buffer);
1155
1156         Mem_Free(buffer);
1157         return ret;
1158 }
1159
1160 //=============================================================================
1161
1162 void R_ClearScreen(void)
1163 {
1164         if (r_render.integer)
1165         {
1166                 // clear to black
1167                 qglClearColor(0,0,0,0);CHECKGLERROR
1168                 // clear the screen
1169                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);CHECKGLERROR
1170                 // set dithering mode
1171                 if (gl_dither.integer)
1172                 {
1173                         qglEnable(GL_DITHER);CHECKGLERROR
1174                 }
1175                 else
1176                 {
1177                         qglDisable(GL_DITHER);CHECKGLERROR
1178                 }
1179         }
1180 }
1181
1182 /*
1183 ==================
1184 SCR_UpdateScreen
1185
1186 This is called every frame, and can also be called explicitly to flush
1187 text to the screen.
1188 ==================
1189 */
1190 void SCR_UpdateScreen (void)
1191 {
1192         VID_Finish ();
1193
1194         R_TimeReport("finish");
1195
1196         if (r_textureunits.integer > gl_textureunits)
1197                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1198         if (r_textureunits.integer < 1)
1199                 Cvar_SetValueQuick(&r_textureunits, 1);
1200
1201         if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
1202                 Cvar_SetValueQuick(&gl_combine, 0);
1203
1204         // lighting scale
1205         overbrightscale = 1.0f / (float) (1 << v_overbrightbits.integer);
1206
1207         // lightmaps only
1208         lightscalebit = v_overbrightbits.integer;
1209         if (gl_combine.integer && r_textureunits.integer > 1)
1210                 lightscalebit += 2;
1211         lightscale = 1.0f / (float) (1 << lightscalebit);
1212
1213         R_TimeReport("setup");
1214
1215         R_ClearScreen();
1216
1217         R_TimeReport("clear");
1218
1219         if (scr_conlines < vid.conheight)
1220                 R_RenderView();
1221
1222         // draw 2D stuff
1223         R_DrawQueue();
1224
1225         // tell driver to commit it's partially full geometry queue to the rendering queue
1226         // (this doesn't wait for the commands themselves to complete)
1227         qglFlush();
1228 }
1229