]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
coronas now scale with the light radius
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3
4 static int max_meshs;
5 static int max_batch;
6 static int max_verts; // always max_meshs * 3
7 #define TRANSDEPTHRES 4096
8
9 //static cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "21760"};
10 static cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "4096"};
11 static cvar_t gl_mesh_batchtriangles = {0, "gl_mesh_batchtriangles", "1024"};
12 static cvar_t gl_mesh_merge = {0, "gl_mesh_merge", "1"};
13 static cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
14 static cvar_t gl_mesh_dupetransverts = {0, "gl_mesh_dupetransverts", "0"};
15
16 typedef struct buf_mesh_s
17 {
18         struct buf_mesh_s *next;
19         int depthmask;
20         int depthtest;
21         int blendfunc1, blendfunc2;
22         int textures[MAX_TEXTUREUNITS];
23         float texturergbscale[MAX_TEXTUREUNITS];
24         int firsttriangle;
25         int triangles;
26         int firstvert;
27         int lastvert;
28 }
29 buf_mesh_t;
30
31 typedef struct buf_transtri_s
32 {
33         struct buf_transtri_s *next;
34         buf_mesh_t *mesh;
35         int index[3];
36 }
37 buf_transtri_t;
38
39 typedef struct buf_tri_s
40 {
41         int index[3];
42 }
43 buf_tri_t;
44
45 typedef struct
46 {
47         float v[4];
48 }
49 buf_vertex_t;
50
51 typedef struct
52 {
53         float c[4];
54 }
55 buf_fcolor_t;
56
57 typedef struct
58 {
59         byte c[4];
60 }
61 buf_bcolor_t;
62
63 typedef struct
64 {
65         float t[2];
66 }
67 buf_texcoord_t;
68
69 static float meshfarclip;
70 static int currentmesh, currenttriangle, currentvertex, backendunits, backendactive, meshmerge, floatcolors, transranout;
71 static buf_mesh_t *buf_mesh;
72 static buf_tri_t *buf_tri;
73 static buf_vertex_t *buf_vertex;
74 static buf_fcolor_t *buf_fcolor;
75 static buf_bcolor_t *buf_bcolor;
76 static buf_texcoord_t *buf_texcoord[MAX_TEXTUREUNITS];
77
78 static int currenttransmesh, currenttransvertex, currenttranstriangle;
79 static buf_mesh_t *buf_transmesh;
80 static buf_transtri_t *buf_transtri;
81 static buf_transtri_t **buf_transtri_list;
82 static buf_vertex_t *buf_transvertex;
83 static buf_fcolor_t *buf_transfcolor;
84 static buf_bcolor_t *buf_transbcolor;
85 static buf_texcoord_t *buf_transtexcoord[MAX_TEXTUREUNITS];
86
87 static mempool_t *gl_backend_mempool;
88 static int resizingbuffers = false;
89
90 static void gl_backend_start(void)
91 {
92         int i;
93
94         max_verts = max_meshs * 3;
95
96         if (!gl_backend_mempool)
97                 gl_backend_mempool = Mem_AllocPool("GL_Backend");
98
99 #define BACKENDALLOC(var, count, sizeofstruct)\
100         {\
101                 var = Mem_Alloc(gl_backend_mempool, count * sizeof(sizeofstruct));\
102                 if (var == NULL)\
103                         Sys_Error("gl_backend_start: unable to allocate memory\n");\
104                 memset(var, 0, count * sizeof(sizeofstruct));\
105         }
106
107         BACKENDALLOC(buf_mesh, max_meshs, buf_mesh_t)
108         BACKENDALLOC(buf_tri, max_meshs, buf_tri_t)
109         BACKENDALLOC(buf_vertex, max_verts, buf_vertex_t)
110         BACKENDALLOC(buf_fcolor, max_verts, buf_fcolor_t)
111         BACKENDALLOC(buf_bcolor, max_verts, buf_bcolor_t)
112
113         BACKENDALLOC(buf_transmesh, max_meshs, buf_mesh_t)
114         BACKENDALLOC(buf_transtri, max_meshs, buf_transtri_t)
115         BACKENDALLOC(buf_transtri_list, TRANSDEPTHRES, buf_transtri_t *)
116         BACKENDALLOC(buf_transvertex, max_verts, buf_vertex_t)
117         BACKENDALLOC(buf_transfcolor, max_verts, buf_fcolor_t)
118         BACKENDALLOC(buf_transbcolor, max_verts, buf_bcolor_t)
119
120         for (i = 0;i < MAX_TEXTUREUNITS;i++)
121         {
122                 // only allocate as many texcoord arrays as we need
123                 if (i < gl_textureunits)
124                 {
125                         BACKENDALLOC(buf_texcoord[i], max_verts, buf_texcoord_t)
126                         BACKENDALLOC(buf_transtexcoord[i], max_verts, buf_texcoord_t)
127                 }
128                 else
129                 {
130                         buf_texcoord[i] = NULL;
131                         buf_transtexcoord[i] = NULL;
132                 }
133         }
134         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
135         backendactive = true;
136 }
137
138 static void gl_backend_shutdown(void)
139 {
140         //int i;
141         /*
142 #define BACKENDFREE(var)\
143         if (var)\
144         {\
145                 Mem_Free(var);\
146                 var = NULL;\
147         }
148         */
149         /*
150 #define BACKENDFREE(var) var = NULL;
151
152         BACKENDFREE(buf_mesh)
153         BACKENDFREE(buf_tri)
154         BACKENDFREE(buf_vertex)
155         BACKENDFREE(buf_fcolor)
156         BACKENDFREE(buf_bcolor)
157
158         BACKENDFREE(buf_transmesh)
159         BACKENDFREE(buf_transtri)
160         BACKENDFREE(buf_transtri_list)
161         BACKENDFREE(buf_transvertex)
162         BACKENDFREE(buf_transfcolor)
163         BACKENDFREE(buf_transbcolor)
164
165         for (i = 0;i < MAX_TEXTUREUNITS;i++)
166         {
167                 BACKENDFREE(buf_texcoord[i])
168                 BACKENDFREE(buf_transtexcoord[i])
169         }
170         */
171
172         if (resizingbuffers)
173                 Mem_EmptyPool(gl_backend_mempool);
174         else
175                 Mem_FreePool(&gl_backend_mempool);
176
177         backendunits = 0;
178         backendactive = false;
179 }
180
181 static void gl_backend_bufferchanges(int init)
182 {
183         // 21760 is (65536 / 3) rounded off to a multiple of 128
184         if (gl_mesh_maxtriangles.integer < 256)
185                 Cvar_SetValue("gl_mesh_maxtriangles", 256);
186         if (gl_mesh_maxtriangles.integer > 21760)
187                 Cvar_SetValue("gl_mesh_maxtriangles", 21760);
188
189         if (gl_mesh_batchtriangles.integer < 0)
190                 Cvar_SetValue("gl_mesh_batchtriangles", 0);
191         if (gl_mesh_batchtriangles.integer > gl_mesh_maxtriangles.integer)
192                 Cvar_SetValue("gl_mesh_batchtriangles", gl_mesh_maxtriangles.integer);
193
194         max_batch = gl_mesh_batchtriangles.integer;
195
196         if (max_meshs != gl_mesh_maxtriangles.integer)
197         {
198                 max_meshs = gl_mesh_maxtriangles.integer;
199
200                 if (!init)
201                 {
202                         resizingbuffers = true;
203                         gl_backend_shutdown();
204                         gl_backend_start();
205                         resizingbuffers = false;
206                 }
207         }
208 }
209
210 float r_farclip, r_newfarclip;
211
212 static void gl_backend_newmap(void)
213 {
214         r_farclip = r_newfarclip = 2048.0f;
215 }
216
217 int polyindexarray[768];
218
219 void gl_backend_init(void)
220 {
221         int i;
222         Cvar_RegisterVariable(&gl_mesh_maxtriangles);
223         Cvar_RegisterVariable(&gl_mesh_batchtriangles);
224         Cvar_RegisterVariable(&gl_mesh_merge);
225         Cvar_RegisterVariable(&gl_mesh_floatcolors);
226         Cvar_RegisterVariable(&gl_mesh_dupetransverts);
227         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
228         gl_backend_bufferchanges(true);
229         for (i = 0;i < 256;i++)
230         {
231                 polyindexarray[i*3+0] = 0;
232                 polyindexarray[i*3+1] = i + 1;
233                 polyindexarray[i*3+2] = i + 2;
234         }
235 }
236
237 static float viewdist;
238
239 int c_meshtris;
240
241 // called at beginning of frame
242 void R_Mesh_Clear(void)
243 {
244         if (!backendactive)
245                 Sys_Error("R_Mesh_Clear: called when backend is not active\n");
246
247         gl_backend_bufferchanges(false);
248
249         currentmesh = 0;
250         currenttriangle = 0;
251         currentvertex = 0;
252         currenttransmesh = 0;
253         currenttranstriangle = 0;
254         currenttransvertex = 0;
255         meshfarclip = 0;
256         meshmerge = gl_mesh_merge.integer;
257         floatcolors = gl_mesh_floatcolors.integer;
258         transranout = false;
259         viewdist = DotProduct(r_origin, vpn);
260
261         c_meshtris = 0;
262 }
263
264 #ifdef DEBUGGL
265 void GL_PrintError(int errornumber, char *filename, int linenumber)
266 {
267         switch(errornumber)
268         {
269         case GL_INVALID_ENUM:
270                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
271                 break;
272         case GL_INVALID_VALUE:
273                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
274                 break;
275         case GL_INVALID_OPERATION:
276                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
277                 break;
278         case GL_STACK_OVERFLOW:
279                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
280                 break;
281         case GL_STACK_UNDERFLOW:
282                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
283                 break;
284         case GL_OUT_OF_MEMORY:
285                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
286                 break;
287 #ifdef GL_TABLE_TOO_LARGE
288     case GL_TABLE_TOO_LARGE:
289                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
290                 break;
291 #endif
292         default:
293                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
294                 break;
295         }
296 }
297
298 int errornumber = 0;
299 #endif
300
301 // renders mesh buffers, called to flush buffers when full
302 void R_Mesh_Render(void)
303 {
304         int i, k, blendfunc1, blendfunc2, blend, depthmask, depthtest, unit = 0, clientunit = 0, firsttriangle, triangles, firstvert, lastvert, texture[MAX_TEXTUREUNITS];
305         float farclip, texturergbscale[MAX_TEXTUREUNITS];
306         buf_mesh_t *mesh;
307         if (!backendactive)
308                 Sys_Error("R_Mesh_Render: called when backend is not active\n");
309         if (!currentmesh)
310                 return;
311
312 CHECKGLERROR
313
314         // push out farclip based on vertices
315         for (i = 0;i < currentvertex;i++)
316         {
317                 farclip = DotProduct(buf_vertex[i].v, vpn);
318                 if (meshfarclip < farclip)
319                         meshfarclip = farclip;
320         }
321
322         farclip = meshfarclip + 256.0f - viewdist; // + 256 just to be safe
323
324         // push out farclip for next frame
325         if (farclip > r_newfarclip)
326                 r_newfarclip = ceil((farclip + 255) / 256) * 256 + 256;
327
328         for (i = 0;i < backendunits;i++)
329                 texturergbscale[i] = 1;
330
331         glEnable(GL_CULL_FACE);
332 CHECKGLERROR
333         glCullFace(GL_FRONT);
334 CHECKGLERROR
335         depthtest = true;
336         glEnable(GL_DEPTH_TEST);
337 CHECKGLERROR
338         blendfunc1 = GL_ONE;
339         blendfunc2 = GL_ZERO;
340         glBlendFunc(blendfunc1, blendfunc2);
341 CHECKGLERROR
342         blend = 0;
343         glDisable(GL_BLEND);
344 CHECKGLERROR
345         depthmask = true;
346         glDepthMask((GLboolean) depthmask);
347 CHECKGLERROR
348
349         glVertexPointer(3, GL_FLOAT, sizeof(buf_vertex_t), buf_vertex);
350 CHECKGLERROR
351         glEnableClientState(GL_VERTEX_ARRAY);
352 CHECKGLERROR
353         if (floatcolors)
354         {
355                 glColorPointer(4, GL_FLOAT, sizeof(buf_fcolor_t), buf_fcolor);
356 CHECKGLERROR
357         }
358         else
359         {
360                 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(buf_bcolor_t), buf_bcolor);
361 CHECKGLERROR
362         }
363         glEnableClientState(GL_COLOR_ARRAY);
364 CHECKGLERROR
365
366         if (backendunits > 1)
367         {
368                 for (i = 0;i < backendunits;i++)
369                 {
370                         qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
371 CHECKGLERROR
372                         glBindTexture(GL_TEXTURE_2D, (texture[i] = 0));
373 CHECKGLERROR
374                         glDisable(GL_TEXTURE_2D);
375 CHECKGLERROR
376                         if (gl_combine.integer)
377                         {
378                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
379 CHECKGLERROR
380                                 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
381 CHECKGLERROR
382                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
383 CHECKGLERROR
384                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
385 CHECKGLERROR
386                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);
387 CHECKGLERROR
388                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
389 CHECKGLERROR
390                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
391 CHECKGLERROR
392                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);
393 CHECKGLERROR
394                                 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
395 CHECKGLERROR
396                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
397 CHECKGLERROR
398                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
399 CHECKGLERROR
400                                 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);
401 CHECKGLERROR
402                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
403 CHECKGLERROR
404                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
405 CHECKGLERROR
406                                 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
407 CHECKGLERROR
408                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
409 CHECKGLERROR
410                                 glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0f);
411 CHECKGLERROR
412                         }
413                         else
414                         {
415                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
416 CHECKGLERROR
417                         }
418
419                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
420 CHECKGLERROR
421                         glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[i]);
422 CHECKGLERROR
423                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
424 CHECKGLERROR
425                 }
426         }
427         else
428         {
429                 glBindTexture(GL_TEXTURE_2D, (texture[0] = 0));
430 CHECKGLERROR
431                 glDisable(GL_TEXTURE_2D);
432 CHECKGLERROR
433                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
434 CHECKGLERROR
435
436                 glTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[0]);
437 CHECKGLERROR
438                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
439 CHECKGLERROR
440         }
441
442         // lock as early as possible
443         GL_LockArray(0, currentvertex);
444 CHECKGLERROR
445
446         for (k = 0;k < currentmesh;)
447         {
448                 mesh = &buf_mesh[k];
449
450                 if (backendunits > 1)
451                 {
452 //                      int topunit = 0;
453                         for (i = 0;i < backendunits;i++)
454                         {
455                                 if (texture[i] != mesh->textures[i])
456                                 {
457                                         if (unit != i)
458                                         {
459                                                 qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
460 CHECKGLERROR
461                                         }
462                                         if (texture[i] == 0)
463                                         {
464                                                 glEnable(GL_TEXTURE_2D);
465 CHECKGLERROR
466                                                 // have to disable texcoord array on disabled texture
467                                                 // units due to NVIDIA driver bug with
468                                                 // compiled_vertex_array
469                                                 if (clientunit != i)
470                                                 {
471                                                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
472 CHECKGLERROR
473                                                 }
474                                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
475 CHECKGLERROR
476                                         }
477                                         glBindTexture(GL_TEXTURE_2D, (texture[i] = mesh->textures[i]));
478 CHECKGLERROR
479                                         if (texture[i] == 0)
480                                         {
481                                                 glDisable(GL_TEXTURE_2D);
482 CHECKGLERROR
483                                                 // have to disable texcoord array on disabled texture
484                                                 // units due to NVIDIA driver bug with
485                                                 // compiled_vertex_array
486                                                 if (clientunit != i)
487                                                 {
488                                                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
489 CHECKGLERROR
490                                                 }
491                                                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
492 CHECKGLERROR
493                                         }
494                                 }
495                                 if (texturergbscale[i] != mesh->texturergbscale[i])
496                                 {
497                                         if (unit != i)
498                                         {
499                                                 qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
500 CHECKGLERROR
501                                         }
502                                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (texturergbscale[i] = mesh->texturergbscale[i]));
503 CHECKGLERROR
504                                 }
505 //                              if (texture[i])
506 //                                      topunit = i;
507                         }
508 //                      if (unit != topunit)
509 //                      {
510 //                              qglActiveTexture(GL_TEXTURE0_ARB + (unit = topunit));
511 //CHECKGLERROR
512 //                      }
513                 }
514                 else
515                 {
516                         if (texture[0] != mesh->textures[0])
517                         {
518                                 if (texture[0] == 0)
519                                 {
520                                         glEnable(GL_TEXTURE_2D);
521 CHECKGLERROR
522                                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
523 CHECKGLERROR
524                                 }
525                                 glBindTexture(GL_TEXTURE_2D, (texture[0] = mesh->textures[0]));
526 CHECKGLERROR
527                                 if (texture[0] == 0)
528                                 {
529                                         glDisable(GL_TEXTURE_2D);
530 CHECKGLERROR
531                                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
532 CHECKGLERROR
533                                 }
534                         }
535                 }
536                 if (blendfunc1 != mesh->blendfunc1 || blendfunc2 != mesh->blendfunc2)
537                 {
538                         blendfunc1 = mesh->blendfunc1;
539                         blendfunc2 = mesh->blendfunc2;
540                         glBlendFunc(blendfunc1, blendfunc2);
541 CHECKGLERROR
542                         if (blendfunc2 == GL_ZERO)
543                         {
544                                 if (blendfunc1 == GL_ONE)
545                                 {
546                                         if (blend)
547                                         {
548                                                 blend = 0;
549                                                 glDisable(GL_BLEND);
550 CHECKGLERROR
551                                         }
552                                 }
553                                 else
554                                 {
555                                         if (!blend)
556                                         {
557                                                 blend = 1;
558                                                 glEnable(GL_BLEND);
559 CHECKGLERROR
560                                         }
561                                 }
562                         }
563                         else
564                         {
565                                 if (!blend)
566                                 {
567                                         blend = 1;
568                                         glEnable(GL_BLEND);
569 CHECKGLERROR
570                                 }
571                         }
572                 }
573                 if (depthtest != mesh->depthtest)
574                 {
575                         depthtest = mesh->depthtest;
576                         if (depthtest)
577                                 glEnable(GL_DEPTH_TEST);
578                         else
579                                 glDisable(GL_DEPTH_TEST);
580                 }
581                 if (depthmask != mesh->depthmask)
582                 {
583                         depthmask = mesh->depthmask;
584                         glDepthMask((GLboolean) depthmask);
585 CHECKGLERROR
586                 }
587
588                 firsttriangle = mesh->firsttriangle;
589                 triangles = mesh->triangles;
590                 firstvert = mesh->firstvert;
591                 lastvert = mesh->lastvert;
592                 mesh = &buf_mesh[++k];
593
594                 if (meshmerge)
595                 {
596                         #if MAX_TEXTUREUNITS != 4
597                         #error update this code
598                         #endif
599                         while (k < currentmesh
600                                 && mesh->blendfunc1 == blendfunc1
601                                 && mesh->blendfunc2 == blendfunc2
602                                 && mesh->depthtest == depthtest
603                                 && mesh->depthmask == depthmask
604                                 && mesh->textures[0] == texture[0]
605                                 && mesh->textures[1] == texture[1]
606                                 && mesh->textures[2] == texture[2]
607                                 && mesh->textures[3] == texture[3]
608                                 && mesh->texturergbscale[0] == texturergbscale[0]
609                                 && mesh->texturergbscale[1] == texturergbscale[1]
610                                 && mesh->texturergbscale[2] == texturergbscale[2]
611                                 && mesh->texturergbscale[3] == texturergbscale[3])
612                         {
613                                 triangles += mesh->triangles;
614                                 if (firstvert > mesh->firstvert)
615                                         firstvert = mesh->firstvert;
616                                 if (lastvert < mesh->lastvert)
617                                         lastvert = mesh->lastvert;
618                                 mesh = &buf_mesh[++k];
619                         }
620                 }
621
622 #ifdef WIN32
623                 // FIXME: dynamic link to GL so we can get DrawRangeElements on WIN32
624                 glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_INT, (unsigned int *)&buf_tri[firsttriangle]);
625 #else
626                 glDrawRangeElements(GL_TRIANGLES, firstvert, lastvert + 1, triangles * 3, GL_UNSIGNED_INT, (unsigned int *)&buf_tri[firsttriangle]);
627 #endif
628 CHECKGLERROR
629         }
630
631         currentmesh = 0;
632         currenttriangle = 0;
633         currentvertex = 0;
634
635         GL_UnlockArray();
636 CHECKGLERROR
637
638         if (backendunits > 1)
639         {
640                 for (i = backendunits - 1;i >= 0;i--)
641                 {
642                         qglActiveTexture(GL_TEXTURE0_ARB + (unit = i));
643 CHECKGLERROR
644                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
645 CHECKGLERROR
646                         if (gl_combine.integer)
647                         {
648                                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
649 CHECKGLERROR
650                         }
651                         if (i > 0)
652                         {
653                                 glDisable(GL_TEXTURE_2D);
654 CHECKGLERROR
655                         }
656                         else
657                         {
658                                 glEnable(GL_TEXTURE_2D);
659 CHECKGLERROR
660                         }
661                         glBindTexture(GL_TEXTURE_2D, 0);
662 CHECKGLERROR
663
664                         qglClientActiveTexture(GL_TEXTURE0_ARB + (clientunit = i));
665 CHECKGLERROR
666                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
667 CHECKGLERROR
668                 }
669         }
670         else
671         {
672                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
673 CHECKGLERROR
674                 glEnable(GL_TEXTURE_2D);
675 CHECKGLERROR
676                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
677 CHECKGLERROR
678         }
679         glDisableClientState(GL_COLOR_ARRAY);
680 CHECKGLERROR
681         glDisableClientState(GL_VERTEX_ARRAY);
682 CHECKGLERROR
683
684         glDisable(GL_BLEND);
685 CHECKGLERROR
686         glEnable(GL_DEPTH_TEST);
687 CHECKGLERROR
688         glDepthMask(true);
689 CHECKGLERROR
690         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
691 CHECKGLERROR
692 }
693
694 void R_Mesh_AddTransparent(void)
695 {
696         if (gl_mesh_dupetransverts.integer)
697         {
698                 int i, j, k, index;
699                 float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
700                 buf_vertex_t *vert1, *vert2, *vert3;
701                 buf_transtri_t *tri;
702                 buf_mesh_t *mesh;
703
704                 // process and add transparent mesh triangles
705                 if (!currenttranstriangle)
706                         return;
707
708                 // map farclip to 0-4095 list range
709                 centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
710                 viewdistcompare = viewdist + 4.0f;
711
712                 memset(buf_transtri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
713
714                 // process in reverse because transtri_list adding code is in reverse as well
715                 k = 0;
716                 for (j = currenttranstriangle - 1;j >= 0;j--)
717                 {
718                         tri = &buf_transtri[j];
719
720                         vert1 = &buf_transvertex[tri->index[0]];
721                         vert2 = &buf_transvertex[tri->index[1]];
722                         vert3 = &buf_transvertex[tri->index[2]];
723
724                         dist1 = DotProduct(vert1->v, vpn);
725                         dist2 = DotProduct(vert2->v, vpn);
726                         dist3 = DotProduct(vert3->v, vpn);
727
728                         maxdist = max(dist1, max(dist2, dist3));
729                         if (maxdist < viewdistcompare)
730                                 continue;
731
732                         center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
733         #if SLOWMATH
734                         i = (int) center;
735                         i = bound(0, i, (TRANSDEPTHRES - 1));
736         #else
737                         if (center < 0.0f)
738                                 center = 0.0f;
739                         center += 8388608.0f;
740                         i = *((long *)&center) & 0x7FFFFF;
741                         i = min(i, (TRANSDEPTHRES - 1));
742         #endif
743                         tri->next = buf_transtri_list[i];
744                         buf_transtri_list[i] = tri;
745                         k++;
746                 }
747
748                 if (currentmesh + k > max_meshs || currenttriangle + k > max_batch || currentvertex + k * 3 > max_verts)
749                         R_Mesh_Render();
750
751                 currenttransmesh = 0;
752                 currenttranstriangle = 0;
753                 currenttransvertex = 0;
754
755                 // note: can't batch these because they can be rendered in any order
756                 // there can never be more transparent triangles than fit in main buffers
757                 for (j = TRANSDEPTHRES - 1;j >= 0;j--)
758                 {
759                         if ((tri = buf_transtri_list[j]))
760                         {
761                                 while(tri)
762                                 {
763                                         mesh = &buf_mesh[currentmesh++];
764                                         *mesh = *tri->mesh; // copy mesh properties
765                                         mesh->firstvert = currentvertex;
766                                         mesh->lastvert = currentvertex + 2;
767                                         mesh->firsttriangle = currenttriangle;
768                                         mesh->triangles = 1;
769                                         for (k = 0;k < 3;k++)
770                                         {
771                                                 index = tri->index[k];
772                                                 buf_tri[currenttriangle].index[k] = currentvertex;
773                                                 memcpy(buf_vertex[currentvertex].v, buf_transvertex[index].v, sizeof(buf_vertex_t));
774                                                 if (floatcolors)
775                                                         memcpy(buf_fcolor[currentvertex].c, buf_transfcolor[index].c, sizeof(buf_fcolor_t));
776                                                 else
777                                                         memcpy(buf_bcolor[currentvertex].c, buf_transbcolor[index].c, sizeof(buf_bcolor_t));
778                                                 for (i = 0;i < backendunits && tri->mesh->textures[i];i++)
779                                                         memcpy(buf_texcoord[i][currentvertex].t, buf_transtexcoord[i][index].t, sizeof(buf_texcoord_t));
780                                                 currentvertex++;
781                                         }
782                                         currenttriangle++;
783                                         tri = tri->next;
784                                 }
785                         }
786                 }
787         }
788         else
789         {
790                 int i, j, k;
791                 float viewdistcompare, centerscaler, dist1, dist2, dist3, center, maxdist;
792                 buf_vertex_t *vert1, *vert2, *vert3;
793                 buf_transtri_t *tri;
794                 buf_mesh_t *mesh;
795
796                 // process and add transparent mesh triangles
797                 if (!currenttranstriangle)
798                         return;
799
800                 // map farclip to 0-4095 list range
801                 centerscaler = (TRANSDEPTHRES / r_farclip) * (1.0f / 3.0f);
802                 viewdistcompare = viewdist + 4.0f;
803
804                 memset(buf_transtri_list, 0, TRANSDEPTHRES * sizeof(buf_transtri_t *));
805
806                 // process in reverse because transtri_list adding code is in reverse as well
807                 k = 0;
808                 for (j = currenttranstriangle - 1;j >= 0;j--)
809                 {
810                         tri = &buf_transtri[j];
811
812                         vert1 = &buf_transvertex[tri->index[0]];
813                         vert2 = &buf_transvertex[tri->index[1]];
814                         vert3 = &buf_transvertex[tri->index[2]];
815
816                         dist1 = DotProduct(vert1->v, vpn);
817                         dist2 = DotProduct(vert2->v, vpn);
818                         dist3 = DotProduct(vert3->v, vpn);
819
820                         maxdist = max(dist1, max(dist2, dist3));
821                         if (maxdist < viewdistcompare)
822                                 continue;
823
824                         center = (dist1 + dist2 + dist3) * centerscaler - viewdist;
825         #if SLOWMATH
826                         i = (int) center;
827                         i = bound(0, i, (TRANSDEPTHRES - 1));
828         #else
829                         if (center < 0.0f)
830                                 center = 0.0f;
831                         center += 8388608.0f;
832                         i = *((long *)&center) & 0x7FFFFF;
833                         i = min(i, (TRANSDEPTHRES - 1));
834         #endif
835                         tri->next = buf_transtri_list[i];
836                         buf_transtri_list[i] = tri;
837                         k++;
838                 }
839
840                 if (currentmesh + k > max_meshs || currenttriangle + k > max_batch || currentvertex + currenttransvertex > max_verts)
841                         R_Mesh_Render();
842
843                 // note: can't batch these because they can be rendered in any order
844                 // there can never be more transparent triangles than fit in main buffers
845                 memcpy(&buf_vertex[currentvertex], &buf_transvertex[0], currenttransvertex * sizeof(buf_vertex_t));
846                 if (floatcolors)
847                         memcpy(&buf_fcolor[currentvertex], &buf_transfcolor[0], currenttransvertex * sizeof(buf_fcolor_t));
848                 else
849                         memcpy(&buf_fcolor[currentvertex], &buf_transbcolor[0], currenttransvertex * sizeof(buf_bcolor_t));
850                 for (i = 0;i < backendunits;i++)
851                         memcpy(&buf_texcoord[i][currentvertex], &buf_transtexcoord[i][0], currenttransvertex * sizeof(buf_texcoord_t));
852
853                 for (j = TRANSDEPTHRES - 1;j >= 0;j--)
854                 {
855                         if ((tri = buf_transtri_list[j]))
856                         {
857                                 while(tri)
858                                 {
859                                         mesh = &buf_mesh[currentmesh++];
860                                         *mesh = *tri->mesh; // copy mesh properties
861                                         buf_tri[currenttriangle].index[0] = tri->index[0] + currentvertex;
862                                         buf_tri[currenttriangle].index[1] = tri->index[1] + currentvertex;
863                                         buf_tri[currenttriangle].index[2] = tri->index[2] + currentvertex;
864                                         mesh->firstvert = min(buf_tri[currenttriangle].index[0], min(buf_tri[currenttriangle].index[1], buf_tri[currenttriangle].index[2]));
865                                         mesh->lastvert = max(buf_tri[currenttriangle].index[0], max(buf_tri[currenttriangle].index[1], buf_tri[currenttriangle].index[2]));
866                                         mesh->firsttriangle = currenttriangle++;
867                                         mesh->triangles = 1;
868                                         tri = tri->next;
869                                 }
870                         }
871                 }
872                 currentvertex += currenttransvertex;
873                 currenttransmesh = 0;
874                 currenttranstriangle = 0;
875                 currenttransvertex = 0;
876         }
877 }
878
879 void R_Mesh_Draw(const rmeshinfo_t *m)
880 {
881         // these are static because gcc runs out of virtual registers otherwise
882         static int i, j, *index, overbright;
883         static float c, *in, scaler, cr, cg, cb, ca;
884         static buf_mesh_t *mesh;
885         static buf_vertex_t *vert;
886         static buf_fcolor_t *fcolor;
887         static buf_bcolor_t *bcolor;
888         static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
889         static buf_transtri_t *tri;
890         static byte br, bg, bb, ba;
891
892         if (m->index == NULL
893          || !m->numtriangles
894          || m->vertex == NULL
895          || !m->numverts)
896                 return;
897         // ignore meaningless alpha meshs
898         if (!m->depthwrite && m->blendfunc1 == GL_SRC_ALPHA && (m->blendfunc2 == GL_ONE || m->blendfunc2 == GL_ONE_MINUS_SRC_ALPHA))
899         {
900                 if (m->color)
901                 {
902                         for (i = 0, in = m->color + 3;i < m->numverts;i++, (int)in += m->colorstep)
903                                 if (*in >= 0.01f)
904                                         break;
905                         if (i == m->numverts)
906                                 return;
907                 }
908                 else if (m->ca < 0.01f)
909                         return;
910         }
911
912         if (!backendactive)
913                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
914
915         scaler = 1;
916         if (m->blendfunc2 == GL_SRC_COLOR)
917         {
918                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
919                         scaler *= 0.5f;
920         }
921         else
922         {
923                 if (m->tex[0])
924                 {
925                         overbright = gl_combine.integer;
926                         if (overbright)
927                                 scaler *= 0.25f;
928                 }
929                 if (lighthalf)
930                         scaler *= 0.5f;
931         }
932
933         if (m->transparent)
934         {
935                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
936                 {
937                         if (!transranout)
938                         {
939                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
940                                 transranout = true;
941                         }
942                         return;
943                 }
944
945                 vert = &buf_transvertex[currenttransvertex];
946                 fcolor = &buf_transfcolor[currenttransvertex];
947                 bcolor = &buf_transbcolor[currenttransvertex];
948                 for (i = 0;i < backendunits;i++)
949                         texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
950
951                 // transmesh is only for storage of transparent meshs until they
952                 // are inserted into the main mesh array
953                 mesh = &buf_transmesh[currenttransmesh++];
954                 mesh->blendfunc1 = m->blendfunc1;
955                 mesh->blendfunc2 = m->blendfunc2;
956                 mesh->depthmask = false;
957                 mesh->depthtest = !m->depthdisable;
958                 j = -1;
959                 for (i = 0;i < backendunits;i++)
960                 {
961                         if ((mesh->textures[i] = m->tex[i]))
962                                 j = i;
963                         mesh->texturergbscale[i] = m->texrgbscale[i];
964                         if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
965                                 mesh->texturergbscale[i] = 1;
966                 }
967                 if (overbright && j >= 0)
968                         mesh->texturergbscale[j] = 4;
969
970                 // transparent meshs are broken up into individual triangles which can
971                 // be sorted by depth
972                 index = m->index;
973                 for (i = 0;i < m->numtriangles;i++)
974                 {
975                         tri = &buf_transtri[currenttranstriangle++];
976                         tri->mesh = mesh;
977                         tri->index[0] = *index++ + currenttransvertex;
978                         tri->index[1] = *index++ + currenttransvertex;
979                         tri->index[2] = *index++ + currenttransvertex;
980                 }
981
982                 currenttransvertex += m->numverts;
983         }
984         else
985         {
986                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
987                 {
988                         Con_Printf("R_Mesh_Draw: mesh too big for buffers\n");
989                         return;
990                 }
991
992                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
993                         R_Mesh_Render();
994
995                 vert = &buf_vertex[currentvertex];
996                 fcolor = &buf_fcolor[currentvertex];
997                 bcolor = &buf_bcolor[currentvertex];
998                 for (i = 0;i < backendunits;i++)
999                         texcoord[i] = &buf_texcoord[i][currentvertex];
1000
1001                 mesh = &buf_mesh[currentmesh++];
1002                 mesh->blendfunc1 = m->blendfunc1;
1003                 mesh->blendfunc2 = m->blendfunc2;
1004                 mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
1005                 mesh->depthtest = !m->depthdisable;
1006                 mesh->firsttriangle = currenttriangle;
1007                 mesh->triangles = m->numtriangles;
1008                 j = -1;
1009                 for (i = 0;i < backendunits;i++)
1010                 {
1011                         if ((mesh->textures[i] = m->tex[i]))
1012                                 j = i;
1013                         mesh->texturergbscale[i] = m->texrgbscale[i];
1014                         if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
1015                                 mesh->texturergbscale[i] = 1;
1016                 }
1017                 if (overbright && j >= 0)
1018                         mesh->texturergbscale[j] = 4;
1019
1020                 // opaque meshs are rendered directly
1021                 index = (int *)&buf_tri[currenttriangle];
1022                 for (i = 0;i < m->numtriangles * 3;i++)
1023                         index[i] = m->index[i] + currentvertex;
1024                 mesh->firstvert = currentvertex;
1025                 currenttriangle += m->numtriangles;
1026                 currentvertex += m->numverts;
1027                 mesh->lastvert = currentvertex - 1;
1028         }
1029
1030         // vertex array code is shared for transparent and opaque meshs
1031
1032         c_meshtris += m->numtriangles;
1033
1034         if (m->vertexstep != sizeof(buf_vertex_t))
1035         {
1036                 for (i = 0, in = m->vertex;i < m->numverts;i++, (int)in += m->vertexstep)
1037                 {
1038                         vert[i].v[0] = in[0];
1039                         vert[i].v[1] = in[1];
1040                         vert[i].v[2] = in[2];
1041                 }
1042         }
1043         else
1044                 memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
1045
1046         if (floatcolors)
1047         {
1048                 if (m->color)
1049                 {
1050                         for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
1051                         {
1052                                 fcolor[i].c[0] = in[0] * scaler;
1053                                 fcolor[i].c[1] = in[1] * scaler;
1054                                 fcolor[i].c[2] = in[2] * scaler;
1055                                 fcolor[i].c[3] = in[3];
1056                         }
1057                 }
1058                 else
1059                 {
1060                         cr = m->cr * scaler;
1061                         cg = m->cg * scaler;
1062                         cb = m->cb * scaler;
1063                         ca = m->ca;
1064                         for (i = 0;i < m->numverts;i++)
1065                         {
1066                                 fcolor[i].c[0] = cr;
1067                                 fcolor[i].c[1] = cg;
1068                                 fcolor[i].c[2] = cb;
1069                                 fcolor[i].c[3] = ca;
1070                         }
1071                 }
1072         }
1073         else
1074         {
1075                 if (m->color)
1076                 {
1077                         for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
1078                         {
1079                                 // shift float to have 8bit fraction at base of number,
1080                                 // then read as integer and kill float bits...
1081                                 c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[0] = (byte) j;
1082                                 c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[1] = (byte) j;
1083                                 c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[2] = (byte) j;
1084                                 c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[3] = (byte) j;
1085                         }
1086                 }
1087                 else
1088                 {
1089                         c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;br = (byte) j;
1090                         c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bg = (byte) j;
1091                         c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bb = (byte) j;
1092                         c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;ba = (byte) j;
1093                         for (i = 0;i < m->numverts;i++)
1094                         {
1095                                 bcolor[i].c[0] = br;
1096                                 bcolor[i].c[1] = bg;
1097                                 bcolor[i].c[2] = bb;
1098                                 bcolor[i].c[3] = ba;
1099                         }
1100                 }
1101         }
1102
1103         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
1104         {
1105                 if (j >= backendunits)
1106                         Sys_Error("R_Mesh_Draw: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
1107                 if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
1108                 {
1109                         for (i = 0, in = m->texcoords[j];i < m->numverts;i++, (int)in += m->texcoordstep[j])
1110                         {
1111                                 texcoord[j][i].t[0] = in[0];
1112                                 texcoord[j][i].t[1] = in[1];
1113                         }
1114                 }
1115                 else
1116                         memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
1117         }
1118         #if 0
1119         for (;j < backendunits;j++)
1120                 memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
1121         #endif
1122 }
1123
1124 void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
1125 {
1126         m->index = polyindexarray;
1127         m->numverts = numverts;
1128         m->numtriangles = numverts - 2;
1129         if (m->numtriangles < 1)
1130         {
1131                 Con_Printf("R_Mesh_DrawPolygon: invalid vertex count\n");
1132                 return;
1133         }
1134         if (m->numtriangles >= 256)
1135         {
1136                 Con_Printf("R_Mesh_DrawPolygon: only up to 256 triangles (258 verts) supported\n");
1137                 return;
1138         }
1139         R_Mesh_Draw(m);
1140 }
1141
1142 // LordHavoc: this thing is evil, but necessary because decals account for so much overhead
1143 void R_Mesh_DrawDecal(const rmeshinfo_t *m)
1144 {
1145         // these are static because gcc runs out of virtual registers otherwise
1146         static int i, j, *index, overbright;
1147         static float c, *in, scaler, cr, cg, cb, ca;
1148         static buf_mesh_t *mesh;
1149         static buf_vertex_t *vert;
1150         static buf_fcolor_t *fcolor;
1151         static buf_bcolor_t *bcolor;
1152         static buf_texcoord_t *texcoord;
1153         static buf_transtri_t *tri;
1154         static byte br, bg, bb, ba;
1155
1156         if (!backendactive)
1157                 Sys_Error("R_Mesh_Draw: called when backend is not active\n");
1158
1159         scaler = 1;
1160         if (m->tex[0])
1161         {
1162                 overbright = gl_combine.integer;
1163                 if (overbright)
1164                         scaler *= 0.25f;
1165         }
1166         if (lighthalf)
1167                 scaler *= 0.5f;
1168
1169         if (m->transparent)
1170         {
1171                 if (currenttransmesh >= max_meshs || (currenttranstriangle + 2) > max_meshs || (currenttransvertex + 4) > max_verts)
1172                 {
1173                         if (!transranout)
1174                         {
1175                                 Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
1176                                 transranout = true;
1177                         }
1178                         return;
1179                 }
1180
1181                 vert = &buf_transvertex[currenttransvertex];
1182                 fcolor = &buf_transfcolor[currenttransvertex];
1183                 bcolor = &buf_transbcolor[currenttransvertex];
1184                 texcoord = &buf_transtexcoord[0][currenttransvertex];
1185
1186                 // transmesh is only for storage of transparent meshs until they
1187                 // are inserted into the main mesh array
1188                 mesh = &buf_transmesh[currenttransmesh++];
1189                 mesh->blendfunc1 = m->blendfunc1;
1190                 mesh->blendfunc2 = m->blendfunc2;
1191                 mesh->depthmask = false;
1192                 mesh->depthtest = true;
1193                 mesh->textures[0] = m->tex[0];
1194                 mesh->texturergbscale[0] = overbright ? 4 : 1;
1195                 for (i = 1;i < backendunits;i++)
1196                 {
1197                         mesh->textures[i] = 0;
1198                         mesh->texturergbscale[i] = 1;
1199                 }
1200
1201                 // transparent meshs are broken up into individual triangles which can
1202                 // be sorted by depth
1203                 index = m->index;
1204                 tri = &buf_transtri[currenttranstriangle++];
1205                 tri->mesh = mesh;
1206                 tri->index[0] = 0 + currenttransvertex;
1207                 tri->index[1] = 1 + currenttransvertex;
1208                 tri->index[2] = 2 + currenttransvertex;
1209                 tri = &buf_transtri[currenttranstriangle++];
1210                 tri->mesh = mesh;
1211                 tri->index[0] = 0 + currenttransvertex;
1212                 tri->index[1] = 2 + currenttransvertex;
1213                 tri->index[2] = 3 + currenttransvertex;
1214
1215                 currenttransvertex += 4;
1216         }
1217         else
1218         {
1219                 if (2 > max_meshs || 4 > max_verts)
1220                 {
1221                         Con_Printf("R_Mesh_Draw: mesh too big for buffers\n");
1222                         return;
1223                 }
1224
1225                 if (currentmesh >= max_meshs || (currenttriangle + 2) > max_batch || (currentvertex + 4) > max_verts)
1226                         R_Mesh_Render();
1227
1228                 vert = &buf_vertex[currentvertex];
1229                 fcolor = &buf_fcolor[currentvertex];
1230                 bcolor = &buf_bcolor[currentvertex];
1231                 texcoord = &buf_texcoord[0][currentvertex];
1232
1233                 mesh = &buf_mesh[currentmesh++];
1234                 mesh->blendfunc1 = m->blendfunc1;
1235                 mesh->blendfunc2 = m->blendfunc2;
1236                 mesh->depthmask = false;
1237                 mesh->depthtest = !m->depthdisable;
1238                 mesh->firsttriangle = currenttriangle;
1239                 mesh->triangles = 2;
1240                 mesh->textures[0] = m->tex[0];
1241                 mesh->texturergbscale[0] = overbright ? 4 : 1;
1242                 for (i = 1;i < backendunits;i++)
1243                 {
1244                         mesh->textures[i] = 0;
1245                         mesh->texturergbscale[i] = 1;
1246                 }
1247
1248                 // opaque meshs are rendered directly
1249                 index = (int *)&buf_tri[currenttriangle];
1250                 index[0] = 0 + currentvertex;
1251                 index[1] = 1 + currentvertex;
1252                 index[2] = 2 + currentvertex;
1253                 index[3] = 0 + currentvertex;
1254                 index[4] = 2 + currentvertex;
1255                 index[5] = 3 + currentvertex;
1256                 mesh->firstvert = currentvertex;
1257                 currenttriangle += 2;
1258                 currentvertex += 4;
1259                 mesh->lastvert = currentvertex - 1;
1260         }
1261
1262         // vertex array code is shared for transparent and opaque meshs
1263
1264         c_meshtris += 2;
1265
1266         // buf_vertex_t must match the size of the decal vertex array (or vice versa)
1267         memcpy(vert, m->vertex, 4 * sizeof(buf_vertex_t));
1268
1269         if (floatcolors)
1270         {
1271                 cr = m->cr * scaler;
1272                 cg = m->cg * scaler;
1273                 cb = m->cb * scaler;
1274                 ca = m->ca;
1275                 fcolor[0].c[0] = cr;
1276                 fcolor[0].c[1] = cg;
1277                 fcolor[0].c[2] = cb;
1278                 fcolor[0].c[3] = ca;
1279                 fcolor[1].c[0] = cr;
1280                 fcolor[1].c[1] = cg;
1281                 fcolor[1].c[2] = cb;
1282                 fcolor[1].c[3] = ca;
1283                 fcolor[2].c[0] = cr;
1284                 fcolor[2].c[1] = cg;
1285                 fcolor[2].c[2] = cb;
1286                 fcolor[2].c[3] = ca;
1287                 fcolor[3].c[0] = cr;
1288                 fcolor[3].c[1] = cg;
1289                 fcolor[3].c[2] = cb;
1290                 fcolor[3].c[3] = ca;
1291         }
1292         else
1293         {
1294                 c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;br = (byte) j;
1295                 c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bg = (byte) j;
1296                 c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bb = (byte) j;
1297                 c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;ba = (byte) j;
1298                 bcolor[0].c[0] = br;
1299                 bcolor[0].c[1] = bg;
1300                 bcolor[0].c[2] = bb;
1301                 bcolor[0].c[3] = ba;
1302                 bcolor[1].c[0] = br;
1303                 bcolor[1].c[1] = bg;
1304                 bcolor[1].c[2] = bb;
1305                 bcolor[1].c[3] = ba;
1306                 bcolor[2].c[0] = br;
1307                 bcolor[2].c[1] = bg;
1308                 bcolor[2].c[2] = bb;
1309                 bcolor[2].c[3] = ba;
1310                 bcolor[3].c[0] = br;
1311                 bcolor[3].c[1] = bg;
1312                 bcolor[3].c[2] = bb;
1313                 bcolor[3].c[3] = ba;
1314         }
1315
1316         // buf_texcoord_t must be the same size as the decal texcoord array (or vice versa)
1317         memcpy(&texcoord[0].t[0], m->texcoords[0], 4 * sizeof(buf_texcoord_t));
1318 }