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