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