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