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