moved a lot of 2D/screen stuff out of gl_screen.c into cl_screen.c
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3
4 cvar_t          r_render = {0, "r_render", "1"};
5 cvar_t          gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
6
7 int                     lightscalebit;
8 float           lightscale;
9 float           overbrightscale;
10
11 void SCR_ScreenShot_f (void);
12 static void R_Envmap_f (void);
13
14 static int max_meshs;
15 static int max_batch;
16 static int max_verts; // always max_meshs * 3
17 #define TRANSDEPTHRES 4096
18
19 //#define FLOATCOLORS
20
21 //static cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "21760"};
22 static cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "8192"};
23 static cvar_t gl_mesh_batchtriangles = {0, "gl_mesh_batchtriangles", "1024"};
24 static cvar_t gl_mesh_merge = {0, "gl_mesh_merge", "1"};
25 #if FLOATCOLORS
26 static cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
27 #endif
28 static cvar_t gl_mesh_dupetransverts = {0, "gl_mesh_dupetransverts", "0"};
29 static cvar_t gl_mesh_sorttransbymesh = {0, "gl_mesh_sorttransbymesh", "1"};
30
31 typedef struct buf_mesh_s
32 {
33         //struct buf_mesh_s *next;
34         int depthmask;
35         int depthtest;
36         int blendfunc1, blendfunc2;
37         int textures[MAX_TEXTUREUNITS];
38         float texturergbscale[MAX_TEXTUREUNITS];
39         int firsttriangle;
40         int triangles;
41         int firstvert;
42         int lastvert;
43         struct buf_mesh_s *chain;
44         struct buf_transtri_s *transchain;
45         //struct buf_transtri_s **transchainpointer;
46 }
47 buf_mesh_t;
48
49 typedef struct buf_transtri_s
50 {
51         struct buf_transtri_s *next;
52         struct buf_transtri_s *meshsortchain;
53         buf_mesh_t *mesh;
54         int index[3];
55 }
56 buf_transtri_t;
57
58 typedef struct buf_tri_s
59 {
60         int index[3];
61 }
62 buf_tri_t;
63
64 typedef struct
65 {
66         float v[4];
67 }
68 buf_vertex_t;
69
70 #if FLOATCOLORS
71 typedef struct
72 {
73         float c[4];
74 }
75 buf_fcolor_t;
76 #endif
77
78 typedef struct
79 {
80         byte c[4];
81 }
82 buf_bcolor_t;
83
84 typedef struct
85 {
86         float t[2];
87 }
88 buf_texcoord_t;
89
90 static float meshfarclip;
91 static int currentmesh, currenttriangle, currentvertex, backendunits, backendactive, meshmerge, transranout;
92 #if FLOATCOLORS
93 static int floatcolors;
94 #endif
95 static buf_mesh_t *buf_mesh;
96 static buf_tri_t *buf_tri;
97 static buf_vertex_t *buf_vertex;
98 #if FLOATCOLORS
99 static buf_fcolor_t *buf_fcolor;
100 #endif
101 static buf_bcolor_t *buf_bcolor;
102 static buf_texcoord_t *buf_texcoord[MAX_TEXTUREUNITS];
103
104 static int currenttransmesh, currenttransvertex, currenttranstriangle;
105 static buf_mesh_t *buf_transmesh;
106 static buf_transtri_t *buf_transtri;
107 static buf_transtri_t **buf_transtri_list;
108 static buf_vertex_t *buf_transvertex;
109 #if FLOATCOLORS
110 static buf_fcolor_t *buf_transfcolor;
111 #endif
112 static buf_bcolor_t *buf_transbcolor;
113 static buf_texcoord_t *buf_transtexcoord[MAX_TEXTUREUNITS];
114
115 static mempool_t *gl_backend_mempool;
116 static int resizingbuffers = false;
117
118 static void gl_backend_start(void)
119 {
120         int i;
121
122         max_verts = max_meshs * 3;
123
124         if (!gl_backend_mempool)
125                 gl_backend_mempool = Mem_AllocPool("GL_Backend");
126
127 #define BACKENDALLOC(var, count, sizeofstruct)\
128         {\
129                 var = Mem_Alloc(gl_backend_mempool, count * sizeof(sizeofstruct));\
130                 if (var == NULL)\
131                         Sys_Error("gl_backend_start: unable to allocate memory\n");\
132                 memset(var, 0, count * sizeof(sizeofstruct));\
133         }
134
135         BACKENDALLOC(buf_mesh, max_meshs, buf_mesh_t)
136         BACKENDALLOC(buf_tri, max_meshs, buf_tri_t)
137         BACKENDALLOC(buf_vertex, max_verts, buf_vertex_t)
138 #if FLOATCOLORS
139         BACKENDALLOC(buf_fcolor, max_verts, buf_fcolor_t)
140 #endif
141         BACKENDALLOC(buf_bcolor, max_verts, buf_bcolor_t)
142
143         BACKENDALLOC(buf_transmesh, max_meshs, buf_mesh_t)
144         BACKENDALLOC(buf_transtri, max_meshs, buf_transtri_t)
145         BACKENDALLOC(buf_transtri_list, TRANSDEPTHRES, buf_transtri_t *)
146         BACKENDALLOC(buf_transvertex, max_verts, buf_vertex_t)
147 #if FLOATCOLORS
148         BACKENDALLOC(buf_transfcolor, max_verts, buf_fcolor_t)
149 #endif
150         BACKENDALLOC(buf_transbcolor, max_verts, buf_bcolor_t)
151
152         for (i = 0;i < MAX_TEXTUREUNITS;i++)
153         {
154                 // only allocate as many texcoord arrays as we need
155                 if (i < gl_textureunits)
156                 {
157                         BACKENDALLOC(buf_texcoord[i], max_verts, buf_texcoord_t)
158                         BACKENDALLOC(buf_transtexcoord[i], max_verts, buf_texcoord_t)
159                 }
160                 else
161                 {
162                         buf_texcoord[i] = NULL;
163                         buf_transtexcoord[i] = NULL;
164                 }
165         }
166         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
167         backendactive = true;
168 }
169
170 static void gl_backend_shutdown(void)
171 {
172         //int i;
173         /*
174 #define BACKENDFREE(var)\
175         if (var)\
176         {\
177                 Mem_Free(var);\
178                 var = NULL;\
179         }
180         */
181         /*
182 #define BACKENDFREE(var) var = NULL;
183
184         BACKENDFREE(buf_mesh)
185         BACKENDFREE(buf_tri)
186         BACKENDFREE(buf_vertex)
187 #if FLOATCOLORS
188         BACKENDFREE(buf_fcolor)
189 #endif
190         BACKENDFREE(buf_bcolor)
191
192         BACKENDFREE(buf_transmesh)
193         BACKENDFREE(buf_transtri)
194         BACKENDFREE(buf_transtri_list)
195         BACKENDFREE(buf_transvertex)
196 #if FLOATCOLORS
197         BACKENDFREE(buf_transfcolor)
198 #endif
199         BACKENDFREE(buf_transbcolor)
200
201         for (i = 0;i < MAX_TEXTUREUNITS;i++)
202         {
203                 BACKENDFREE(buf_texcoord[i])
204                 BACKENDFREE(buf_transtexcoord[i])
205         }
206         */
207
208         if (resizingbuffers)
209                 Mem_EmptyPool(gl_backend_mempool);
210         else
211                 Mem_FreePool(&gl_backend_mempool);
212
213         backendunits = 0;
214         backendactive = false;
215 }
216
217 static void gl_backend_bufferchanges(int init)
218 {
219         // 21760 is (65536 / 3) rounded off to a multiple of 128
220         if (gl_mesh_maxtriangles.integer < 256)
221                 Cvar_SetValue("gl_mesh_maxtriangles", 256);
222         if (gl_mesh_maxtriangles.integer > 21760)
223                 Cvar_SetValue("gl_mesh_maxtriangles", 21760);
224
225         if (gl_mesh_batchtriangles.integer < 0)
226                 Cvar_SetValue("gl_mesh_batchtriangles", 0);
227         if (gl_mesh_batchtriangles.integer > gl_mesh_maxtriangles.integer)
228                 Cvar_SetValue("gl_mesh_batchtriangles", gl_mesh_maxtriangles.integer);
229
230         max_batch = gl_mesh_batchtriangles.integer;
231
232         if (max_meshs != gl_mesh_maxtriangles.integer)
233         {
234                 max_meshs = gl_mesh_maxtriangles.integer;
235
236                 if (!init)
237                 {
238                         resizingbuffers = true;
239                         gl_backend_shutdown();
240                         gl_backend_start();
241                         resizingbuffers = false;
242                 }
243         }
244 }
245
246 float r_farclip, r_newfarclip;
247
248 static void gl_backend_newmap(void)
249 {
250         r_farclip = r_newfarclip = 2048.0f;
251 }
252
253 int polyindexarray[768];
254
255 void gl_backend_init(void)
256 {
257         int i;
258
259         Cvar_RegisterVariable (&r_render);
260         Cvar_RegisterVariable (&gl_dither);
261 #ifdef NORENDER
262         Cvar_SetValue("r_render", 0);
263 #endif
264
265         Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
266         Cmd_AddCommand ("envmap", R_Envmap_f);
267
268         Cvar_RegisterVariable(&gl_mesh_maxtriangles);
269         Cvar_RegisterVariable(&gl_mesh_batchtriangles);
270         Cvar_RegisterVariable(&gl_mesh_merge);
271 #if FLOATCOLORS
272         Cvar_RegisterVariable(&gl_mesh_floatcolors);
273 #endif
274         Cvar_RegisterVariable(&gl_mesh_dupetransverts);
275         Cvar_RegisterVariable(&gl_mesh_sorttransbymesh);
276         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
277         gl_backend_bufferchanges(true);
278         for (i = 0;i < 256;i++)
279         {
280                 polyindexarray[i*3+0] = 0;
281                 polyindexarray[i*3+1] = i + 1;
282                 polyindexarray[i*3+2] = i + 2;
283         }
284 }
285
286 static void MYgluPerspective(GLdouble fovx, GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar )
287 {
288         GLdouble xmax, ymax;
289
290         xmax = zNear * tan( fovx * M_PI / 360.0 ) * aspect;
291         ymax = zNear * tan( fovy * M_PI / 360.0 );
292
293         glFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar );
294 }
295
296
297 /*
298 =============
299 GL_SetupFrame
300 =============
301 */
302 static void GL_SetupFrame (void)
303 {
304         if (!r_render.integer)
305                 return;
306
307 //      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: moved to SCR_UpdateScreen
308         gldepthmin = 0;
309         gldepthmax = 1;
310         glDepthFunc (GL_LEQUAL);
311
312         glDepthRange (gldepthmin, gldepthmax);
313
314         // update farclip based on previous frame
315         r_farclip = r_newfarclip;
316
317         // set up viewpoint
318         glMatrixMode(GL_PROJECTION);
319         glLoadIdentity ();
320
321         // y is weird beause OpenGL is bottom to top, we use top to bottom
322         glViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);
323 //      yfov = 2*atan((float)r_refdef.height/r_refdef.width)*180/M_PI;
324         MYgluPerspective (r_refdef.fov_x, r_refdef.fov_y, r_refdef.width/r_refdef.height, 4, r_farclip);
325
326         glCullFace(GL_FRONT);
327
328         glMatrixMode(GL_MODELVIEW);
329         glLoadIdentity ();
330
331         glRotatef (-90,  1, 0, 0);          // put Z going up
332         glRotatef (90,  0, 0, 1);           // put Z going up
333         glRotatef (-r_refdef.viewangles[2],  1, 0, 0);
334         glRotatef (-r_refdef.viewangles[0],  0, 1, 0);
335         glRotatef (-r_refdef.viewangles[1],  0, 0, 1);
336         glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);
337
338 //      glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
339
340         //
341         // set drawing parms
342         //
343 //      if (gl_cull.integer)
344                 glEnable(GL_CULL_FACE);
345 //      else
346 //              glDisable(GL_CULL_FACE);
347
348         glEnable(GL_BLEND); // was Disable
349         glEnable(GL_DEPTH_TEST);
350         glDepthMask(1);
351 }
352
353 static float viewdist;
354
355 int c_meshs, c_meshtris, c_transmeshs, c_transtris;
356
357 // called at beginning of frame
358 void R_Mesh_Clear(void)
359 {
360         if (!backendactive)
361                 Sys_Error("R_Mesh_Clear: called when backend is not active\n");
362
363         gl_backend_bufferchanges(false);
364
365         currentmesh = 0;
366         currenttriangle = 0;
367         currentvertex = 0;
368         currenttransmesh = 0;
369         currenttranstriangle = 0;
370         currenttransvertex = 0;
371         meshfarclip = 0;
372         meshmerge = gl_mesh_merge.integer;
373 #if FLOATCOLORS
374         floatcolors = gl_mesh_floatcolors.integer;
375 #endif
376         transranout = false;
377         viewdist = DotProduct(r_origin, vpn);
378
379         c_meshs = 0;
380         c_meshtris = 0;
381         c_transmeshs = 0;
382         c_transtris = 0;
383
384         GL_SetupFrame();
385 }
386
387 #ifdef DEBUGGL
388 void GL_PrintError(int errornumber, char *filename, int linenumber)
389 {
390         switch(errornumber)
391         {
392         case GL_INVALID_ENUM:
393                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
394                 break;
395         case GL_INVALID_VALUE:
396                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
397                 break;
398         case GL_INVALID_OPERATION:
399                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
400                 break;
401         case GL_STACK_OVERFLOW:
402                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
403                 break;
404         case GL_STACK_UNDERFLOW:
405                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
406                 break;
407         case GL_OUT_OF_MEMORY:
408                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
409                 break;
410 #ifdef GL_TABLE_TOO_LARGE
411     case GL_TABLE_TOO_LARGE:
412                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
413                 break;
414 #endif
415         default:
416                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
417                 break;
418         }
419 }
420
421 int errornumber = 0;
422 #endif
423
424 // renders mesh buffers, called to flush buffers when full
425 void R_Mesh_Render(void)
426 {
427         int i, k, blendfunc1, blendfunc2, blend, depthmask, depthtest, unit = 0, clientunit = 0, firsttriangle, triangles, firstvert, lastvert, texture[MAX_TEXTUREUNITS];
428         float farclip, texturergbscale[MAX_TEXTUREUNITS];
429         buf_mesh_t *mesh;
430         if (!backendactive)
431                 Sys_Error("R_Mesh_Render: called when backend is not active\n");
432         if (!currentmesh)
433                 return;
434
435 CHECKGLERROR
436
437         // push out farclip based on vertices
438         for (i = 0;i < currentvertex;i++)
439         {
440                 farclip = DotProduct(buf_vertex[i].v, vpn);
441                 if (meshfarclip < farclip)
442                         meshfarclip = farclip;
443         }
444
445         farclip = meshfarclip + 256.0f - viewdist; // + 256 just to be safe
446
447         // push out farclip for next frame
448         if (farclip > r_newfarclip)
449                 r_newfarclip = ceil((farclip + 255) / 256) * 256 + 256;
450
451         for (i = 0;i < backendunits;i++)
452                 texturergbscale[i] = 1;
453
454         glEnable(GL_CULL_FACE);
455 CHECKGLERROR
456         glCullFace(GL_FRONT);
457 CHECKGLERROR
458         depthtest = true;
459         glEnable(GL_DEPTH_TEST);
460 CHECKGLERROR
461         blendfunc1 = GL_ONE;
462         blendfunc2 = GL_ZERO;
463         glBlendFunc(blendfunc1, blendfunc2);
464 CHECKGLERROR
465         blend = 0;
466         glDisable(GL_BLEND);
467 CHECKGLERROR
468         depthmask = true;
469         glDepthMask((GLboolean) depthmask);
470 CHECKGLERROR
471
472         glVertexPointer(3, GL_FLOAT, sizeof(buf_vertex_t), buf_vertex);
473 CHECKGLERROR
474         glEnableClientState(GL_VERTEX_ARRAY);
475 CHECKGLERROR
476 #if FLOATCOLORS
477         if (floatcolors)
478         {
479                 glColorPointer(4, GL_FLOAT, sizeof(buf_fcolor_t), buf_fcolor);
480 CHECKGLERROR
481         }
482         else
483         {
484 #endif
485                 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(buf_bcolor_t), buf_bcolor);
486 CHECKGLERROR
487 #if FLOATCOLORS
488         }
489 #endif
490         glEnableClientState(GL_COLOR_ARRAY);
491 CHECKGLERROR
492
493         if (backendunits > 1)
494         {
495                 for (i = 0;i < backendunits;i++)
496                 {
497                         qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
498 CHECKGLERROR
499                         glBindTexture(GL_TEXTURE_2D, (texture[i] = 0));
500 CHECKGLERROR
501                         glDisable(GL_TEXTURE_2D);
502 CHECKGLERROR
503                         if (gl_combine.integer)
504                         {
505                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
506 CHECKGLERROR
507                                 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
508 CHECKGLERROR
509                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
510 CHECKGLERROR
511                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
512 CHECKGLERROR
513                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);
514 CHECKGLERROR
515                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
516 CHECKGLERROR
517                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
518 CHECKGLERROR
519                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);
520 CHECKGLERROR
521                                 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
522 CHECKGLERROR
523                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
524 CHECKGLERROR
525                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
526 CHECKGLERROR
527                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);
528 CHECKGLERROR
529                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
530 CHECKGLERROR
531                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
532 CHECKGLERROR
533                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
534 CHECKGLERROR
535                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
536 CHECKGLERROR
537                                 glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0f);
538 CHECKGLERROR
539                         }
540                         else
541                         {
542                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
543 CHECKGLERROR
544                         }
545
546                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
547 CHECKGLERROR
548                         glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[i]);
549 CHECKGLERROR
550                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
551 CHECKGLERROR
552                 }
553         }
554         else
555         {
556                 glBindTexture(GL_TEXTURE_2D, (texture[0] = 0));
557 CHECKGLERROR
558                 glDisable(GL_TEXTURE_2D);
559 CHECKGLERROR
560                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
561 CHECKGLERROR
562
563                 glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[0]);
564 CHECKGLERROR
565                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
566 CHECKGLERROR
567         }
568
569         // lock as early as possible
570         GL_LockArray(0, currentvertex);
571 CHECKGLERROR
572
573         for (k = 0;k < currentmesh;)
574         {
575                 mesh = &buf_mesh[k];
576
577                 if (backendunits > 1)
578                 {
579 //                      int topunit = 0;
580                         for (i = 0;i < backendunits;i++)
581                         {
582                                 if (texture[i] != mesh->textures[i])
583                                 {
584                                         if (unit != i)
585                                         {
586                                                 qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
587 CHECKGLERROR
588                                         }
589                                         if (texture[i] == 0)
590                                         {
591                                                 glEnable(GL_TEXTURE_2D);
592 CHECKGLERROR
593                                                 // have to disable texcoord array on disabled texture
594                                                 // units due to NVIDIA driver bug with
595                                                 // compiled_vertex_array
596                                                 if (clientunit != i)
597                                                 {
598                                                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
599 CHECKGLERROR
600                                                 }
601                                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
602 CHECKGLERROR
603                                         }
604                                         glBindTexture(GL_TEXTURE_2D, (texture[i] = mesh->textures[i]));
605 CHECKGLERROR
606                                         if (texture[i] == 0)
607                                         {
608                                                 glDisable(GL_TEXTURE_2D);
609 CHECKGLERROR
610                                                 // have to disable texcoord array on disabled texture
611                                                 // units due to NVIDIA driver bug with
612                                                 // compiled_vertex_array
613                                                 if (clientunit != i)
614                                                 {
615                                                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
616 CHECKGLERROR
617                                                 }
618                                                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
619 CHECKGLERROR
620                                         }
621                                 }
622                                 if (texturergbscale[i] != mesh->texturergbscale[i])
623                                 {
624                                         if (unit != i)
625                                         {
626                                                 qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
627 CHECKGLERROR
628                                         }
629                                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (texturergbscale[i] = mesh->texturergbscale[i]));
630 CHECKGLERROR
631                                 }
632 //                              if (texture[i])
633 //                                      topunit = i;
634                         }
635 //                      if (unit != topunit)
636 //                      {
637 //                              qglActiveTexture(GL_TEXTURE0_ARB + (unit = topunit));
638 //CHECKGLERROR
639 //                      }
640                 }
641                 else
642                 {
643                         if (texture[0] != mesh->textures[0])
644                         {
645                                 if (texture[0] == 0)
646                                 {
647                                         glEnable(GL_TEXTURE_2D);
648 CHECKGLERROR
649                                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
650 CHECKGLERROR
651                                 }
652                                 glBindTexture(GL_TEXTURE_2D, (texture[0] = mesh->textures[0]));
653 CHECKGLERROR
654                                 if (texture[0] == 0)
655                                 {
656                                         glDisable(GL_TEXTURE_2D);
657 CHECKGLERROR
658                                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
659 CHECKGLERROR
660                                 }
661                         }
662                 }
663                 if (blendfunc1 != mesh->blendfunc1 || blendfunc2 != mesh->blendfunc2)
664                 {
665                         blendfunc1 = mesh->blendfunc1;
666                         blendfunc2 = mesh->blendfunc2;
667                         glBlendFunc(blendfunc1, blendfunc2);
668 CHECKGLERROR
669                         if (blendfunc2 == GL_ZERO)
670                         {
671                                 if (blendfunc1 == GL_ONE)
672                                 {
673                                         if (blend)
674                                         {
675                                                 blend = 0;
676                                                 glDisable(GL_BLEND);
677 CHECKGLERROR
678                                         }
679                                 }
680                                 else
681                                 {
682                                         if (!blend)
683                                         {
684                                                 blend = 1;
685                                                 glEnable(GL_BLEND);
686 CHECKGLERROR
687                                         }
688                                 }
689                         }
690                         else
691                         {
692                                 if (!blend)
693                                 {
694                                         blend = 1;
695                                         glEnable(GL_BLEND);
696 CHECKGLERROR
697                                 }
698                         }
699                 }
700                 if (depthtest != mesh->depthtest)
701                 {
702                         depthtest = mesh->depthtest;
703                         if (depthtest)
704                                 glEnable(GL_DEPTH_TEST);
705                         else
706                                 glDisable(GL_DEPTH_TEST);
707                 }
708                 if (depthmask != mesh->depthmask)
709                 {
710                         depthmask = mesh->depthmask;
711                         glDepthMask((GLboolean) depthmask);
712 CHECKGLERROR
713                 }
714
715                 firsttriangle = mesh->firsttriangle;
716                 triangles = mesh->triangles;
717                 firstvert = mesh->firstvert;
718                 lastvert = mesh->lastvert;
719                 mesh = &buf_mesh[++k];
720
721                 if (meshmerge)
722                 {
723                         #if MAX_TEXTUREUNITS != 4
724                         #error update this code
725                         #endif
726                         while (k < currentmesh
727                                 && mesh->blendfunc1 == blendfunc1
728                                 && mesh->blendfunc2 == blendfunc2
729                                 && mesh->depthtest == depthtest
730                                 && mesh->depthmask == depthmask
731                                 && mesh->textures[0] == texture[0]
732                                 && mesh->textures[1] == texture[1]
733                                 && mesh->textures[2] == texture[2]
734                                 && mesh->textures[3] == texture[3]
735                                 && mesh->texturergbscale[0] == texturergbscale[0]
736                                 && mesh->texturergbscale[1] == texturergbscale[1]
737                                 && mesh->texturergbscale[2] == texturergbscale[2]
738                                 && mesh->texturergbscale[3] == texturergbscale[3])
739                         {
740                                 triangles += mesh->triangles;
741                                 if (firstvert > mesh->firstvert)
742                                         firstvert = mesh->firstvert;
743                                 if (lastvert < mesh->lastvert)
744                                         lastvert = mesh->lastvert;
745                                 mesh = &buf_mesh[++k];
746                         }
747                 }
748
749 #ifdef WIN32
750                 // FIXME: dynamic link to GL so we can get DrawRangeElements on WIN32
751                 glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_INT, (unsigned int *)&buf_tri[firsttriangle]);
752 #else
753                 glDrawRangeElements(GL_TRIANGLES, firstvert, lastvert + 1, triangles * 3, GL_UNSIGNED_INT, (unsigned int *)&buf_tri[firsttriangle]);
754 #endif
755 CHECKGLERROR
756         }
757
758         currentmesh = 0;
759         currenttriangle = 0;
760         currentvertex = 0;
761
762         GL_UnlockArray();
763 CHECKGLERROR
764
765         if (backendunits > 1)
766         {
767                 for (i = backendunits - 1;i >= 0;i--)
768                 {
769                         qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
770 CHECKGLERROR
771                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
772 CHECKGLERROR
773                         if (gl_combine.integer)
774                         {
775                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
776 CHECKGLERROR
777                         }
778                         if (i > 0)
779                         {
780                                 glDisable(GL_TEXTURE_2D);
781 CHECKGLERROR
782                         }
783                         else
784                         {
785                                 glEnable(GL_TEXTURE_2D);
786 CHECKGLERROR
787                         }
788                         glBindTexture(GL_TEXTURE_2D, 0);
789 CHECKGLERROR
790
791                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
792 CHECKGLERROR
793                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
794 CHECKGLERROR
795                 }
796         }
797         else
798         {
799                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
800 CHECKGLERROR
801                 glEnable(GL_TEXTURE_2D);
802 CHECKGLERROR
803                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
804 CHECKGLERROR
805         }
806         glDisableClientState(GL_COLOR_ARRAY);
807 CHECKGLERROR
808         glDisableClientState(GL_VERTEX_ARRAY);
809 CHECKGLERROR
810
811         glDisable(GL_BLEND);
812 CHECKGLERROR
813         glEnable(GL_DEPTH_TEST);
814 CHECKGLERROR
815         glDepthMask(true);
816 CHECKGLERROR
817         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
818 CHECKGLERROR
819 }
820
821 void R_Mesh_AddTransparent(void)
822 {
823         if (gl_mesh_sorttransbymesh.integer)
824         {
825                 int i, j, k;
826                 float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
827                 buf_vertex_t *vert1, *vert2, *vert3;
828                 buf_transtri_t *tri;
829                 buf_mesh_t *mesh, *transmesh;
830
831                 // process and add transparent mesh triangles
832                 if (!currenttranstriangle)
833                         return;
834
835                 // map farclip to 0-4095 list range
836                 centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
837                 viewdistcompare = viewdist + 4.0f;
838
839                 memset(buf_transtri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
840
841                 k = 0;
842                 for (j = 0;j < currenttranstriangle;j++)
843                 {
844                         tri = &buf_transtri[j];
845
846                         vert1 = &buf_transvertex[tri->index[0]];
847                         vert2 = &buf_transvertex[tri->index[1]];
848                         vert3 = &buf_transvertex[tri->index[2]];
849
850                         dist1 = DotProduct(vert1->v, vpn);
851                         dist2 = DotProduct(vert2->v, vpn);
852                         dist3 = DotProduct(vert3->v, vpn);
853
854                         maxdist = max(dist1, max(dist2, dist3));
855                         if (maxdist < viewdistcompare)
856                                 continue;
857
858                         center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
859         #if SLOWMATH
860                         i = (int) center;
861                         i = bound(0, i, (TRANSDEPTHRES - 1));
862         #else
863                         if (center < 0.0f)
864                                 center = 0.0f;
865                         center += 8388608.0f;
866                         i = *((long *)&center) & 0x7FFFFF;
867                         i = min(i, (TRANSDEPTHRES - 1));
868         #endif
869                         tri->next = buf_transtri_list[i];
870                         buf_transtri_list[i] = tri;
871                         k++;
872                 }
873
874                 #ifndef TRANSBATCH
875                 if (currentmesh + k > max_meshs || currenttriangle + k > max_batch || currentvertex + currenttransvertex > max_verts)
876                         R_Mesh_Render();
877
878                 // note: can't batch these because they can be rendered in any order
879                 // there can never be more transparent triangles than fit in main buffers
880                 memcpy(&buf_vertex[currentvertex], &buf_transvertex[0], currenttransvertex * sizeof(buf_vertex_t));
881 #if FLOATCOLORS
882                 if (floatcolors)
883                         memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[0], currenttransvertex * sizeof(buf_fcolor_t));
884                 else
885 #endif
886                         memcpy(&buf_bcolor[currentvertex], &buf_transbcolor[0], currenttransvertex * sizeof(buf_bcolor_t));
887                 for (i = 0;i < backendunits;i++)
888                         memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][0], currenttransvertex * sizeof(buf_texcoord_t));
889                 #endif
890
891                 for (i = 0;i < currenttransmesh;i++)
892                 {
893                         buf_transmesh[i].transchain = NULL;
894                         //buf_transmesh[i].transchainpointer = &buf_transmesh[i].transchain;
895                         buf_transmesh[i].triangles = 0;
896                 }
897                 transmesh = NULL;
898                 for (j = 0;j < TRANSDEPTHRES;j++)
899                 {
900                         if ((tri = buf_transtri_list[j]))
901                         {
902                                 for (;tri;tri = tri->next)
903                                 {
904                                         if (!tri->mesh->transchain)
905                                         {
906                                                 tri->mesh->chain = transmesh;
907                                                 transmesh = tri->mesh;
908                                         }
909                                         tri->meshsortchain = tri->mesh->transchain;
910                                         tri->mesh->transchain = tri;
911                                         /*
912                                         *tri->mesh->transchainpointer = tri;
913                                         tri->meshsortchain = NULL;
914                                         tri->mesh->transchainpointer = &tri->meshsortchain;
915                                         */
916                                         tri->mesh->triangles++;
917                                 }
918                         }
919                 }
920
921                 #if TRANSBATCH
922                 for (;transmesh;transmesh = transmesh->chain)
923                 {
924                         int meshvertexadjust;
925                         int numverts = transmesh->lastvert - transmesh->firstvert + 1;
926                         if (currentmesh >= max_meshs || currenttriangle + transmesh->triangles > max_batch || currentvertex + numverts > max_verts)
927                                 R_Mesh_Render();
928
929                         memcpy(&buf_vertex[currentvertex], &buf_transvertex[transmesh->firstvert], numverts * sizeof(buf_vertex_t));
930 #if FLOATCOLORS
931                         if (floatcolors)
932                                 memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[transmesh->firstvert], numverts * sizeof(buf_fcolor_t));
933                         else
934 #endif
935                                 memcpy(&buf_bcolor[currentvertex], &buf_transbcolor[transmesh->firstvert], numverts * sizeof(buf_bcolor_t));
936                         for (i = 0;i < backendunits && transmesh->textures[i];i++)
937                                 memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][transmesh->firstvert], numverts * sizeof(buf_texcoord_t));
938
939                         mesh = &buf_mesh[currentmesh++];
940                         *mesh = *transmesh; // copy mesh properties
941                         mesh->firstvert = currentvertex;
942                         mesh->lastvert = currentvertex + numverts - 1;
943                         currentvertex += numverts;
944                         meshvertexadjust = mesh->firstvert - transmesh->firstvert;
945                         mesh->firsttriangle = currenttriangle;
946                         for (tri = transmesh->transchain;tri;tri = tri->meshsortchain)
947                         {
948                                 buf_tri[currenttriangle].index[0] = tri->index[0] + meshvertexadjust;
949                                 buf_tri[currenttriangle].index[1] = tri->index[1] + meshvertexadjust;
950                                 buf_tri[currenttriangle].index[2] = tri->index[2] + meshvertexadjust;
951                                 /*
952                                 if (tri->mesh != transmesh)
953                                         Sys_Error("!?!");
954                                 if ((unsigned int) buf_tri[currenttriangle].index[0] < (unsigned int) mesh->firstvert
955                                  || (unsigned int) buf_tri[currenttriangle].index[0] > (unsigned int) mesh->lastvert
956                                  || (unsigned int) buf_tri[currenttriangle].index[1] < (unsigned int) mesh->firstvert
957                                  || (unsigned int) buf_tri[currenttriangle].index[1] > (unsigned int) mesh->lastvert
958                                  || (unsigned int) buf_tri[currenttriangle].index[2] < (unsigned int) mesh->firstvert
959                                  || (unsigned int) buf_tri[currenttriangle].index[2] > (unsigned int) mesh->lastvert)
960                                         Sys_Error("!?");
961                                 */
962                                 currenttriangle++;
963                         }
964                         /*
965                         if (mesh->triangles != currenttriangle - mesh->firsttriangle)
966                                 Sys_Error("!");
967                         */
968                 }
969                 #else
970                 for (;transmesh;transmesh = transmesh->chain)
971                 {
972                         mesh = &buf_mesh[currentmesh++];
973                         *mesh = *transmesh; // copy mesh properties
974                         mesh->firstvert += currentvertex;
975                         mesh->lastvert += currentvertex;
976                         mesh->firsttriangle = currenttriangle;
977                         for (tri = transmesh->transchain;tri;tri = tri->meshsortchain)
978                         {
979                                 buf_tri[currenttriangle].index[0] = tri->index[0] + currentvertex;
980                                 buf_tri[currenttriangle].index[1] = tri->index[1] + currentvertex;
981                                 buf_tri[currenttriangle].index[2] = tri->index[2] + currentvertex;
982                                 /*
983                                 if (tri->mesh != transmesh)
984                                         Sys_Error("!?!");
985                                 if ((unsigned int) buf_tri[currenttriangle].index[0] < (unsigned int) mesh->firstvert
986                                  || (unsigned int) buf_tri[currenttriangle].index[0] > (unsigned int) mesh->lastvert
987                                  || (unsigned int) buf_tri[currenttriangle].index[1] < (unsigned int) mesh->firstvert
988                                  || (unsigned int) buf_tri[currenttriangle].index[1] > (unsigned int) mesh->lastvert
989                                  || (unsigned int) buf_tri[currenttriangle].index[2] < (unsigned int) mesh->firstvert
990                                  || (unsigned int) buf_tri[currenttriangle].index[2] > (unsigned int) mesh->lastvert)
991                                         Sys_Error("!?");
992                                 */
993                                 currenttriangle++;
994                         }
995                         /*
996                         if (mesh->triangles != currenttriangle - mesh->firsttriangle)
997                                 Sys_Error("!");
998                         */
999                 }
1000                 currentvertex += currenttransvertex;
1001                 #endif
1002
1003                 currenttransmesh = 0;
1004                 currenttranstriangle = 0;
1005                 currenttransvertex = 0;
1006         }
1007         else if (gl_mesh_dupetransverts.integer)
1008         {
1009                 int i, j, k, index;
1010                 float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
1011                 buf_vertex_t *vert1, *vert2, *vert3;
1012                 buf_transtri_t *tri;
1013                 buf_mesh_t *mesh;
1014
1015                 // process and add transparent mesh triangles
1016                 if (!currenttranstriangle)
1017                         return;
1018
1019                 // map farclip to 0-4095 list range
1020                 centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
1021                 viewdistcompare = viewdist + 4.0f;
1022
1023                 memset(buf_transtri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
1024
1025                 // process in reverse because transtri_list adding code is in reverse as well
1026                 k = 0;
1027                 for (j = currenttranstriangle - 1;j >= 0;j--)
1028                 {
1029                         tri = &buf_transtri[j];
1030
1031                         vert1 = &buf_transvertex[tri->index[0]];
1032                         vert2 = &buf_transvertex[tri->index[1]];
1033                         vert3 = &buf_transvertex[tri->index[2]];
1034
1035                         dist1 = DotProduct(vert1->v, vpn);
1036                         dist2 = DotProduct(vert2->v, vpn);
1037                         dist3 = DotProduct(vert3->v, vpn);
1038
1039                         maxdist = max(dist1, max(dist2, dist3));
1040                         if (maxdist < viewdistcompare)
1041                                 continue;
1042
1043                         center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
1044         #if SLOWMATH
1045                         i = (int) center;
1046                         i = bound(0, i, (TRANSDEPTHRES - 1));
1047         #else
1048                         if (center < 0.0f)
1049                                 center = 0.0f;
1050                         center += 8388608.0f;
1051                         i = *((long *)&center) & 0x7FFFFF;
1052                         i = min(i, (TRANSDEPTHRES - 1));
1053         #endif
1054                         tri->next = buf_transtri_list[i];
1055                         buf_transtri_list[i] = tri;
1056                         k++;
1057                 }
1058
1059                 if (currentmesh + k > max_meshs || currenttriangle + k > max_batch || currentvertex + k * 3 > max_verts)
1060                         R_Mesh_Render();
1061
1062                 currenttransmesh = 0;
1063                 currenttranstriangle = 0;
1064                 currenttransvertex = 0;
1065
1066                 // note: can't batch these because they can be rendered in any order
1067                 // there can never be more transparent triangles than fit in main buffers
1068                 for (j = TRANSDEPTHRES - 1;j >= 0;j--)
1069                 {
1070                         if ((tri = buf_transtri_list[j]))
1071                         {
1072                                 while(tri)
1073                                 {
1074                                         mesh = &buf_mesh[currentmesh++];
1075                                         *mesh = *tri->mesh; // copy mesh properties
1076                                         mesh->firstvert = currentvertex;
1077                                         mesh->lastvert = currentvertex + 2;
1078                                         mesh->firsttriangle = currenttriangle;
1079                                         mesh->triangles = 1;
1080                                         for (k = 0;k < 3;k++)
1081                                         {
1082                                                 index = tri->index[k];
1083                                                 buf_tri[currenttriangle].index[k] = currentvertex;
1084                                                 memcpy(buf_vertex[currentvertex].v, buf_transvertex[index].v, sizeof(buf_vertex_t));
1085 #if FLOATCOLORS
1086                                                 if (floatcolors)
1087                                                         memcpy(buf_fcolor[currentvertex].c, buf_transfcolor[index].c, sizeof(buf_fcolor_t));
1088                                                 else
1089 #endif
1090                                                         memcpy(buf_bcolor[currentvertex].c, buf_transbcolor[index].c, sizeof(buf_bcolor_t));
1091                                                 for (i = 0;i < backendunits && tri->mesh->textures[i];i++)
1092                                                         memcpy(buf_texcoord[i][currentvertex].t, buf_transtexcoord[i][index].t, sizeof(buf_texcoord_t));
1093                                                 currentvertex++;
1094                                         }
1095                                         currenttriangle++;
1096                                         tri = tri->next;
1097                                 }
1098                         }
1099                 }
1100         }
1101         else
1102         {
1103                 int i, j, k;
1104                 float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
1105                 buf_vertex_t *vert1, *vert2, *vert3;
1106                 buf_transtri_t *tri;
1107                 buf_mesh_t *mesh;
1108
1109                 // process and add transparent mesh triangles
1110                 if (!currenttranstriangle)
1111                         return;
1112
1113                 // map farclip to 0-4095 list range
1114                 centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
1115                 viewdistcompare = viewdist + 4.0f;
1116
1117                 memset(buf_transtri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
1118
1119                 // process in reverse because transtri_list adding code is in reverse as well
1120                 k = 0;
1121                 for (j = currenttranstriangle - 1;j >= 0;j--)
1122                 {
1123                         tri = &buf_transtri[j];
1124
1125                         vert1 = &buf_transvertex[tri->index[0]];
1126                         vert2 = &buf_transvertex[tri->index[1]];
1127                         vert3 = &buf_transvertex[tri->index[2]];
1128
1129                         dist1 = DotProduct(vert1->v, vpn);
1130                         dist2 = DotProduct(vert2->v, vpn);
1131                         dist3 = DotProduct(vert3->v, vpn);
1132
1133                         maxdist = max(dist1, max(dist2, dist3));
1134                         if (maxdist < viewdistcompare)
1135                                 continue;
1136
1137                         center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
1138         #if SLOWMATH
1139                         i = (int) center;
1140                         i = bound(0, i, (TRANSDEPTHRES - 1));
1141         #else
1142                         if (center < 0.0f)
1143                                 center = 0.0f;
1144                         center += 8388608.0f;
1145                         i = *((long *)&center) & 0x7FFFFF;
1146                         i = min(i, (TRANSDEPTHRES - 1));
1147         #endif
1148                         tri->next = buf_transtri_list[i];
1149                         buf_transtri_list[i] = tri;
1150                         k++;
1151                 }
1152
1153                 if (currentmesh + k > max_meshs || currenttriangle + k > max_batch || currentvertex + currenttransvertex > max_verts)
1154                         R_Mesh_Render();
1155
1156                 // note: can't batch these because they can be rendered in any order
1157                 // there can never be more transparent triangles than fit in main buffers
1158                 memcpy(&buf_vertex[currentvertex], &buf_transvertex[0], currenttransvertex * sizeof(buf_vertex_t));
1159 #if FLOATCOLORS
1160                 if (floatcolors)
1161                         memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[0], currenttransvertex * sizeof(buf_fcolor_t));
1162                 else
1163 #endif
1164                         memcpy(&buf_bcolor[currentvertex], &buf_transbcolor[0], currenttransvertex * sizeof(buf_bcolor_t));
1165                 for (i = 0;i < backendunits;i++)
1166                         memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][0], currenttransvertex * sizeof(buf_texcoord_t));
1167
1168                 for (j = TRANSDEPTHRES - 1;j >= 0;j--)
1169                 {
1170                         if ((tri = buf_transtri_list[j]))
1171                         {
1172                                 while(tri)
1173                                 {
1174                                         mesh = &buf_mesh[currentmesh++];
1175                                         *mesh = *tri->mesh; // copy mesh properties
1176                                         buf_tri[currenttriangle].index[0] = tri->index[0] + currentvertex;
1177                                         buf_tri[currenttriangle].index[1] = tri->index[1] + currentvertex;
1178                                         buf_tri[currenttriangle].index[2] = tri->index[2] + currentvertex;
1179                                         mesh->firstvert = min(buf_tri[currenttriangle].index[0], min(buf_tri[currenttriangle].index[1], buf_tri[currenttriangle].index[2]));
1180                                         mesh->lastvert = max(buf_tri[currenttriangle].index[0], max(buf_tri[currenttriangle].index[1], buf_tri[currenttriangle].index[2]));
1181                                         mesh->firsttriangle = currenttriangle++;
1182                                         mesh->triangles = 1;
1183                                         tri = tri->next;
1184                                 }
1185                         }
1186                 }
1187                 currentvertex += currenttransvertex;
1188                 currenttransmesh = 0;
1189                 currenttranstriangle = 0;
1190                 currenttransvertex = 0;
1191         }
1192 }
1193
1194 void R_Mesh_Draw(const rmeshinfo_t *m)
1195 {
1196         // these are static because gcc runs out of virtual registers otherwise
1197         static int i, j, *index, overbright;
1198         static float c, *in, scaler;
1199 #if FLOATCOLORS
1200         static float cr, cg, cb, ca;
1201 #endif
1202         static buf_mesh_t *mesh;
1203         static buf_vertex_t *vert;
1204 #if FLOATCOLORS
1205         static buf_fcolor_t *fcolor;
1206 #endif
1207         static buf_bcolor_t *bcolor;
1208         static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
1209         static buf_transtri_t *tri;
1210         static buf_bcolor_t flatbcolor;
1211
1212         if (m->index == NULL
1213          || !m->numtriangles
1214          || m->vertex == NULL
1215          || !m->numverts)
1216                 return;
1217         // ignore meaningless alpha meshs
1218         if (!m->depthwrite && m->blendfunc1 == GL_SRC_ALPHA && (m->blendfunc2 == GL_ONE || m->blendfunc2 == GL_ONE_MINUS_SRC_ALPHA))
1219         {
1220                 if (m->color)
1221                 {
1222                         for (i = 0, in = m->color + 3;i < m->numverts;i++, (int)in += m->colorstep)
1223                                 if (*in >= 0.01f)
1224                                         break;
1225                         if (i == m->numverts)
1226                                 return;
1227                 }
1228                 else if (m->ca < 0.01f)
1229                         return;
1230         }
1231
1232         if (!backendactive)
1233                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
1234
1235         scaler = 1;
1236         if (m->blendfunc2 == GL_SRC_COLOR)
1237         {
1238                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
1239                         scaler *= 0.5f;
1240         }
1241         else
1242         {
1243                 if (m->tex[0])
1244                 {
1245                         overbright = gl_combine.integer;
1246                         if (overbright)
1247                                 scaler *= 0.25f;
1248                 }
1249                 scaler *= overbrightscale;
1250         }
1251
1252         if (m->transparent)
1253         {
1254                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
1255                 {
1256                         if (!transranout)
1257                         {
1258                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
1259                                 transranout = true;
1260                         }
1261                         return;
1262                 }
1263
1264                 c_transmeshs++;
1265                 c_transtris += m->numtriangles;
1266                 vert = &buf_transvertex[currenttransvertex];
1267 #if FLOATCOLORS
1268                 fcolor = &buf_transfcolor[currenttransvertex];
1269 #endif
1270                 bcolor = &buf_transbcolor[currenttransvertex];
1271                 for (i = 0;i < backendunits;i++)
1272                         texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
1273
1274                 // transmesh is only for storage of transparent meshs until they
1275                 // are inserted into the main mesh array
1276                 mesh = &buf_transmesh[currenttransmesh++];
1277
1278                 // transparent meshs are broken up into individual triangles which can
1279                 // be sorted by depth
1280                 index = m->index;
1281                 for (i = 0;i < m->numtriangles;i++)
1282                 {
1283                         tri = &buf_transtri[currenttranstriangle++];
1284                         tri->mesh = mesh;
1285                         tri->index[0] = *index++ + currenttransvertex;
1286                         tri->index[1] = *index++ + currenttransvertex;
1287                         tri->index[2] = *index++ + currenttransvertex;
1288                 }
1289
1290                 mesh->firstvert = currenttransvertex;
1291                 mesh->lastvert = currenttransvertex + m->numverts - 1;
1292                 currenttransvertex += m->numverts;
1293         }
1294         else
1295         {
1296                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
1297                 {
1298                         Con_Printf("R_Mesh_Draw: mesh too big for buffers\n");
1299                         return;
1300                 }
1301
1302                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
1303                         R_Mesh_Render();
1304
1305                 c_meshs++;
1306                 c_meshtris += m->numtriangles;
1307                 vert = &buf_vertex[currentvertex];
1308 #if FLOATCOLORS
1309                 fcolor = &buf_fcolor[currentvertex];
1310 #endif
1311                 bcolor = &buf_bcolor[currentvertex];
1312                 for (i = 0;i < backendunits;i++)
1313                         texcoord[i] = &buf_texcoord[i][currentvertex];
1314
1315                 mesh = &buf_mesh[currentmesh++];
1316                 // opaque meshs are rendered directly
1317                 index = (int *)&buf_tri[currenttriangle];
1318                 mesh->firsttriangle = currenttriangle;
1319                 currenttriangle += m->numtriangles;
1320                 for (i = 0;i < m->numtriangles * 3;i++)
1321                         index[i] = m->index[i] + currentvertex;
1322
1323                 mesh->firstvert = currentvertex;
1324                 mesh->lastvert = currentvertex + m->numverts - 1;
1325                 currentvertex += m->numverts;
1326         }
1327
1328         // code shared for transparent and opaque meshs
1329         mesh->blendfunc1 = m->blendfunc1;
1330         mesh->blendfunc2 = m->blendfunc2;
1331         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1332         mesh->depthtest = !m->depthdisable;
1333         mesh->triangles = m->numtriangles;
1334         j = -1;
1335         for (i = 0;i < backendunits;i++)
1336         {
1337                 if ((mesh->textures[i] = m->tex[i]))
1338                         j = i;
1339                 mesh->texturergbscale[i] = m->texrgbscale[i];
1340                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1341                         mesh->texturergbscale[i] = 1;
1342         }
1343         if (overbright && j >= 0)
1344                 mesh->texturergbscale[j] = 4;
1345
1346         if (m->vertexstep != sizeof(buf_vertex_t))
1347         {
1348                 for (i = 0, in = m->vertex;i < m->numverts;i++, (int)in += m->vertexstep)
1349                 {
1350                         vert[i].v[0] = in[0];
1351                         vert[i].v[1] = in[1];
1352                         vert[i].v[2] = in[2];
1353                 }
1354         }
1355         else
1356                 memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
1357
1358 #if FLOATCOLORS
1359         if (floatcolors)
1360         {
1361                 if (m->color)
1362                 {
1363                         for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
1364                         {
1365                                 fcolor[i].c[0] = in[0] * scaler;
1366                                 fcolor[i].c[1] = in[1] * scaler;
1367                                 fcolor[i].c[2] = in[2] * scaler;
1368                                 fcolor[i].c[3] = in[3];
1369                         }
1370                 }
1371                 else
1372                 {
1373                         cr = m->cr * scaler;
1374                         cg = m->cg * scaler;
1375                         cb = m->cb * scaler;
1376                         ca = m->ca;
1377                         for (i = 0;i < m->numverts;i++)
1378                         {
1379                                 fcolor[i].c[0] = cr;
1380                                 fcolor[i].c[1] = cg;
1381                                 fcolor[i].c[2] = cb;
1382                                 fcolor[i].c[3] = ca;
1383                         }
1384                 }
1385         }
1386         else
1387         {
1388 #endif
1389                 if (m->color)
1390                 {
1391                         for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
1392                         {
1393                                 // shift float to have 8bit fraction at base of number,
1394                                 // then read as integer and kill float bits...
1395                                 c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[0] = (byte) j;
1396                                 c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[1] = (byte) j;
1397                                 c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[2] = (byte) j;
1398                                 c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[3] = (byte) j;
1399                         }
1400                 }
1401                 else
1402                 {
1403                         c = m->cr * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[0] = (byte) j;
1404                         c = m->cg * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[1] = (byte) j;
1405                         c = m->cb * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[2] = (byte) j;
1406                         c = m->ca          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[3] = (byte) j;
1407                         for (i = 0;i < m->numverts;i++)
1408                                 bcolor[i] = flatbcolor;
1409                 }
1410 #if FLOATCOLORS
1411         }
1412 #endif
1413
1414         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1415         {
1416                 if (j >= backendunits)
1417                         Sys_Error("R_Mesh_Draw: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1418                 if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
1419                 {
1420                         for (i = 0, in = m->texcoords[j];i < m->numverts;i++, (int)in += m->texcoordstep[j])
1421                         {
1422                                 texcoord[j][i].t[0] = in[0];
1423                                 texcoord[j][i].t[1] = in[1];
1424                         }
1425                 }
1426                 else
1427                         memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
1428         }
1429         #if 0
1430         for (;j < backendunits;j++)
1431                 memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
1432         #endif
1433 }
1434
1435 void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
1436 {
1437         m->index = polyindexarray;
1438         m->numverts = numverts;
1439         m->numtriangles = numverts - 2;
1440         if (m->numtriangles < 1)
1441         {
1442                 Con_Printf("R_Mesh_DrawPolygon: invalid vertex count\n");
1443                 return;
1444         }
1445         if (m->numtriangles >= 256)
1446         {
1447                 Con_Printf("R_Mesh_DrawPolygon: only up to 256 triangles (258 verts) supported\n");
1448                 return;
1449         }
1450         R_Mesh_Draw(m);
1451 }
1452
1453 // LordHavoc: this thing is evil, but necessary because decals account for so much overhead
1454 void R_Mesh_DrawDecal(const rmeshinfo_t *m)
1455 {
1456         // these are static because gcc runs out of virtual registers otherwise
1457         static int i, j, *index, overbright;
1458         static float c, scaler;
1459 #if FLOATCOLORS
1460         static float cr, cg, cb, ca;
1461 #endif
1462         static buf_mesh_t *mesh;
1463         static buf_vertex_t *vert;
1464 #if FLOATCOLORS
1465         static buf_fcolor_t *fcolor;
1466 #endif
1467         static buf_bcolor_t *bcolor;
1468         static buf_texcoord_t *texcoord;
1469         static buf_transtri_t *tri;
1470         static buf_bcolor_t flatbcolor;
1471
1472         if (!backendactive)
1473                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
1474
1475         scaler = 1;
1476         if (m->tex[0])
1477         {
1478                 overbright = gl_combine.integer;
1479                 if (overbright)
1480                         scaler *= 0.25f;
1481         }
1482         scaler *= overbrightscale;
1483
1484         if (m->transparent)
1485         {
1486                 if (currenttransmesh >= max_meshs || (currenttranstriangle + 2) > max_meshs || (currenttransvertex + 4) > max_verts)
1487                 {
1488                         if (!transranout)
1489                         {
1490                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
1491                                 transranout = true;
1492                         }
1493                         return;
1494                 }
1495
1496                 c_transmeshs++;
1497                 c_transtris += 2;
1498                 vert = &buf_transvertex[currenttransvertex];
1499 #if FLOATCOLORS
1500                 fcolor = &buf_transfcolor[currenttransvertex];
1501 #endif
1502                 bcolor = &buf_transbcolor[currenttransvertex];
1503                 texcoord = &buf_transtexcoord[0][currenttransvertex];
1504
1505                 // transmesh is only for storage of transparent meshs until they
1506                 // are inserted into the main mesh array
1507                 mesh = &buf_transmesh[currenttransmesh++];
1508                 mesh->blendfunc1 = m->blendfunc1;
1509                 mesh->blendfunc2 = m->blendfunc2;
1510                 mesh->depthmask = false;
1511                 mesh->depthtest = true;
1512                 mesh->triangles = 2;
1513                 mesh->textures[0] = m->tex[0];
1514                 mesh->texturergbscale[0] = overbright ? 4 : 1;
1515                 for (i = 1;i < backendunits;i++)
1516                 {
1517                         mesh->textures[i] = 0;
1518                         mesh->texturergbscale[i] = 1;
1519                 }
1520                 mesh->chain = NULL;
1521
1522                 // transparent meshs are broken up into individual triangles which can
1523                 // be sorted by depth
1524                 index = m->index;
1525                 tri = &buf_transtri[currenttranstriangle++];
1526                 tri->mesh = mesh;
1527                 tri->index[0] = 0 + currenttransvertex;
1528                 tri->index[1] = 1 + currenttransvertex;
1529                 tri->index[2] = 2 + currenttransvertex;
1530                 tri = &buf_transtri[currenttranstriangle++];
1531                 tri->mesh = mesh;
1532                 tri->index[0] = 0 + currenttransvertex;
1533                 tri->index[1] = 2 + currenttransvertex;
1534                 tri->index[2] = 3 + currenttransvertex;
1535
1536                 mesh->firstvert = currenttransvertex;
1537                 mesh->lastvert = currenttransvertex + 3;
1538                 currenttransvertex += 4;
1539         }
1540         else
1541         {
1542                 if (2 > max_meshs || 4 > max_verts)
1543                 {
1544                         Con_Printf("R_Mesh_Draw: mesh too big for buffers\n");
1545                         return;
1546                 }
1547
1548                 if (currentmesh >= max_meshs || (currenttriangle + 2) > max_batch || (currentvertex + 4) > max_verts)
1549                         R_Mesh_Render();
1550
1551                 c_meshs++;
1552                 c_meshtris += 2;
1553                 vert = &buf_vertex[currentvertex];
1554 #if FLOATCOLORS
1555                 fcolor = &buf_fcolor[currentvertex];
1556 #endif
1557                 bcolor = &buf_bcolor[currentvertex];
1558                 texcoord = &buf_texcoord[0][currentvertex];
1559
1560                 mesh = &buf_mesh[currentmesh++];
1561                 mesh->blendfunc1 = m->blendfunc1;
1562                 mesh->blendfunc2 = m->blendfunc2;
1563                 mesh->depthmask = false;
1564                 mesh->depthtest = !m->depthdisable;
1565                 mesh->firsttriangle = currenttriangle;
1566                 mesh->triangles = 2;
1567                 mesh->textures[0] = m->tex[0];
1568                 mesh->texturergbscale[0] = overbright ? 4 : 1;
1569                 for (i = 1;i < backendunits;i++)
1570                 {
1571                         mesh->textures[i] = 0;
1572                         mesh->texturergbscale[i] = 1;
1573                 }
1574
1575                 // opaque meshs are rendered directly
1576                 index = (int *)&buf_tri[currenttriangle];
1577                 index[0] = 0 + currentvertex;
1578                 index[1] = 1 + currentvertex;
1579                 index[2] = 2 + currentvertex;
1580                 index[3] = 0 + currentvertex;
1581                 index[4] = 2 + currentvertex;
1582                 index[5] = 3 + currentvertex;
1583                 mesh->firstvert = currentvertex;
1584                 mesh->lastvert = currentvertex + 3;
1585                 currenttriangle += 2;
1586                 currentvertex += 4;
1587         }
1588
1589         // buf_vertex_t must match the size of the decal vertex array (or vice versa)
1590         memcpy(vert, m->vertex, 4 * sizeof(buf_vertex_t));
1591
1592 #if FLOATCOLORS
1593         if (floatcolors)
1594         {
1595                 cr = m->cr * scaler;
1596                 cg = m->cg * scaler;
1597                 cb = m->cb * scaler;
1598                 ca = m->ca;
1599                 fcolor[0].c[0] = cr;
1600                 fcolor[0].c[1] = cg;
1601                 fcolor[0].c[2] = cb;
1602                 fcolor[0].c[3] = ca;
1603                 fcolor[1].c[0] = cr;
1604                 fcolor[1].c[1] = cg;
1605                 fcolor[1].c[2] = cb;
1606                 fcolor[1].c[3] = ca;
1607                 fcolor[2].c[0] = cr;
1608                 fcolor[2].c[1] = cg;
1609                 fcolor[2].c[2] = cb;
1610                 fcolor[2].c[3] = ca;
1611                 fcolor[3].c[0] = cr;
1612                 fcolor[3].c[1] = cg;
1613                 fcolor[3].c[2] = cb;
1614                 fcolor[3].c[3] = ca;
1615         }
1616         else
1617         {
1618 #endif
1619                 c = m->cr * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[0] = (byte) j;
1620                 c = m->cg * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[1] = (byte) j;
1621                 c = m->cb * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[2] = (byte) j;
1622                 c = m->ca          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;flatbcolor.c[3] = (byte) j;
1623                 bcolor[0] = flatbcolor;
1624                 bcolor[1] = flatbcolor;
1625                 bcolor[2] = flatbcolor;
1626                 bcolor[3] = flatbcolor;
1627 #if FLOATCOLORS
1628         }
1629 #endif
1630
1631         // buf_texcoord_t must be the same size as the decal texcoord array (or vice versa)
1632         memcpy(&texcoord[0].t[0], m->texcoords[0], 4 * sizeof(buf_texcoord_t));
1633 }
1634
1635 /*
1636 ==============================================================================
1637
1638                                                 SCREEN SHOTS
1639
1640 ==============================================================================
1641 */
1642
1643 float CalcFov (float fov_x, float width, float height);
1644 void R_ClearScreen(void);
1645
1646 void SCR_ScreenShot(char *filename, int x, int y, int width, int height)
1647 {
1648         int i;
1649         byte *buffer;
1650
1651         buffer = Mem_Alloc(tempmempool, width*height*3);
1652         glReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
1653         CHECKGLERROR
1654
1655         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
1656         if (v_hwgamma.integer)
1657                 for (i = 0;i < width * height * 3;i++)
1658                         buffer[i] <<= v_overbrightbits.integer;
1659
1660         Image_WriteTGARGB_preflipped(filename, width, height, buffer);
1661
1662         Mem_Free(buffer);
1663 }
1664
1665 /*
1666 ==================
1667 SCR_ScreenShot_f
1668 ==================
1669 */
1670 void SCR_ScreenShot_f (void)
1671 {
1672         int i;
1673         char filename[16];
1674         char checkname[MAX_OSPATH];
1675 //
1676 // find a file name to save it to
1677 //
1678         strcpy(filename, "dp0000.tga");
1679
1680         for (i=0 ; i<=9999 ; i++)
1681         {
1682                 filename[2] = (i/1000)%10 + '0';
1683                 filename[3] = (i/ 100)%10 + '0';
1684                 filename[4] = (i/  10)%10 + '0';
1685                 filename[5] = (i/   1)%10 + '0';
1686                 sprintf (checkname, "%s/%s", com_gamedir, filename);
1687                 if (Sys_FileTime(checkname) == -1)
1688                         break;  // file doesn't exist
1689         }
1690         if (i==10000)
1691         {
1692                 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
1693                 return;
1694         }
1695
1696         SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight);
1697         Con_Printf ("Wrote %s\n", filename);
1698 }
1699
1700 /*
1701 ===============
1702 R_Envmap_f
1703
1704 Grab six views for environment mapping tests
1705 ===============
1706 */
1707 struct
1708 {
1709         float angles[3];
1710         char *name;
1711 }
1712 envmapinfo[6] =
1713 {
1714         {{  0,   0, 0}, "ft"},
1715         {{  0,  90, 0}, "rt"},
1716         {{  0, 180, 0}, "bk"},
1717         {{  0, 270, 0}, "lf"},
1718         {{-90,  90, 0}, "up"},
1719         {{ 90,  90, 0}, "dn"}
1720 };
1721 static void R_Envmap_f (void)
1722 {
1723         int j, size;
1724         char filename[256], basename[256];
1725
1726         if (Cmd_Argc() != 3)
1727         {
1728                 Con_Printf ("envmap <basename> <size>: save out 6 cubic environment map images, usable with loadsky, note that size must one of 128, 256, 512, or 1024 and can't be bigger than your current resolution\n");
1729                 return;
1730         }
1731
1732         if (!r_render.integer)
1733                 return;
1734
1735         strcpy(basename, Cmd_Argv(1));
1736         size = atoi(Cmd_Argv(2));
1737         if (size != 128 && size != 256 && size != 512 && size != 1024)
1738         {
1739                 Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
1740                 return;
1741         }
1742         if (size > vid.realwidth || size > vid.realheight)
1743         {
1744                 Con_Printf("envmap: your resolution is not big enough to render that size\n");
1745                 return;
1746         }
1747
1748         envmap = true;
1749
1750         r_refdef.x = 0;
1751         r_refdef.y = 0;
1752         r_refdef.width = size;
1753         r_refdef.height = size;
1754
1755         r_refdef.fov_x = 90;
1756         r_refdef.fov_y = 90;
1757
1758         for (j = 0;j < 6;j++)
1759         {
1760                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1761                 VectorCopy(envmapinfo[j].angles, r_refdef.viewangles);
1762                 R_ClearScreen();
1763                 R_RenderView ();
1764                 SCR_ScreenShot(filename, vid.realx, vid.realy, size, size);
1765         }
1766
1767         envmap = false;
1768 }
1769
1770 //=============================================================================
1771
1772 void R_ClearScreen(void)
1773 {
1774         if (r_render.integer)
1775         {
1776                 glClearColor(0,0,0,0);
1777                 CHECKGLERROR
1778                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
1779                 CHECKGLERROR
1780                 if (gl_dither.integer)
1781                         glEnable(GL_DITHER);
1782                 else
1783                         glDisable(GL_DITHER);
1784                 CHECKGLERROR
1785         }
1786 }
1787
1788 /*
1789 ==================
1790 SCR_UpdateScreen
1791
1792 This is called every frame, and can also be called explicitly to flush
1793 text to the screen.
1794 ==================
1795 */
1796 void SCR_UpdateScreen (void)
1797 {
1798         //Mem_CheckSentinelsGlobal();
1799         //R_TimeReport("memtest");
1800
1801         glFinish ();
1802         CHECKGLERROR
1803
1804         VID_Finish ();
1805
1806         R_TimeReport("finish");
1807
1808         if (gl_combine.integer && !gl_combine_extension)
1809                 Cvar_SetValue("gl_combine", 0);
1810
1811         lightscalebit = v_overbrightbits.integer;
1812         if (gl_combine.integer && r_multitexture.integer)
1813                 lightscalebit += 2;
1814
1815         lightscale = 1.0f / (float) (1 << lightscalebit);
1816         overbrightscale = 1.0f / (float) (1 << v_overbrightbits.integer);
1817
1818         R_TimeReport("setup");
1819
1820         R_ClearScreen();
1821
1822         R_TimeReport("clear");
1823
1824         if (scr_conlines < vid.conheight)
1825                 R_RenderView();
1826
1827         // draw 2D stuff
1828         R_DrawQueue();
1829 }