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