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