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