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