]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
added athlon CPU choice (for gcc 2.96 and up)
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3
4 //cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "21760"};
5 cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "8192"};
6 //cvar_t gl_mesh_batchtriangles = {0, "gl_mesh_batchtriangles", "1024"};
7 cvar_t gl_mesh_batchtriangles = {0, "gl_mesh_batchtriangles", "0"};
8 cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "0"};
9
10 cvar_t r_render = {0, "r_render", "1"};
11 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
12 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
13
14 #ifdef DEBUGGL
15 int errornumber = 0;
16
17 void GL_PrintError(int errornumber, char *filename, int linenumber)
18 {
19         switch(errornumber)
20         {
21 #ifdef GL_INVALID_ENUM
22         case GL_INVALID_ENUM:
23                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
24                 break;
25 #endif
26 #ifdef GL_INVALID_VALUE
27         case GL_INVALID_VALUE:
28                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
29                 break;
30 #endif
31 #ifdef GL_INVALID_OPERATION
32         case GL_INVALID_OPERATION:
33                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
34                 break;
35 #endif
36 #ifdef GL_STACK_OVERFLOW
37         case GL_STACK_OVERFLOW:
38                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
39                 break;
40 #endif
41 #ifdef GL_STACK_UNDERFLOW
42         case GL_STACK_UNDERFLOW:
43                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
44                 break;
45 #endif
46 #ifdef GL_OUT_OF_MEMORY
47         case GL_OUT_OF_MEMORY:
48                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
49                 break;
50 #endif
51 #ifdef GL_TABLE_TOO_LARGE
52     case GL_TABLE_TOO_LARGE:
53                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
54                 break;
55 #endif
56         default:
57                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
58                 break;
59         }
60 }
61 #endif
62
63 float r_farclip, r_newfarclip;
64
65 int polyindexarray[768];
66
67 static float viewdist;
68
69 int c_meshs, c_meshtris, c_transmeshs, c_transtris;
70
71 int                     lightscalebit;
72 float           lightscale;
73 float           overbrightscale;
74
75 void SCR_ScreenShot_f (void);
76
77 static int max_meshs;
78 static int max_batch;
79 static int max_verts; // always max_meshs * 3
80 #define TRANSDEPTHRES 4096
81
82 typedef struct buf_mesh_s
83 {
84         int depthmask;
85         int depthtest;
86         int blendfunc1, blendfunc2;
87         int textures[MAX_TEXTUREUNITS];
88         float texturergbscale[MAX_TEXTUREUNITS];
89         int firsttriangle;
90         int triangles;
91         int firstvert;
92         int verts;
93         struct buf_mesh_s *chain;
94         struct buf_transtri_s *transchain;
95 }
96 buf_mesh_t;
97
98 typedef struct buf_transtri_s
99 {
100         struct buf_transtri_s *next;
101         struct buf_transtri_s *meshsortchain;
102         buf_mesh_t *mesh;
103         int index[3];
104 }
105 buf_transtri_t;
106
107 typedef struct buf_tri_s
108 {
109         int index[3];
110 }
111 buf_tri_t;
112
113 typedef struct
114 {
115         float v[4];
116 }
117 buf_vertex_t;
118
119 typedef struct
120 {
121         float c[4];
122 }
123 buf_fcolor_t;
124
125 typedef struct
126 {
127         qbyte c[4];
128 }
129 buf_bcolor_t;
130
131 typedef struct
132 {
133         float t[2];
134 }
135 buf_texcoord_t;
136
137 static float meshfarclip;
138 static int currentmesh, currenttriangle, currentvertex, backendunits, backendactive, transranout;
139 static buf_mesh_t *buf_mesh;
140 static buf_tri_t *buf_tri;
141 static buf_vertex_t *buf_vertex;
142 static buf_fcolor_t *buf_fcolor;
143 static buf_bcolor_t *buf_bcolor;
144 static buf_texcoord_t *buf_texcoord[MAX_TEXTUREUNITS];
145
146 static int currenttransmesh, currenttransvertex, currenttranstriangle;
147 static buf_mesh_t *buf_transmesh;
148 static buf_transtri_t *buf_sorttranstri;
149 static buf_transtri_t **buf_sorttranstri_list;
150 static buf_tri_t *buf_transtri;
151 static buf_vertex_t *buf_transvertex;
152 static buf_fcolor_t *buf_transfcolor;
153 static buf_texcoord_t *buf_transtexcoord[MAX_TEXTUREUNITS];
154
155 static mempool_t *gl_backend_mempool;
156 static int resizingbuffers = false;
157
158 static void gl_backend_start(void)
159 {
160         int i;
161
162         max_verts = max_meshs * 3;
163
164         if (!gl_backend_mempool)
165                 gl_backend_mempool = Mem_AllocPool("GL_Backend");
166
167 #define BACKENDALLOC(var, count, sizeofstruct)\
168         {\
169                 var = Mem_Alloc(gl_backend_mempool, count * sizeof(sizeofstruct));\
170                 if (var == NULL)\
171                         Sys_Error("gl_backend_start: unable to allocate memory\n");\
172                 memset(var, 0, count * sizeof(sizeofstruct));\
173         }
174
175         BACKENDALLOC(buf_mesh, max_meshs, buf_mesh_t)
176         BACKENDALLOC(buf_tri, max_meshs, buf_tri_t)
177         BACKENDALLOC(buf_vertex, max_verts, buf_vertex_t)
178         BACKENDALLOC(buf_fcolor, max_verts, buf_fcolor_t)
179         BACKENDALLOC(buf_bcolor, max_verts, buf_bcolor_t)
180
181         BACKENDALLOC(buf_transmesh, max_meshs, buf_mesh_t)
182         BACKENDALLOC(buf_sorttranstri, max_meshs, buf_transtri_t)
183         BACKENDALLOC(buf_sorttranstri_list, TRANSDEPTHRES, buf_transtri_t *)
184         BACKENDALLOC(buf_transtri, max_meshs, buf_tri_t)
185         BACKENDALLOC(buf_transvertex, max_verts, buf_vertex_t)
186         BACKENDALLOC(buf_transfcolor, max_verts, buf_fcolor_t)
187
188         for (i = 0;i < MAX_TEXTUREUNITS;i++)
189         {
190                 // only allocate as many texcoord arrays as we need
191                 if (i < gl_textureunits)
192                 {
193                         BACKENDALLOC(buf_texcoord[i], max_verts, buf_texcoord_t)
194                         BACKENDALLOC(buf_transtexcoord[i], max_verts, buf_texcoord_t)
195                 }
196                 else
197                 {
198                         buf_texcoord[i] = NULL;
199                         buf_transtexcoord[i] = NULL;
200                 }
201         }
202         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
203         backendactive = true;
204 }
205
206 static void gl_backend_shutdown(void)
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 static void gl_backend_newmap(void)
247 {
248         r_farclip = r_newfarclip = 2048.0f;
249 }
250
251 void gl_backend_init(void)
252 {
253         int i;
254
255         Cvar_RegisterVariable(&r_render);
256         Cvar_RegisterVariable(&gl_dither);
257         Cvar_RegisterVariable(&gl_lockarrays);
258 #ifdef NORENDER
259         Cvar_SetValue("r_render", 0);
260 #endif
261
262         Cvar_RegisterVariable(&gl_mesh_maxtriangles);
263         Cvar_RegisterVariable(&gl_mesh_batchtriangles);
264         Cvar_RegisterVariable(&gl_mesh_floatcolors);
265         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
266         gl_backend_bufferchanges(true);
267         for (i = 0;i < 256;i++)
268         {
269                 polyindexarray[i*3+0] = 0;
270                 polyindexarray[i*3+1] = i + 1;
271                 polyindexarray[i*3+2] = i + 2;
272         }
273 }
274
275 int arraylocked = false;
276
277 void GL_LockArray(int first, int count)
278 {
279         if (!arraylocked && gl_supportslockarrays && gl_lockarrays.integer)
280         {
281                 qglLockArraysEXT(first, count);
282                 CHECKGLERROR
283                 arraylocked = true;
284         }
285 }
286
287 void GL_UnlockArray(void)
288 {
289         if (arraylocked)
290         {
291                 qglUnlockArraysEXT();
292                 CHECKGLERROR
293                 arraylocked = false;
294         }
295 }
296
297 //static float gldepthmin, gldepthmax;
298
299 /*
300 =============
301 GL_SetupFrame
302 =============
303 */
304 static void GL_SetupFrame (void)
305 {
306         double xmax, ymax;
307         double fovx, fovy, zNear, zFar, aspect;
308
309         // update farclip based on previous frame
310         r_farclip = r_newfarclip;
311
312         if (!r_render.integer)
313                 return;
314
315 //      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: moved to SCR_UpdateScreen
316 //      gldepthmin = 0;
317 //      gldepthmax = 1;
318         glDepthFunc (GL_LEQUAL);CHECKGLERROR
319
320 //      glDepthRange (gldepthmin, gldepthmax);CHECKGLERROR
321
322         // set up viewpoint
323         glMatrixMode(GL_PROJECTION);CHECKGLERROR
324         glLoadIdentity ();CHECKGLERROR
325
326         // y is weird beause OpenGL is bottom to top, we use top to bottom
327         glViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);CHECKGLERROR
328
329         // depth range
330         zNear = 1.0;
331         zFar = r_farclip;
332
333         // fov angles
334         fovx = r_refdef.fov_x;
335         fovy = r_refdef.fov_y;
336         aspect = r_refdef.width / r_refdef.height;
337
338         // pyramid slopes
339         xmax = zNear * tan(fovx * M_PI / 360.0) * aspect;
340         ymax = zNear * tan(fovy * M_PI / 360.0);
341
342         // set view pyramid
343         glFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
344
345 //      glCullFace(GL_FRONT);CHECKGLERROR
346
347         glMatrixMode(GL_MODELVIEW);CHECKGLERROR
348         glLoadIdentity ();CHECKGLERROR
349
350         // put Z going up
351         glRotatef (-90,  1, 0, 0);CHECKGLERROR
352         glRotatef (90,  0, 0, 1);CHECKGLERROR
353         // camera rotation
354         glRotatef (-r_refdef.viewangles[2],  1, 0, 0);CHECKGLERROR
355         glRotatef (-r_refdef.viewangles[0],  0, 1, 0);CHECKGLERROR
356         glRotatef (-r_refdef.viewangles[1],  0, 0, 1);CHECKGLERROR
357         // camera location
358         glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);CHECKGLERROR
359
360 //      glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
361
362         //
363         // set drawing parms
364         //
365 //      if (gl_cull.integer)
366 //      {
367 //              glEnable(GL_CULL_FACE);CHECKGLERROR
368 //      }
369 //      else
370 //      {
371 //              glDisable(GL_CULL_FACE);CHECKGLERROR
372 //      }
373
374 //      glEnable(GL_BLEND);CHECKGLERROR
375 //      glEnable(GL_DEPTH_TEST);CHECKGLERROR
376 //      glDepthMask(1);CHECKGLERROR
377 }
378
379 static int mesh_blendfunc1;
380 static int mesh_blendfunc2;
381 static int mesh_blend;
382 static GLboolean mesh_depthmask;
383 static int mesh_depthtest;
384 static int mesh_unit;
385 static int mesh_clientunit;
386 static int mesh_texture[MAX_TEXTUREUNITS];
387 static float mesh_texturergbscale[MAX_TEXTUREUNITS];
388
389 void GL_SetupTextureState(void)
390 {
391         int i;
392         if (backendunits > 1)
393         {
394                 for (i = 0;i < backendunits;i++)
395                 {
396                         qglActiveTexture(GL_TEXTURE0_ARB + (mesh_unit = i));CHECKGLERROR
397                         glBindTexture(GL_TEXTURE_2D, mesh_texture[i]);CHECKGLERROR
398                         if (gl_combine.integer)
399                         {
400                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
401                                 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
402                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
403                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
404                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);CHECKGLERROR
405                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
406                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
407                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
408                                 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
409                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
410                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
411                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
412                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
413                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
414                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
415                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, mesh_texturergbscale[i]);CHECKGLERROR
416                                 glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0f);CHECKGLERROR
417                         }
418                         else
419                         {
420                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
421                         }
422                         qglClientActiveTexture(GL_TEXTURE0_ARB + (mesh_clientunit = i));CHECKGLERROR
423                         glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[i]);CHECKGLERROR
424                         if (mesh_texture[i])
425                         {
426                                 glEnable(GL_TEXTURE_2D);CHECKGLERROR
427                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
428                         }
429                         else
430                         {
431                                 glDisable(GL_TEXTURE_2D);CHECKGLERROR
432                                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
433                         }
434                 }
435         }
436         else
437         {
438                 glBindTexture(GL_TEXTURE_2D, mesh_texture[0]);CHECKGLERROR
439                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
440                 glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[0]);CHECKGLERROR
441                 if (mesh_texture[0])
442                 {
443                         glEnable(GL_TEXTURE_2D);CHECKGLERROR
444                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
445                 }
446                 else
447                 {
448                         glDisable(GL_TEXTURE_2D);CHECKGLERROR
449                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
450                 }
451         }
452 }
453
454 // called at beginning of frame
455 void R_Mesh_Start(void)
456 {
457         int i;
458         if (!backendactive)
459                 Sys_Error("R_Mesh_Clear: called when backend is not active\n");
460
461         CHECKGLERROR
462
463         gl_backend_bufferchanges(false);
464
465         currentmesh = 0;
466         currenttriangle = 0;
467         currentvertex = 0;
468         currenttransmesh = 0;
469         currenttranstriangle = 0;
470         currenttransvertex = 0;
471         meshfarclip = 0;
472         transranout = false;
473         viewdist = DotProduct(r_origin, vpn);
474
475         c_meshs = 0;
476         c_meshtris = 0;
477         c_transmeshs = 0;
478         c_transtris = 0;
479
480         GL_SetupFrame();
481
482         mesh_unit = 0;
483         mesh_clientunit = 0;
484
485         for (i = 0;i < backendunits;i++)
486         {
487                 mesh_texture[i] = 0;
488                 mesh_texturergbscale[i] = 1;
489         }
490
491         glEnable(GL_CULL_FACE);CHECKGLERROR
492         glCullFace(GL_FRONT);CHECKGLERROR
493
494         mesh_depthtest = true;
495         glEnable(GL_DEPTH_TEST);CHECKGLERROR
496
497         mesh_blendfunc1 = GL_ONE;
498         mesh_blendfunc2 = GL_ZERO;
499         glBlendFunc(mesh_blendfunc1, mesh_blendfunc2);CHECKGLERROR
500
501         mesh_blend = 0;
502         glDisable(GL_BLEND);CHECKGLERROR
503
504         mesh_depthmask = GL_TRUE;
505         glDepthMask(mesh_depthmask);CHECKGLERROR
506
507         glVertexPointer(3, GL_FLOAT, sizeof(buf_vertex_t), &buf_vertex[0].v[0]);CHECKGLERROR
508         glEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
509         if (gl_mesh_floatcolors.integer)
510         {
511                 glColorPointer(4, GL_FLOAT, sizeof(buf_fcolor_t), &buf_fcolor[0].c[0]);CHECKGLERROR
512         }
513         else
514         {
515                 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(buf_bcolor_t), &buf_bcolor[0].c[0]);CHECKGLERROR
516         }
517         glEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
518
519         GL_SetupTextureState();
520 }
521
522 int gl_backend_rebindtextures;
523
524 void GL_UpdateFarclip(void)
525 {
526         int i;
527         float farclip;
528
529         // push out farclip based on vertices
530         // FIXME: wouldn't this be slow when using matrix transforms?
531         for (i = 0;i < currentvertex;i++)
532         {
533                 farclip = DotProduct(buf_vertex[i].v, vpn);
534                 if (meshfarclip < farclip)
535                         meshfarclip = farclip;
536         }
537
538         farclip = meshfarclip + 256.0f - viewdist; // + 256 just to be safe
539
540         // push out farclip for next frame
541         if (farclip > r_newfarclip)
542                 r_newfarclip = ceil((farclip + 255) / 256) * 256 + 256;
543 }
544
545 void GL_ConvertColorsFloatToByte(void)
546 {
547         int i, k, *icolor;
548         float *fcolor;
549         qbyte *bcolor;
550
551         // shift float to have 8bit fraction at base of number
552         for (i = 0, fcolor = &buf_fcolor->c[0];i < currentvertex;i++)
553         {
554                 *fcolor++ += 32768.0f;
555                 *fcolor++ += 32768.0f;
556                 *fcolor++ += 32768.0f;
557                 *fcolor++ += 32768.0f;
558         }
559         // then read as integer and kill float bits...
560         for (i = 0, icolor = (int *)&buf_fcolor->c[0], bcolor = &buf_bcolor->c[0];i < currentvertex;i++)
561         {
562                 k = (*icolor++) & 0x7FFFFF;*bcolor++ = k > 255 ? 255 : k;
563                 k = (*icolor++) & 0x7FFFFF;*bcolor++ = k > 255 ? 255 : k;
564                 k = (*icolor++) & 0x7FFFFF;*bcolor++ = k > 255 ? 255 : k;
565                 k = (*icolor++) & 0x7FFFFF;*bcolor++ = k > 255 ? 255 : k;
566         }
567 }
568
569 void GL_MeshState(buf_mesh_t *mesh)
570 {
571         int i;
572         if (backendunits > 1)
573         {
574                 for (i = 0;i < backendunits;i++)
575                 {
576                         if (mesh_texture[i] != mesh->textures[i])
577                         {
578                                 if (mesh_unit != i)
579                                 {
580                                         qglActiveTexture(GL_TEXTURE0_ARB + (mesh_unit = i));CHECKGLERROR
581                                 }
582                                 if (mesh_texture[i] == 0)
583                                 {
584                                         glEnable(GL_TEXTURE_2D);CHECKGLERROR
585                                         // have to disable texcoord array on disabled texture
586                                         // units due to NVIDIA driver bug with
587                                         // compiled_vertex_array
588                                         if (mesh_clientunit != i)
589                                         {
590                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (mesh_clientunit = i));CHECKGLERROR
591                                         }
592                                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
593                                 }
594                                 glBindTexture(GL_TEXTURE_2D, (mesh_texture[i] = mesh->textures[i]));CHECKGLERROR
595                                 if (mesh_texture[i] == 0)
596                                 {
597                                         glDisable(GL_TEXTURE_2D);CHECKGLERROR
598                                         // have to disable texcoord array on disabled texture
599                                         // units due to NVIDIA driver bug with
600                                         // compiled_vertex_array
601                                         if (mesh_clientunit != i)
602                                         {
603                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (mesh_clientunit = i));CHECKGLERROR
604                                         }
605                                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
606                                 }
607                         }
608                         if (mesh_texturergbscale[i] != mesh->texturergbscale[i])
609                         {
610                                 if (mesh_unit != i)
611                                 {
612                                         qglActiveTexture(GL_TEXTURE0_ARB + (mesh_unit = i));CHECKGLERROR
613                                 }
614                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (mesh_texturergbscale[i] = mesh->texturergbscale[i]));CHECKGLERROR
615                         }
616                 }
617         }
618         else
619         {
620                 if (mesh_texture[0] != mesh->textures[0])
621                 {
622                         if (mesh_texture[0] == 0)
623                         {
624                                 glEnable(GL_TEXTURE_2D);CHECKGLERROR
625                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
626                         }
627                         glBindTexture(GL_TEXTURE_2D, (mesh_texture[0] = mesh->textures[0]));CHECKGLERROR
628                         if (mesh_texture[0] == 0)
629                         {
630                                 glDisable(GL_TEXTURE_2D);CHECKGLERROR
631                                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
632                         }
633                 }
634         }
635         if (mesh_blendfunc1 != mesh->blendfunc1 || mesh_blendfunc2 != mesh->blendfunc2)
636         {
637                 glBlendFunc(mesh_blendfunc1 = mesh->blendfunc1, mesh_blendfunc2 = mesh->blendfunc2);CHECKGLERROR
638                 if (mesh_blendfunc2 == GL_ZERO)
639                 {
640                         if (mesh_blendfunc1 == GL_ONE)
641                         {
642                                 if (mesh_blend)
643                                 {
644                                         mesh_blend = 0;
645                                         glDisable(GL_BLEND);CHECKGLERROR
646                                 }
647                         }
648                         else
649                         {
650                                 if (!mesh_blend)
651                                 {
652                                         mesh_blend = 1;
653                                         glEnable(GL_BLEND);CHECKGLERROR
654                                 }
655                         }
656                 }
657                 else
658                 {
659                         if (!mesh_blend)
660                         {
661                                 mesh_blend = 1;
662                                 glEnable(GL_BLEND);CHECKGLERROR
663                         }
664                 }
665         }
666         if (mesh_depthtest != mesh->depthtest)
667         {
668                 mesh_depthtest = mesh->depthtest;
669                 if (mesh_depthtest)
670                         glEnable(GL_DEPTH_TEST);
671                 else
672                         glDisable(GL_DEPTH_TEST);
673         }
674         if (mesh_depthmask != mesh->depthmask)
675         {
676                 glDepthMask(mesh_depthmask = mesh->depthmask);CHECKGLERROR
677         }
678 }
679
680 // renders mesh buffers, called to flush buffers when full
681 void R_Mesh_Render(void)
682 {
683         int i;
684         int k;
685         int indexcount;
686         int firstvert;
687         buf_mesh_t *mesh;
688         unsigned int *index;
689
690         if (!backendactive)
691                 Sys_Error("R_Mesh_Render: called when backend is not active\n");
692
693         if (!currentmesh)
694                 return;
695
696         CHECKGLERROR
697
698         GL_UpdateFarclip();
699
700         if (!gl_mesh_floatcolors.integer)
701                 GL_ConvertColorsFloatToByte();
702
703         // lock the arrays now that they will have no further modifications
704         //GL_LockArray(0, currentvertex);CHECKGLERROR
705         if (gl_backend_rebindtextures)
706         {
707                 gl_backend_rebindtextures = false;
708                 GL_SetupTextureState();
709         }
710
711         GL_MeshState(buf_mesh);
712         GL_LockArray(0, currentvertex);
713         #ifdef WIN32
714         // FIXME: dynamic link to GL so we can get DrawRangeElements on WIN32
715         glDrawElements(GL_TRIANGLES, buf_mesh->triangles * 3, GL_UNSIGNED_INT, (unsigned int *)&buf_tri[buf_mesh->firsttriangle].index[0]);CHECKGLERROR
716         #else
717         glDrawRangeElements(GL_TRIANGLES, buf_mesh->firstvert, buf_mesh->firstvert + buf_mesh->verts, buf_mesh->triangles * 3, GL_UNSIGNED_INT, (unsigned int *)&buf_tri[buf_mesh->firsttriangle].index[0]);CHECKGLERROR
718         #endif
719
720         if (currentmesh >= 2)
721         {
722                 for (k = 1, mesh = buf_mesh + k;k < currentmesh;k++, mesh++)
723                 {
724                         GL_MeshState(mesh);
725
726                         firstvert = mesh->firstvert;
727                         indexcount = mesh->triangles * 3;
728                         index = (unsigned int *)&buf_tri[mesh->firsttriangle].index[0];
729
730                         // if not using batching, skip the index adjustment
731                         if (firstvert != 0)
732                                 for (i = 0;i < indexcount;i++)
733                                         index[i] += firstvert;
734
735                         #ifdef WIN32
736                         // FIXME: dynamic link to GL so we can get DrawRangeElements on WIN32
737                         glDrawElements(GL_TRIANGLES, indexcount, GL_UNSIGNED_INT, index);CHECKGLERROR
738                         #else
739                         glDrawRangeElements(GL_TRIANGLES, firstvert, firstvert + mesh->verts, indexcount, GL_UNSIGNED_INT, index);CHECKGLERROR
740                         #endif
741                 }
742         }
743
744         currentmesh = 0;
745         currenttriangle = 0;
746         currentvertex = 0;
747
748         GL_UnlockArray();CHECKGLERROR
749 }
750
751 // restores backend state, used when done with 3D rendering
752 void R_Mesh_Finish(void)
753 {
754         int i;
755         // flush any queued meshs
756         R_Mesh_Render();
757
758         if (backendunits > 1)
759         {
760                 for (i = backendunits - 1;i >= 0;i--)
761                 {
762                         qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
763                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
764                         if (gl_combine.integer)
765                         {
766                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);CHECKGLERROR
767                         }
768                         if (i > 0)
769                         {
770                                 glDisable(GL_TEXTURE_2D);CHECKGLERROR
771                         }
772                         else
773                         {
774                                 glEnable(GL_TEXTURE_2D);CHECKGLERROR
775                         }
776                         glBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
777
778                         qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
779                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
780                 }
781         }
782         else
783         {
784                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
785                 glEnable(GL_TEXTURE_2D);CHECKGLERROR
786                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
787         }
788         glDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
789         glDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
790
791         glDisable(GL_BLEND);CHECKGLERROR
792         glEnable(GL_DEPTH_TEST);CHECKGLERROR
793         glDepthMask(true);CHECKGLERROR
794         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
795 }
796
797 void R_Mesh_ClearDepth(void)
798 {
799         R_Mesh_AddTransparent();
800         R_Mesh_Finish();
801         glClear(GL_DEPTH_BUFFER_BIT);
802         R_Mesh_Start();
803 }
804
805 void R_Mesh_AddTransparent(void)
806 {
807         int i, j, k, *index;
808         float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
809         buf_vertex_t *vert1, *vert2, *vert3;
810         buf_transtri_t *tri;
811         buf_mesh_t *mesh, *transmesh;
812
813         if (!currenttransmesh)
814                 return;
815
816         // convert index data to transtris for sorting
817         for (j = 0;j < currenttransmesh;j++)
818         {
819                 mesh = buf_transmesh + j;
820                 k = mesh->firsttriangle;
821                 index = &buf_transtri[k].index[0];
822                 for (i = 0;i < mesh->triangles;i++)
823                 {
824                         tri = &buf_sorttranstri[k++];
825                         tri->mesh = mesh;
826                         tri->index[0] = *index++;
827                         tri->index[1] = *index++;
828                         tri->index[2] = *index++;
829                 }
830         }
831
832         // map farclip to 0-4095 list range
833         centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
834         viewdistcompare = viewdist + 4.0f;
835
836         memset(buf_sorttranstri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
837
838         k = 0;
839         for (j = 0;j < currenttranstriangle;j++)
840         {
841                 tri = &buf_sorttranstri[j];
842                 i = tri->mesh->firstvert;
843
844                 vert1 = &buf_transvertex[tri->index[0] + i];
845                 vert2 = &buf_transvertex[tri->index[1] + i];
846                 vert3 = &buf_transvertex[tri->index[2] + i];
847
848                 dist1 = DotProduct(vert1->v, vpn);
849                 dist2 = DotProduct(vert2->v, vpn);
850                 dist3 = DotProduct(vert3->v, vpn);
851
852                 maxdist = max(dist1, max(dist2, dist3));
853                 if (maxdist < viewdistcompare)
854                         continue;
855
856                 center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
857 #if SLOWMATH
858                 i = (int) center;
859                 i = bound(0, i, (TRANSDEPTHRES - 1));
860 #else
861                 if (center < 0.0f)
862                         center = 0.0f;
863                 center += 8388608.0f;
864                 i = *((long *)&center) & 0x7FFFFF;
865                 i = min(i, (TRANSDEPTHRES - 1));
866 #endif
867                 tri->next = buf_sorttranstri_list[i];
868                 buf_sorttranstri_list[i] = tri;
869                 k++;
870         }
871
872         for (i = 0;i < currenttransmesh;i++)
873                 buf_transmesh[i].transchain = NULL;
874         transmesh = NULL;
875         for (j = 0;j < TRANSDEPTHRES;j++)
876         {
877                 if ((tri = buf_sorttranstri_list[j]))
878                 {
879                         for (;tri;tri = tri->next)
880                         {
881                                 if (!tri->mesh->transchain)
882                                 {
883                                         tri->mesh->chain = transmesh;
884                                         transmesh = tri->mesh;
885                                 }
886                                 tri->meshsortchain = tri->mesh->transchain;
887                                 tri->mesh->transchain = tri;
888                         }
889                 }
890         }
891
892         for (;transmesh;transmesh = transmesh->chain)
893         {
894                 if (currentmesh >= max_meshs || currenttriangle + transmesh->triangles > max_batch || currentvertex + transmesh->verts > max_verts)
895                         R_Mesh_Render();
896
897                 mesh = &buf_mesh[currentmesh++];
898                 *mesh = *transmesh; // copy mesh properties
899
900                 mesh->firstvert = currentvertex;
901                 memcpy(&buf_vertex[currentvertex], &buf_transvertex[transmesh->firstvert], transmesh->verts * sizeof(buf_vertex_t));
902                 memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[transmesh->firstvert], transmesh->verts * sizeof(buf_fcolor_t));
903                 for (i = 0;i < backendunits && transmesh->textures[i];i++)
904                         memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][transmesh->firstvert], transmesh->verts * sizeof(buf_texcoord_t));
905                 currentvertex += mesh->verts;
906
907                 mesh->firsttriangle = currenttriangle;
908                 for (tri = transmesh->transchain;tri;tri = tri->meshsortchain)
909                 {
910                         buf_tri[currenttriangle].index[0] = tri->index[0];
911                         buf_tri[currenttriangle].index[1] = tri->index[1];
912                         buf_tri[currenttriangle].index[2] = tri->index[2];
913                         currenttriangle++;
914                 }
915                 mesh->triangles = currenttriangle - mesh->firsttriangle;
916         }
917
918         currenttransmesh = 0;
919         currenttranstriangle = 0;
920         currenttransvertex = 0;
921 }
922
923 void R_Mesh_Draw(const rmeshinfo_t *m)
924 {
925         // these are static because gcc runs out of virtual registers otherwise
926         static int i, j, overbright, *index;
927         static float *in, scaler;
928         static float cr, cg, cb, ca;
929         static buf_mesh_t *mesh;
930         static buf_vertex_t *vert;
931         static buf_fcolor_t *fcolor;
932         static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
933
934         if (!backendactive)
935                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
936
937         if (m->index == NULL
938          || !m->numtriangles
939          || m->vertex == NULL
940          || !m->numverts)
941                 Host_Error("R_Mesh_Draw: no triangles or verts\n");
942
943         // ignore meaningless alpha meshs
944         if (!m->depthwrite && m->blendfunc1 == GL_SRC_ALPHA && (m->blendfunc2 == GL_ONE || m->blendfunc2 == GL_ONE_MINUS_SRC_ALPHA))
945         {
946                 if (m->color)
947                 {
948                         for (i = 0, in = m->color + 3;i < m->numverts;i++, (int)in += m->colorstep)
949                                 if (*in >= 0.01f)
950                                         break;
951                         if (i == m->numverts)
952                                 return;
953                 }
954                 else if (m->ca < 0.01f)
955                         return;
956         }
957
958         if (!backendactive)
959                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
960
961 #ifdef DEBUGGL
962         for (i = 0;i < m->numtriangles * 3;i++)
963                 if ((unsigned int) m->index[i] >= (unsigned int) m->numverts)
964                         Host_Error("R_Mesh_Draw: invalid index (%i of %i verts)\n", m->index, m->numverts);
965 #endif
966
967         if (m->transparent)
968         {
969                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
970                 {
971                         if (!transranout)
972                         {
973                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
974                                 transranout = true;
975                         }
976                         return;
977                 }
978
979                 c_transmeshs++;
980                 c_transtris += m->numtriangles;
981                 vert = &buf_transvertex[currenttransvertex];
982                 fcolor = &buf_transfcolor[currenttransvertex];
983                 for (i = 0;i < backendunits;i++)
984                         texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
985
986                 // transmesh is only for storage of transparent meshs until they
987                 // are inserted into the main mesh array
988                 mesh = &buf_transmesh[currenttransmesh++];
989                 mesh->firsttriangle = currenttranstriangle;
990                 mesh->firstvert = currenttransvertex;
991                 index = &buf_transtri[currenttranstriangle].index[0];
992
993                 currenttranstriangle += m->numtriangles;
994                 currenttransvertex += m->numverts;
995         }
996         else
997         {
998                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
999                 {
1000                         Con_Printf("R_Mesh_Draw: mesh too big for buffers\n");
1001                         return;
1002                 }
1003
1004                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
1005                         R_Mesh_Render();
1006
1007                 c_meshs++;
1008                 c_meshtris += m->numtriangles;
1009                 vert = &buf_vertex[currentvertex];
1010                 fcolor = &buf_fcolor[currentvertex];
1011                 for (i = 0;i < backendunits;i++)
1012                         texcoord[i] = &buf_texcoord[i][currentvertex];
1013
1014                 // opaque meshs are rendered directly
1015                 mesh = &buf_mesh[currentmesh++];
1016                 mesh->firsttriangle = currenttriangle;
1017                 mesh->firstvert = currentvertex;
1018                 index = &buf_tri[currenttriangle].index[0];
1019
1020                 currenttriangle += m->numtriangles;
1021                 currentvertex += m->numverts;
1022         }
1023
1024         // code shared for transparent and opaque meshs
1025         memcpy(index, m->index, sizeof(int[3]) * m->numtriangles);
1026         mesh->blendfunc1 = m->blendfunc1;
1027         mesh->blendfunc2 = m->blendfunc2;
1028         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1029         mesh->depthtest = !m->depthdisable;
1030         mesh->triangles = m->numtriangles;
1031         mesh->verts = m->numverts;
1032
1033         overbright = false;
1034         scaler = 1;
1035         if (m->blendfunc2 == GL_SRC_COLOR)
1036         {
1037                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
1038                         scaler *= 0.5f;
1039         }
1040         else
1041         {
1042                 if (m->tex[0])
1043                 {
1044                         overbright = gl_combine.integer;
1045                         if (overbright)
1046                                 scaler *= 0.25f;
1047                 }
1048                 scaler *= overbrightscale;
1049         }
1050
1051
1052         j = -1;
1053         for (i = 0;i < backendunits;i++)
1054         {
1055                 if ((mesh->textures[i] = m->tex[i]))
1056                         j = i;
1057                 mesh->texturergbscale[i] = m->texrgbscale[i];
1058                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1059                         mesh->texturergbscale[i] = 1;
1060         }
1061         if (overbright && j >= 0)
1062                 mesh->texturergbscale[j] = 4;
1063
1064         if (m->vertexstep != sizeof(buf_vertex_t))
1065         {
1066                 for (i = 0, in = m->vertex;i < m->numverts;i++, (int)in += m->vertexstep)
1067                 {
1068                         vert[i].v[0] = in[0];
1069                         vert[i].v[1] = in[1];
1070                         vert[i].v[2] = in[2];
1071                 }
1072         }
1073         else
1074                 memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
1075
1076         if (m->color)
1077         {
1078                 for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
1079                 {
1080                         fcolor[i].c[0] = in[0] * scaler;
1081                         fcolor[i].c[1] = in[1] * scaler;
1082                         fcolor[i].c[2] = in[2] * scaler;
1083                         fcolor[i].c[3] = in[3];
1084                 }
1085         }
1086         else
1087         {
1088                 cr = m->cr * scaler;
1089                 cg = m->cg * scaler;
1090                 cb = m->cb * scaler;
1091                 ca = m->ca;
1092                 for (i = 0;i < m->numverts;i++)
1093                 {
1094                         fcolor[i].c[0] = cr;
1095                         fcolor[i].c[1] = cg;
1096                         fcolor[i].c[2] = cb;
1097                         fcolor[i].c[3] = ca;
1098                 }
1099         }
1100
1101         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1102         {
1103                 if (j >= backendunits)
1104                         Sys_Error("R_Mesh_Draw: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1105                 if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
1106                 {
1107                         for (i = 0, in = m->texcoords[j];i < m->numverts;i++, (int)in += m->texcoordstep[j])
1108                         {
1109                                 texcoord[j][i].t[0] = in[0];
1110                                 texcoord[j][i].t[1] = in[1];
1111                         }
1112                 }
1113                 else
1114                         memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
1115         }
1116         #if 0
1117         for (;j < backendunits;j++)
1118                 memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
1119         #endif
1120 }
1121
1122 void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m)
1123 {
1124         // these are static because gcc runs out of virtual registers otherwise
1125         static int i, j, overbright, *index;
1126         static float *in, scaler;
1127         static buf_mesh_t *mesh;
1128         static buf_vertex_t *vert;
1129         static buf_fcolor_t *fcolor;
1130         static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
1131
1132         if (!backendactive)
1133                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
1134
1135         if (m->index == NULL
1136          || !m->numtriangles
1137          || m->vertex == NULL
1138          || !m->numverts)
1139                 Host_Error("R_Mesh_Draw: no triangles or verts\n");
1140
1141         // ignore meaningless alpha meshs
1142         if (!m->depthwrite && m->blendfunc1 == GL_SRC_ALPHA && (m->blendfunc2 == GL_ONE || m->blendfunc2 == GL_ONE_MINUS_SRC_ALPHA))
1143         {
1144                 if (m->color)
1145                 {
1146                         for (i = 0, in = m->color + 3;i < m->numverts;i++, (int)in += m->colorstep)
1147                                 if (*in >= 0.01f)
1148                                         break;
1149                         if (i == m->numverts)
1150                                 return;
1151                 }
1152                 else if (m->ca < 0.01f)
1153                         return;
1154         }
1155
1156         if (m->transparent)
1157         {
1158                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
1159                 {
1160                         if (!transranout)
1161                         {
1162                                 Con_Printf("R_Mesh_Draw_NativeOnly: ran out of room for transparent meshs\n");
1163                                 transranout = true;
1164                         }
1165                         return;
1166                 }
1167
1168                 c_transmeshs++;
1169                 c_transtris += m->numtriangles;
1170                 vert = &buf_transvertex[currenttransvertex];
1171                 fcolor = &buf_transfcolor[currenttransvertex];
1172                 for (i = 0;i < backendunits;i++)
1173                         texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
1174
1175                 // transmesh is only for storage of transparent meshs until they
1176                 // are inserted into the main mesh array
1177                 mesh = &buf_transmesh[currenttransmesh++];
1178                 mesh->firsttriangle = currenttranstriangle;
1179                 mesh->firstvert = currenttransvertex;
1180                 index = &buf_transtri[currenttranstriangle].index[0];
1181                 currenttranstriangle += m->numtriangles;
1182                 currenttransvertex += m->numverts;
1183         }
1184         else
1185         {
1186                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
1187                 {
1188                         Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for buffers\n");
1189                         return;
1190                 }
1191
1192                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
1193                         R_Mesh_Render();
1194
1195                 c_meshs++;
1196                 c_meshtris += m->numtriangles;
1197                 vert = &buf_vertex[currentvertex];
1198                 fcolor = &buf_fcolor[currentvertex];
1199                 for (i = 0;i < backendunits;i++)
1200                         texcoord[i] = &buf_texcoord[i][currentvertex];
1201
1202                 // opaque meshs are rendered directly
1203                 mesh = &buf_mesh[currentmesh++];
1204                 mesh->firsttriangle = currenttriangle;
1205                 mesh->firstvert = currentvertex;
1206                 index = &buf_tri[currenttriangle].index[0];
1207                 currenttriangle += m->numtriangles;
1208                 currentvertex += m->numverts;
1209         }
1210
1211         // code shared for transparent and opaque meshs
1212         memcpy(index, m->index, sizeof(int[3]) * m->numtriangles);
1213         mesh->blendfunc1 = m->blendfunc1;
1214         mesh->blendfunc2 = m->blendfunc2;
1215         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1216         mesh->depthtest = !m->depthdisable;
1217         mesh->triangles = m->numtriangles;
1218         mesh->verts = m->numverts;
1219
1220         overbright = false;
1221         scaler = 1;
1222         if (m->blendfunc2 == GL_SRC_COLOR)
1223         {
1224                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
1225                         scaler *= 0.5f;
1226         }
1227         else
1228         {
1229                 if (m->tex[0])
1230                 {
1231                         overbright = gl_combine.integer;
1232                         if (overbright)
1233                                 scaler *= 0.25f;
1234                 }
1235                 scaler *= overbrightscale;
1236         }
1237
1238         j = -1;
1239         for (i = 0;i < backendunits;i++)
1240         {
1241                 if ((mesh->textures[i] = m->tex[i]))
1242                         j = i;
1243                 mesh->texturergbscale[i] = m->texrgbscale[i];
1244                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1245                         mesh->texturergbscale[i] = 1;
1246         }
1247         if (overbright && j >= 0)
1248                 mesh->texturergbscale[j] = 4;
1249
1250         if (m->vertexstep != sizeof(buf_vertex_t))
1251                 Host_Error("R_Mesh_Draw_NativeOnly: unsupported vertexstep\n");
1252         if (m->colorstep != sizeof(buf_fcolor_t))
1253                 Host_Error("R_Mesh_Draw_NativeOnly: unsupported colorstep\n");
1254         if (m->color == NULL)
1255                 Host_Error("R_Mesh_Draw_NativeOnly: must provide color array\n");
1256         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1257         {
1258                 if (j >= backendunits)
1259                         Sys_Error("R_Mesh_Draw_NativeOnly: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1260                 if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
1261                         Host_Error("R_Mesh_Draw_NativeOnly: unsupported texcoordstep\n");
1262         }
1263
1264         memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
1265         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1266                 memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
1267         #if 0
1268         for (;j < backendunits;j++)
1269                 memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
1270         #endif
1271
1272         memcpy(fcolor, m->color, m->numverts * sizeof(buf_fcolor_t));
1273
1274         // do this as a second step because memcpy preloaded the cache, which we can't easily do
1275         if (scaler != 1)
1276         {
1277                 for (i = 0;i < m->numverts;i++)
1278                 {
1279                         fcolor[i].c[0] *= scaler;
1280                         fcolor[i].c[1] *= scaler;
1281                         fcolor[i].c[2] *= scaler;
1282                 }
1283         }
1284 }
1285
1286 // allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
1287 // (this is used for very high speed rendering, no copying)
1288 int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m)
1289 {
1290         // these are static because gcc runs out of virtual registers otherwise
1291         int i, j, overbright;
1292         float scaler;
1293         buf_mesh_t *mesh;
1294
1295         if (!backendactive)
1296                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
1297
1298         if (!m->numtriangles
1299          || !m->numverts)
1300                 Host_Error("R_Mesh_Draw: no triangles or verts\n");
1301
1302         if (m->transparent)
1303         {
1304                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
1305                 {
1306                         if (!transranout)
1307                         {
1308                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
1309                                 transranout = true;
1310                         }
1311                         return false;
1312                 }
1313
1314                 c_transmeshs++;
1315                 c_transtris += m->numtriangles;
1316                 m->index = &buf_transtri[currenttranstriangle].index[0];
1317                 m->vertex = &buf_transvertex[currenttransvertex].v[0];
1318                 m->color = &buf_transfcolor[currenttransvertex].c[0];
1319                 for (i = 0;i < backendunits;i++)
1320                         m->texcoords[i] = &buf_transtexcoord[i][currenttransvertex].t[0];
1321
1322                 // transmesh is only for storage of transparent meshs until they
1323                 // are inserted into the main mesh array
1324                 mesh = &buf_transmesh[currenttransmesh++];
1325                 mesh->firsttriangle = currenttranstriangle;
1326                 mesh->firstvert = currenttransvertex;
1327                 currenttranstriangle += m->numtriangles;
1328                 currenttransvertex += m->numverts;
1329         }
1330         else
1331         {
1332                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
1333                 {
1334                         Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for buffers\n");
1335                         return false;
1336                 }
1337
1338                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
1339                         R_Mesh_Render();
1340
1341                 c_meshs++;
1342                 c_meshtris += m->numtriangles;
1343                 m->index = &buf_tri[currenttriangle].index[0];
1344                 m->vertex = &buf_vertex[currentvertex].v[0];
1345                 m->color = &buf_fcolor[currentvertex].c[0];
1346                 for (i = 0;i < backendunits;i++)
1347                         m->texcoords[i] = &buf_texcoord[i][currentvertex].t[0];
1348
1349                 // opaque meshs are rendered directly
1350                 mesh = &buf_mesh[currentmesh++];
1351                 mesh->firsttriangle = currenttriangle;
1352                 mesh->firstvert = currentvertex;
1353                 currenttriangle += m->numtriangles;
1354                 currentvertex += m->numverts;
1355         }
1356
1357         // code shared for transparent and opaque meshs
1358         mesh->blendfunc1 = m->blendfunc1;
1359         mesh->blendfunc2 = m->blendfunc2;
1360         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1361         mesh->depthtest = !m->depthdisable;
1362         mesh->triangles = m->numtriangles;
1363         mesh->verts = m->numverts;
1364
1365         overbright = false;
1366         scaler = 1;
1367         if (m->blendfunc2 == GL_SRC_COLOR)
1368         {
1369                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
1370                         scaler *= 0.5f;
1371         }
1372         else
1373         {
1374                 if (m->tex[0])
1375                 {
1376                         overbright = gl_combine.integer;
1377                         if (overbright)
1378                                 scaler *= 0.25f;
1379                 }
1380                 scaler *= overbrightscale;
1381         }
1382         m->colorscale = scaler;
1383
1384         j = -1;
1385         for (i = 0;i < MAX_TEXTUREUNITS;i++)
1386         {
1387                 if ((mesh->textures[i] = m->tex[i]))
1388                 {
1389                         j = i;
1390                         if (i >= backendunits)
1391                                 Sys_Error("R_Mesh_Draw_GetBuffer: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1392                 }
1393                 mesh->texturergbscale[i] = m->texrgbscale[i];
1394                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1395                         mesh->texturergbscale[i] = 1;
1396         }
1397         if (overbright && j >= 0)
1398                 mesh->texturergbscale[j] = 4;
1399
1400         return true;
1401 }
1402
1403 void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
1404 {
1405         m->index = polyindexarray;
1406         m->numverts = numverts;
1407         m->numtriangles = numverts - 2;
1408         if (m->numtriangles < 1)
1409         {
1410                 Con_Printf("R_Mesh_DrawPolygon: invalid vertex count\n");
1411                 return;
1412         }
1413         if (m->numtriangles >= 256)
1414         {
1415                 Con_Printf("R_Mesh_DrawPolygon: only up to 256 triangles (258 verts) supported\n");
1416                 return;
1417         }
1418         R_Mesh_Draw(m);
1419 }
1420
1421 /*
1422 ==============================================================================
1423
1424                                                 SCREEN SHOTS
1425
1426 ==============================================================================
1427 */
1428
1429 void SCR_ScreenShot(char *filename, int x, int y, int width, int height)
1430 {
1431         int i;
1432         qbyte *buffer;
1433
1434         if (!r_render.integer)
1435                 return;
1436
1437         buffer = Mem_Alloc(tempmempool, width*height*3);
1438         glReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
1439         CHECKGLERROR
1440
1441         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
1442         if (v_hwgamma.integer)
1443                 for (i = 0;i < width * height * 3;i++)
1444                         buffer[i] <<= v_overbrightbits.integer;
1445
1446         Image_WriteTGARGB_preflipped(filename, width, height, buffer);
1447
1448         Mem_Free(buffer);
1449 }
1450
1451 //=============================================================================
1452
1453 void R_ClearScreen(void)
1454 {
1455         if (r_render.integer)
1456         {
1457                 // clear to black
1458                 glClearColor(0,0,0,0);CHECKGLERROR
1459                 // clear the screen
1460                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);CHECKGLERROR
1461                 // set dithering mode
1462                 if (gl_dither.integer)
1463                 {
1464                         glEnable(GL_DITHER);CHECKGLERROR
1465                 }
1466                 else
1467                 {
1468                         glDisable(GL_DITHER);CHECKGLERROR
1469                 }
1470         }
1471 }
1472
1473 /*
1474 ==================
1475 SCR_UpdateScreen
1476
1477 This is called every frame, and can also be called explicitly to flush
1478 text to the screen.
1479 ==================
1480 */
1481 void SCR_UpdateScreen (void)
1482 {
1483         //Mem_CheckSentinelsGlobal();
1484         //R_TimeReport("memtest");
1485
1486         VID_Finish ();
1487
1488         R_TimeReport("finish");
1489
1490         if (gl_combine.integer && !gl_combine_extension)
1491                 Cvar_SetValue("gl_combine", 0);
1492
1493         lightscalebit = v_overbrightbits.integer;
1494         if (gl_combine.integer && r_multitexture.integer)
1495                 lightscalebit += 2;
1496
1497         lightscale = 1.0f / (float) (1 << lightscalebit);
1498         overbrightscale = 1.0f / (float) (1 << v_overbrightbits.integer);
1499
1500         R_TimeReport("setup");
1501
1502         R_ClearScreen();
1503
1504         R_TimeReport("clear");
1505
1506         if (scr_conlines < vid.conheight)
1507                 R_RenderView();
1508
1509         // draw 2D stuff
1510         R_DrawQueue();
1511
1512         // tell driver to commit it's partially full geometry queue to the rendering queue
1513         // (this doesn't wait for the commands themselves to complete)
1514         glFlush();
1515 }