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