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