removed gl_viewmodeldepthhack
[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 verts;
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.0 / 3.0, 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, endvert, 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[0].v[0]);
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[0].c[0]);
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[0].c[0]);
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                 endvert = firstvert + mesh->verts;
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->firstvert == endvert
683                                 && mesh->blendfunc1 == blendfunc1
684                                 && mesh->blendfunc2 == blendfunc2
685                                 && mesh->depthtest == depthtest
686                                 && mesh->depthmask == depthmask
687                                 && mesh->textures[0] == texture[0]
688                                 && mesh->textures[1] == texture[1]
689                                 && mesh->textures[2] == texture[2]
690                                 && mesh->textures[3] == texture[3]
691                                 && mesh->texturergbscale[0] == texturergbscale[0]
692                                 && mesh->texturergbscale[1] == texturergbscale[1]
693                                 && mesh->texturergbscale[2] == texturergbscale[2]
694                                 && mesh->texturergbscale[3] == texturergbscale[3])
695                         {
696                                 triangles += mesh->triangles;
697                                 endvert += mesh->verts;
698                                 mesh = &buf_mesh[++k];
699                         }
700                 }
701
702                 index = (unsigned int *)&buf_tri[firsttriangle].index[0];
703                 for (i = 0;i < triangles * 3;i++)
704                         index[i] += firstvert;
705
706 #ifdef WIN32
707                 // FIXME: dynamic link to GL so we can get DrawRangeElements on WIN32
708                 glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_INT, index);
709 #else
710                 glDrawRangeElements(GL_TRIANGLES, firstvert, endvert, triangles * 3, GL_UNSIGNED_INT, index);
711 #endif
712 CHECKGLERROR
713         }
714
715         currentmesh = 0;
716         currenttriangle = 0;
717         currentvertex = 0;
718
719         GL_UnlockArray();
720 CHECKGLERROR
721
722         if (backendunits > 1)
723         {
724                 for (i = backendunits - 1;i >= 0;i--)
725                 {
726                         qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
727 CHECKGLERROR
728                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
729 CHECKGLERROR
730                         if (gl_combine.integer)
731                         {
732                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
733 CHECKGLERROR
734                         }
735                         if (i > 0)
736                         {
737                                 glDisable(GL_TEXTURE_2D);
738 CHECKGLERROR
739                         }
740                         else
741                         {
742                                 glEnable(GL_TEXTURE_2D);
743 CHECKGLERROR
744                         }
745                         glBindTexture(GL_TEXTURE_2D, 0);
746 CHECKGLERROR
747
748                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
749 CHECKGLERROR
750                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
751 CHECKGLERROR
752                 }
753         }
754         else
755         {
756                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
757 CHECKGLERROR
758                 glEnable(GL_TEXTURE_2D);
759 CHECKGLERROR
760                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
761 CHECKGLERROR
762         }
763         glDisableClientState(GL_COLOR_ARRAY);
764 CHECKGLERROR
765         glDisableClientState(GL_VERTEX_ARRAY);
766 CHECKGLERROR
767
768         glDisable(GL_BLEND);
769 CHECKGLERROR
770         glEnable(GL_DEPTH_TEST);
771 CHECKGLERROR
772         glDepthMask(true);
773 CHECKGLERROR
774         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
775 CHECKGLERROR
776 }
777
778 void R_Mesh_AddTransparent(void)
779 {
780         int i, j, k, *index;
781         float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
782         buf_vertex_t *vert1, *vert2, *vert3;
783         buf_transtri_t *tri;
784         buf_mesh_t *mesh, *transmesh;
785
786         if (!currenttransmesh)
787                 return;
788
789         // convert index data to transtris for sorting
790         for (j = 0;j < currenttransmesh;j++)
791         {
792                 mesh = buf_transmesh + j;
793                 k = mesh->firsttriangle;
794                 index = &buf_transtri[k].index[0];
795                 for (i = 0;i < mesh->triangles;i++)
796                 {
797                         tri = &buf_sorttranstri[k++];
798                         tri->mesh = mesh;
799                         tri->index[0] = *index++;
800                         tri->index[1] = *index++;
801                         tri->index[2] = *index++;
802                 }
803         }
804
805         // map farclip to 0-4095 list range
806         centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
807         viewdistcompare = viewdist + 4.0f;
808
809         memset(buf_sorttranstri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
810
811         k = 0;
812         for (j = 0;j < currenttranstriangle;j++)
813         {
814                 tri = &buf_sorttranstri[j];
815                 i = tri->mesh->firstvert;
816
817                 vert1 = &buf_transvertex[tri->index[0] + i];
818                 vert2 = &buf_transvertex[tri->index[1] + i];
819                 vert3 = &buf_transvertex[tri->index[2] + i];
820
821                 dist1 = DotProduct(vert1->v, vpn);
822                 dist2 = DotProduct(vert2->v, vpn);
823                 dist3 = DotProduct(vert3->v, vpn);
824
825                 maxdist = max(dist1, max(dist2, dist3));
826                 if (maxdist < viewdistcompare)
827                         continue;
828
829                 center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
830 #if SLOWMATH
831                 i = (int) center;
832                 i = bound(0, i, (TRANSDEPTHRES - 1));
833 #else
834                 if (center < 0.0f)
835                         center = 0.0f;
836                 center += 8388608.0f;
837                 i = *((long *)&center) & 0x7FFFFF;
838                 i = min(i, (TRANSDEPTHRES - 1));
839 #endif
840                 tri->next = buf_sorttranstri_list[i];
841                 buf_sorttranstri_list[i] = tri;
842                 k++;
843         }
844
845         if (currentmesh + k > max_meshs || currenttriangle + k > max_batch || currentvertex + currenttransvertex > max_verts)
846                 R_Mesh_Render();
847
848         for (i = 0;i < currenttransmesh;i++)
849                 buf_transmesh[i].transchain = NULL;
850         transmesh = NULL;
851         for (j = 0;j < TRANSDEPTHRES;j++)
852         {
853                 if ((tri = buf_sorttranstri_list[j]))
854                 {
855                         for (;tri;tri = tri->next)
856                         {
857                                 if (!tri->mesh->transchain)
858                                 {
859                                         tri->mesh->chain = transmesh;
860                                         transmesh = tri->mesh;
861                                 }
862                                 tri->meshsortchain = tri->mesh->transchain;
863                                 tri->mesh->transchain = tri;
864                         }
865                 }
866         }
867
868         for (;transmesh;transmesh = transmesh->chain)
869         {
870                 //if (currentmesh >= max_meshs || currenttriangle + transmesh->triangles > max_batch || currentvertex + transmesh->verts > max_verts)
871                 //      R_Mesh_Render();
872
873                 memcpy(&buf_vertex[currentvertex], &buf_transvertex[transmesh->firstvert], transmesh->verts * sizeof(buf_vertex_t));
874                 memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[transmesh->firstvert], transmesh->verts * sizeof(buf_fcolor_t));
875                 for (i = 0;i < backendunits && transmesh->textures[i];i++)
876                         memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][transmesh->firstvert], transmesh->verts * sizeof(buf_texcoord_t));
877
878                 mesh = &buf_mesh[currentmesh++];
879                 *mesh = *transmesh; // copy mesh properties
880                 mesh->firstvert = currentvertex;
881                 currentvertex += mesh->verts;
882                 mesh->firsttriangle = currenttriangle;
883                 for (tri = transmesh->transchain;tri;tri = tri->meshsortchain)
884                 {
885                         buf_tri[currenttriangle].index[0] = tri->index[0];
886                         buf_tri[currenttriangle].index[1] = tri->index[1];
887                         buf_tri[currenttriangle].index[2] = tri->index[2];
888                         currenttriangle++;
889                 }
890                 mesh->triangles = currenttriangle - mesh->firsttriangle;
891         }
892
893         currenttransmesh = 0;
894         currenttranstriangle = 0;
895         currenttransvertex = 0;
896 }
897
898 void R_Mesh_Draw(const rmeshinfo_t *m)
899 {
900         // these are static because gcc runs out of virtual registers otherwise
901         static int i, j, overbright;
902         static float *in, scaler;
903         static float cr, cg, cb, ca;
904         static buf_mesh_t *mesh;
905         static buf_vertex_t *vert;
906         static buf_fcolor_t *fcolor;
907         static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
908
909         if (!backendactive)
910                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
911
912         if (m->index == NULL
913          || !m->numtriangles
914          || m->vertex == NULL
915          || !m->numverts)
916                 Host_Error("R_Mesh_Draw: no triangles or verts\n");
917
918         // ignore meaningless alpha meshs
919         if (!m->depthwrite && m->blendfunc1 == GL_SRC_ALPHA && (m->blendfunc2 == GL_ONE || m->blendfunc2 == GL_ONE_MINUS_SRC_ALPHA))
920         {
921                 if (m->color)
922                 {
923                         for (i = 0, in = m->color + 3;i < m->numverts;i++, (int)in += m->colorstep)
924                                 if (*in >= 0.01f)
925                                         break;
926                         if (i == m->numverts)
927                                 return;
928                 }
929                 else if (m->ca < 0.01f)
930                         return;
931         }
932
933         if (!backendactive)
934                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
935
936 #ifdef DEBUGGL
937         for (i = 0;i < m->numtriangles * 3;i++)
938                 if ((unsigned int) m->index[i] >= (unsigned int) m->numverts)
939                         Host_Error("R_Mesh_Draw: invalid index (%i of %i verts)\n", m->index, m->numverts);
940 #endif
941
942         if (m->transparent)
943         {
944                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
945                 {
946                         if (!transranout)
947                         {
948                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
949                                 transranout = true;
950                         }
951                         return;
952                 }
953
954                 c_transmeshs++;
955                 c_transtris += m->numtriangles;
956                 vert = &buf_transvertex[currenttransvertex];
957                 fcolor = &buf_transfcolor[currenttransvertex];
958                 for (i = 0;i < backendunits;i++)
959                         texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
960
961                 // transmesh is only for storage of transparent meshs until they
962                 // are inserted into the main mesh array
963                 mesh = &buf_transmesh[currenttransmesh++];
964                 mesh->firsttriangle = currenttranstriangle;
965                 mesh->firstvert = currenttransvertex;
966                 memcpy(&buf_transtri[currenttranstriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
967
968                 currenttranstriangle += m->numtriangles;
969                 currenttransvertex += m->numverts;
970         }
971         else
972         {
973                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
974                 {
975                         Con_Printf("R_Mesh_Draw: mesh too big for buffers\n");
976                         return;
977                 }
978
979                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
980                         R_Mesh_Render();
981
982                 c_meshs++;
983                 c_meshtris += m->numtriangles;
984                 vert = &buf_vertex[currentvertex];
985                 fcolor = &buf_fcolor[currentvertex];
986                 for (i = 0;i < backendunits;i++)
987                         texcoord[i] = &buf_texcoord[i][currentvertex];
988
989                 // opaque meshs are rendered directly
990                 mesh = &buf_mesh[currentmesh++];
991                 mesh->firsttriangle = currenttriangle;
992                 mesh->firstvert = currentvertex;
993                 memcpy(&buf_tri[currenttriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
994                 currenttriangle += m->numtriangles;
995                 currentvertex += m->numverts;
996         }
997
998         // code shared for transparent and opaque meshs
999         mesh->blendfunc1 = m->blendfunc1;
1000         mesh->blendfunc2 = m->blendfunc2;
1001         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1002         mesh->depthtest = !m->depthdisable;
1003         mesh->triangles = m->numtriangles;
1004         mesh->verts = m->numverts;
1005
1006         overbright = false;
1007         scaler = 1;
1008         if (m->blendfunc2 == GL_SRC_COLOR)
1009         {
1010                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
1011                         scaler *= 0.5f;
1012         }
1013         else
1014         {
1015                 if (m->tex[0])
1016                 {
1017                         overbright = gl_combine.integer;
1018                         if (overbright)
1019                                 scaler *= 0.25f;
1020                 }
1021                 scaler *= overbrightscale;
1022         }
1023
1024
1025         j = -1;
1026         for (i = 0;i < backendunits;i++)
1027         {
1028                 if ((mesh->textures[i] = m->tex[i]))
1029                         j = i;
1030                 mesh->texturergbscale[i] = m->texrgbscale[i];
1031                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1032                         mesh->texturergbscale[i] = 1;
1033         }
1034         if (overbright && j >= 0)
1035                 mesh->texturergbscale[j] = 4;
1036
1037         if (m->vertexstep != sizeof(buf_vertex_t))
1038         {
1039                 for (i = 0, in = m->vertex;i < m->numverts;i++, (int)in += m->vertexstep)
1040                 {
1041                         vert[i].v[0] = in[0];
1042                         vert[i].v[1] = in[1];
1043                         vert[i].v[2] = in[2];
1044                 }
1045         }
1046         else
1047                 memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
1048
1049         if (m->color)
1050         {
1051                 for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
1052                 {
1053                         fcolor[i].c[0] = in[0] * scaler;
1054                         fcolor[i].c[1] = in[1] * scaler;
1055                         fcolor[i].c[2] = in[2] * scaler;
1056                         fcolor[i].c[3] = in[3];
1057                 }
1058         }
1059         else
1060         {
1061                 cr = m->cr * scaler;
1062                 cg = m->cg * scaler;
1063                 cb = m->cb * scaler;
1064                 ca = m->ca;
1065                 for (i = 0;i < m->numverts;i++)
1066                 {
1067                         fcolor[i].c[0] = cr;
1068                         fcolor[i].c[1] = cg;
1069                         fcolor[i].c[2] = cb;
1070                         fcolor[i].c[3] = ca;
1071                 }
1072         }
1073
1074         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1075         {
1076                 if (j >= backendunits)
1077                         Sys_Error("R_Mesh_Draw: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1078                 if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
1079                 {
1080                         for (i = 0, in = m->texcoords[j];i < m->numverts;i++, (int)in += m->texcoordstep[j])
1081                         {
1082                                 texcoord[j][i].t[0] = in[0];
1083                                 texcoord[j][i].t[1] = in[1];
1084                         }
1085                 }
1086                 else
1087                         memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
1088         }
1089         #if 0
1090         for (;j < backendunits;j++)
1091                 memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
1092         #endif
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         if (m->transparent)
1130         {
1131                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
1132                 {
1133                         if (!transranout)
1134                         {
1135                                 Con_Printf("R_Mesh_Draw_NativeOnly: ran out of room for transparent meshs\n");
1136                                 transranout = true;
1137                         }
1138                         return;
1139                 }
1140
1141                 c_transmeshs++;
1142                 c_transtris += m->numtriangles;
1143                 vert = &buf_transvertex[currenttransvertex];
1144                 fcolor = &buf_transfcolor[currenttransvertex];
1145                 for (i = 0;i < backendunits;i++)
1146                         texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
1147
1148                 // transmesh is only for storage of transparent meshs until they
1149                 // are inserted into the main mesh array
1150                 mesh = &buf_transmesh[currenttransmesh++];
1151                 mesh->firsttriangle = currenttranstriangle;
1152                 mesh->firstvert = currenttransvertex;
1153                 memcpy(&buf_transtri[currenttranstriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
1154                 currenttranstriangle += m->numtriangles;
1155                 currenttransvertex += m->numverts;
1156         }
1157         else
1158         {
1159                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
1160                 {
1161                         Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for buffers\n");
1162                         return;
1163                 }
1164
1165                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
1166                         R_Mesh_Render();
1167
1168                 c_meshs++;
1169                 c_meshtris += m->numtriangles;
1170                 vert = &buf_vertex[currentvertex];
1171                 fcolor = &buf_fcolor[currentvertex];
1172                 for (i = 0;i < backendunits;i++)
1173                         texcoord[i] = &buf_texcoord[i][currentvertex];
1174
1175                 // opaque meshs are rendered directly
1176                 mesh = &buf_mesh[currentmesh++];
1177                 mesh->firsttriangle = currenttriangle;
1178                 mesh->firstvert = currentvertex;
1179                 memcpy(&buf_tri[currenttriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
1180                 currenttriangle += m->numtriangles;
1181                 currentvertex += m->numverts;
1182         }
1183
1184         // code shared for transparent and opaque meshs
1185         mesh->blendfunc1 = m->blendfunc1;
1186         mesh->blendfunc2 = m->blendfunc2;
1187         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1188         mesh->depthtest = !m->depthdisable;
1189         mesh->triangles = m->numtriangles;
1190         mesh->verts = m->numverts;
1191
1192         overbright = false;
1193         scaler = 1;
1194         if (m->blendfunc2 == GL_SRC_COLOR)
1195         {
1196                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
1197                         scaler *= 0.5f;
1198         }
1199         else
1200         {
1201                 if (m->tex[0])
1202                 {
1203                         overbright = gl_combine.integer;
1204                         if (overbright)
1205                                 scaler *= 0.25f;
1206                 }
1207                 scaler *= overbrightscale;
1208         }
1209
1210         j = -1;
1211         for (i = 0;i < backendunits;i++)
1212         {
1213                 if ((mesh->textures[i] = m->tex[i]))
1214                         j = i;
1215                 mesh->texturergbscale[i] = m->texrgbscale[i];
1216                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1217                         mesh->texturergbscale[i] = 1;
1218         }
1219         if (overbright && j >= 0)
1220                 mesh->texturergbscale[j] = 4;
1221
1222         if (m->vertexstep != sizeof(buf_vertex_t))
1223                 Host_Error("R_Mesh_Draw_NativeOnly: unsupported vertexstep\n");
1224         if (m->colorstep != sizeof(buf_fcolor_t))
1225                 Host_Error("R_Mesh_Draw_NativeOnly: unsupported colorstep\n");
1226         if (m->color == NULL)
1227                 Host_Error("R_Mesh_Draw_NativeOnly: must provide color array\n");
1228         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1229         {
1230                 if (j >= backendunits)
1231                         Sys_Error("R_Mesh_Draw_NativeOnly: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1232                 if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
1233                         Host_Error("R_Mesh_Draw_NativeOnly: unsupported texcoordstep\n");
1234         }
1235
1236         memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
1237         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1238                 memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
1239         #if 0
1240         for (;j < backendunits;j++)
1241                 memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
1242         #endif
1243
1244         memcpy(fcolor, m->color, m->numverts * sizeof(buf_fcolor_t));
1245
1246         // do this as a second step because memcpy preloaded the cache, which we can't easily do
1247         if (scaler != 1)
1248         {
1249                 for (i = 0;i < m->numverts;i++)
1250                 {
1251                         fcolor[i].c[0] *= scaler;
1252                         fcolor[i].c[1] *= scaler;
1253                         fcolor[i].c[2] *= scaler;
1254                 }
1255         }
1256 }
1257
1258 /*
1259 void R_Mesh_Draw_GetBuffer(volatile rmeshinfo_t *m)
1260 {
1261         // these are static because gcc runs out of virtual registers otherwise
1262         static int i, j, *index, overbright;
1263         static float *in, scaler;
1264
1265         if (!backendactive)
1266                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
1267
1268         if (!m->numtriangles
1269          || !m->numverts)
1270                 Host_Error("R_Mesh_Draw: no triangles or verts\n");
1271
1272         scaler = 1;
1273         if (m->blendfunc2 == GL_SRC_COLOR)
1274         {
1275                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
1276                         scaler *= 0.5f;
1277         }
1278         else
1279         {
1280                 if (m->tex[0])
1281                 {
1282                         overbright = gl_combine.integer;
1283                         if (overbright)
1284                                 scaler *= 0.25f;
1285                 }
1286                 scaler *= overbrightscale;
1287         }
1288
1289         if (m->transparent)
1290         {
1291                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
1292                 {
1293                         if (!transranout)
1294                         {
1295                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
1296                                 transranout = true;
1297                         }
1298                         return;
1299                 }
1300
1301                 c_transmeshs++;
1302                 c_transtris += m->numtriangles;
1303                 m->vertex = &buf_transvertex[currenttransvertex].v[0];
1304                 m->color = &buf_transfcolor[currenttransvertex].c[0];
1305                 for (i = 0;i < backendunits;i++)
1306                         m->texcoords[i] = &buf_transtexcoord[i][currenttransvertex].tc[0];
1307
1308                 // transmesh is only for storage of transparent meshs until they
1309                 // are inserted into the main mesh array
1310                 mesh = &buf_transmesh[currenttransmesh++];
1311                 mesh->firsttriangle = currenttranstriangle;
1312                 mesh->firstvert = currenttransvertex;
1313                 memcpy(&buf_transtri[currenttranstriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
1314                 currenttranstriangle += m->numtriangles;
1315                 currenttransvertex += m->numverts;
1316         }
1317         else
1318         {
1319                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
1320                 {
1321                         Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for buffers\n");
1322                         return;
1323                 }
1324
1325                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
1326                         R_Mesh_Render();
1327
1328                 c_meshs++;
1329                 c_meshtris += m->numtriangles;
1330                 vert = &buf_vertex[currentvertex];
1331                 fcolor = &buf_fcolor[currentvertex];
1332                 for (i = 0;i < backendunits;i++)
1333                         texcoord[i] = &buf_texcoord[i][currentvertex];
1334
1335                 // opaque meshs are rendered directly
1336                 mesh = &buf_mesh[currentmesh++];
1337                 mesh->firsttriangle = currenttriangle;
1338                 mesh->firstvert = currentvertex;
1339                 memcpy(&buf_tri[currenttriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
1340                 currenttriangle += m->numtriangles;
1341                 currentvertex += m->numverts;
1342         }
1343
1344         // code shared for transparent and opaque meshs
1345         mesh->blendfunc1 = m->blendfunc1;
1346         mesh->blendfunc2 = m->blendfunc2;
1347         mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1348         mesh->depthtest = !m->depthdisable;
1349         mesh->triangles = m->numtriangles;
1350         mesh->verts = m->numverts;
1351         j = -1;
1352         for (i = 0;i < backendunits;i++)
1353         {
1354                 if ((mesh->textures[i] = m->tex[i]))
1355                         j = i;
1356                 mesh->texturergbscale[i] = m->texrgbscale[i];
1357                 if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1358                         mesh->texturergbscale[i] = 1;
1359         }
1360         if (overbright && j >= 0)
1361                 mesh->texturergbscale[j] = 4;
1362
1363         if (m->vertexstep != sizeof(buf_vertex_t))
1364                 Host_Error("R_Mesh_Draw_NativeOnly: unsupported vertexstep\n");
1365         if (m->colorstep != sizeof(buf_fcolor_t))
1366                 Host_Error("R_Mesh_Draw_NativeOnly: unsupported colorstep\n");
1367         if (m->color == NULL)
1368                 Host_Error("R_Mesh_Draw_NativeOnly: must provide color array\n");
1369         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1370         {
1371                 if (j >= backendunits)
1372                         Sys_Error("R_Mesh_Draw_NativeOnly: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1373                 if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
1374                         Host_Error("R_Mesh_Draw_NativeOnly: unsupported texcoordstep\n");
1375         }
1376
1377         memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
1378         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1379                 memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
1380         #if 0
1381         for (;j < backendunits;j++)
1382                 memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
1383         #endif
1384
1385         memcpy(fcolor, m->color, m->numverts * sizeof(buf_fcolor_t));
1386
1387         // do this as a second step because memcpy preloaded the cache, which we can't easily do
1388         if (scaler != 1)
1389         {
1390                 for (i = 0;i < m->numverts;i++)
1391                 {
1392                         fcolor[i].c[0] *= scaler;
1393                         fcolor[i].c[1] *= scaler;
1394                         fcolor[i].c[2] *= scaler;
1395                 }
1396         }
1397 }
1398 */
1399
1400 void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
1401 {
1402         m->index = polyindexarray;
1403         m->numverts = numverts;
1404         m->numtriangles = numverts - 2;
1405         if (m->numtriangles < 1)
1406         {
1407                 Con_Printf("R_Mesh_DrawPolygon: invalid vertex count\n");
1408                 return;
1409         }
1410         if (m->numtriangles >= 256)
1411         {
1412                 Con_Printf("R_Mesh_DrawPolygon: only up to 256 triangles (258 verts) supported\n");
1413                 return;
1414         }
1415         R_Mesh_Draw(m);
1416 }
1417
1418 /*
1419 ==============================================================================
1420
1421                                                 SCREEN SHOTS
1422
1423 ==============================================================================
1424 */
1425
1426 float CalcFov (float fov_x, float width, float height);
1427 void R_ClearScreen(void);
1428
1429 void SCR_ScreenShot(char *filename, int x, int y, int width, int height)
1430 {
1431         int i;
1432         byte *buffer;
1433
1434         buffer = Mem_Alloc(tempmempool, width*height*3);
1435         glReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
1436         CHECKGLERROR
1437
1438         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
1439         if (v_hwgamma.integer)
1440                 for (i = 0;i < width * height * 3;i++)
1441                         buffer[i] <<= v_overbrightbits.integer;
1442
1443         Image_WriteTGARGB_preflipped(filename, width, height, buffer);
1444
1445         Mem_Free(buffer);
1446 }
1447
1448 /*
1449 ==================
1450 SCR_ScreenShot_f
1451 ==================
1452 */
1453 void SCR_ScreenShot_f (void)
1454 {
1455         int i;
1456         char filename[16];
1457         char checkname[MAX_OSPATH];
1458 //
1459 // find a file name to save it to
1460 //
1461         strcpy(filename, "dp0000.tga");
1462
1463         for (i=0 ; i<=9999 ; i++)
1464         {
1465                 filename[2] = (i/1000)%10 + '0';
1466                 filename[3] = (i/ 100)%10 + '0';
1467                 filename[4] = (i/  10)%10 + '0';
1468                 filename[5] = (i/   1)%10 + '0';
1469                 sprintf (checkname, "%s/%s", com_gamedir, filename);
1470                 if (Sys_FileTime(checkname) == -1)
1471                         break;  // file doesn't exist
1472         }
1473         if (i==10000)
1474         {
1475                 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
1476                 return;
1477         }
1478
1479         SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight);
1480         Con_Printf ("Wrote %s\n", filename);
1481 }
1482
1483 /*
1484 ===============
1485 R_Envmap_f
1486
1487 Grab six views for environment mapping tests
1488 ===============
1489 */
1490 struct
1491 {
1492         float angles[3];
1493         char *name;
1494 }
1495 envmapinfo[6] =
1496 {
1497         {{  0,   0, 0}, "ft"},
1498         {{  0,  90, 0}, "rt"},
1499         {{  0, 180, 0}, "bk"},
1500         {{  0, 270, 0}, "lf"},
1501         {{-90,  90, 0}, "up"},
1502         {{ 90,  90, 0}, "dn"}
1503 };
1504 static void R_Envmap_f (void)
1505 {
1506         int j, size;
1507         char filename[256], basename[256];
1508
1509         if (Cmd_Argc() != 3)
1510         {
1511                 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");
1512                 return;
1513         }
1514
1515         if (!r_render.integer)
1516                 return;
1517
1518         strcpy(basename, Cmd_Argv(1));
1519         size = atoi(Cmd_Argv(2));
1520         if (size != 128 && size != 256 && size != 512 && size != 1024)
1521         {
1522                 Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
1523                 return;
1524         }
1525         if (size > vid.realwidth || size > vid.realheight)
1526         {
1527                 Con_Printf("envmap: your resolution is not big enough to render that size\n");
1528                 return;
1529         }
1530
1531         envmap = true;
1532
1533         r_refdef.x = 0;
1534         r_refdef.y = 0;
1535         r_refdef.width = size;
1536         r_refdef.height = size;
1537
1538         r_refdef.fov_x = 90;
1539         r_refdef.fov_y = 90;
1540
1541         for (j = 0;j < 6;j++)
1542         {
1543                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1544                 VectorCopy(envmapinfo[j].angles, r_refdef.viewangles);
1545                 R_ClearScreen();
1546                 R_RenderView ();
1547                 SCR_ScreenShot(filename, vid.realx, vid.realy, size, size);
1548         }
1549
1550         envmap = false;
1551 }
1552
1553 //=============================================================================
1554
1555 void R_ClearScreen(void)
1556 {
1557         if (r_render.integer)
1558         {
1559                 glClearColor(0,0,0,0);
1560                 CHECKGLERROR
1561                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
1562                 CHECKGLERROR
1563                 if (gl_dither.integer)
1564                         glEnable(GL_DITHER);
1565                 else
1566                         glDisable(GL_DITHER);
1567                 CHECKGLERROR
1568         }
1569 }
1570
1571 /*
1572 ==================
1573 SCR_UpdateScreen
1574
1575 This is called every frame, and can also be called explicitly to flush
1576 text to the screen.
1577 ==================
1578 */
1579 void SCR_UpdateScreen (void)
1580 {
1581         //Mem_CheckSentinelsGlobal();
1582         //R_TimeReport("memtest");
1583
1584         glFinish ();
1585         CHECKGLERROR
1586
1587         VID_Finish ();
1588
1589         R_TimeReport("finish");
1590
1591         if (gl_combine.integer && !gl_combine_extension)
1592                 Cvar_SetValue("gl_combine", 0);
1593
1594         lightscalebit = v_overbrightbits.integer;
1595         if (gl_combine.integer && r_multitexture.integer)
1596                 lightscalebit += 2;
1597
1598         lightscale = 1.0f / (float) (1 << lightscalebit);
1599         overbrightscale = 1.0f / (float) (1 << v_overbrightbits.integer);
1600
1601         R_TimeReport("setup");
1602
1603         R_ClearScreen();
1604
1605         R_TimeReport("clear");
1606
1607         if (scr_conlines < vid.conheight)
1608                 R_RenderView();
1609
1610         // draw 2D stuff
1611         R_DrawQueue();
1612 }