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