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