]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
cleaned up a lot of particle rendering properties (mainly related to rain code),...
[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         static int i, j, *index, overbright;
766         static float c, *in, scaler, cr, cg, cb, ca;
767         static buf_mesh_t *mesh;
768         static buf_vertex_t *vert;
769         static buf_fcolor_t *fcolor;
770         static buf_bcolor_t *bcolor;
771         static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
772         static buf_transtri_t *tri;
773         static byte br, bg, bb, ba;
774
775         if (m->index == NULL
776          || !m->numtriangles
777          || m->vertex == NULL
778          || !m->numverts)
779                 return;
780         // ignore meaningless alpha meshs
781         if (!m->depthwrite && m->blendfunc1 == GL_SRC_ALPHA && (m->blendfunc2 == GL_ONE || m->blendfunc2 == GL_ONE_MINUS_SRC_ALPHA))
782         {
783                 if (m->color)
784                 {
785                         for (i = 0, in = m->color + 3;i < m->numverts;i++, (int)in += m->colorstep)
786                                 if (*in >= 0.01f)
787                                         break;
788                         if (i == m->numverts)
789                                 return;
790                 }
791                 else if (m->ca < 0.01f)
792                         return;
793         }
794
795         if (!backendactive)
796                 Sys_Error("R_DrawMesh: called when backend is not active\n");
797
798         if (m->transparent)
799         {
800                 if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
801                 {
802                         if (!transranout)
803                         {
804                                 Con_Printf("R_DrawMesh: ran out of room for transparent meshs\n");
805                                 transranout = true;
806                         }
807                         return;
808                 }
809
810                 vert = &buf_transvertex[currenttransvertex];
811                 fcolor = &buf_transfcolor[currenttransvertex];
812                 bcolor = &buf_transbcolor[currenttransvertex];
813                 for (i = 0;i < backendunits;i++)
814                         texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
815         }
816         else
817         {
818                 if (m->numtriangles > max_meshs || m->numverts > max_verts)
819                 {
820                         Con_Printf("R_DrawMesh: mesh too big for buffers\n");
821                         return;
822                 }
823
824                 if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
825                         R_Mesh_Render();
826
827                 vert = &buf_vertex[currentvertex];
828                 fcolor = &buf_fcolor[currentvertex];
829                 bcolor = &buf_bcolor[currentvertex];
830                 for (i = 0;i < backendunits;i++)
831                         texcoord[i] = &buf_texcoord[i][currentvertex];
832         }
833
834         // vertex array code is shared for transparent and opaque meshs
835
836         for (i = 0, in = m->vertex;i < m->numverts;i++, (int)in += m->vertexstep)
837         {
838                 vert[i].v[0] = in[0];
839                 vert[i].v[1] = in[1];
840                 vert[i].v[2] = in[2];
841                 // push out farclip based on vertices encountered
842                 c = DotProduct(vert[i].v, vpn);
843                 if (meshfarclip < c)
844                         meshfarclip = c;
845         }
846
847         scaler = 1;
848         if (m->blendfunc2 == GL_SRC_COLOR)
849         {
850                 if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
851                         scaler *= 0.5f;
852         }
853         else
854         {
855                 if (m->tex[0])
856                 {
857                         overbright = gl_combine.integer;
858                         if (overbright)
859                                 scaler *= 0.25f;
860                 }
861                 if (lighthalf)
862                         scaler *= 0.5f;
863         }
864
865         if (floatcolors)
866         {
867                 if (m->color)
868                 {
869                         for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
870                         {
871                                 fcolor[i].c[0] = in[0] * scaler;
872                                 fcolor[i].c[1] = in[1] * scaler;
873                                 fcolor[i].c[2] = in[2] * scaler;
874                                 fcolor[i].c[3] = in[3];
875                         }
876                 }
877                 else
878                 {
879                         cr = m->cr * scaler;
880                         cg = m->cg * scaler;
881                         cb = m->cb * scaler;
882                         ca = m->ca;
883                         for (i = 0;i < m->numverts;i++)
884                         {
885                                 fcolor[i].c[0] = cr;
886                                 fcolor[i].c[1] = cg;
887                                 fcolor[i].c[2] = cb;
888                                 fcolor[i].c[3] = ca;
889                         }
890                 }
891         }
892         else
893         {
894                 if (m->color)
895                 {
896                         for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
897                         {
898                                 // shift float to have 8bit fraction at base of number,
899                                 // then read as integer and kill float bits...
900                                 c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[0] = (byte) j;
901                                 c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[1] = (byte) j;
902                                 c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[2] = (byte) j;
903                                 c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bcolor[i].c[3] = (byte) j;
904                         }
905                 }
906                 else
907                 {
908                         c = in[0] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;br = (byte) j;
909                         c = in[1] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bg = (byte) j;
910                         c = in[2] * scaler + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;bb = (byte) j;
911                         c = in[3]          + 32768.0f;j = (*((long *)&c) & 0x7FFFFF);if (j > 255) j = 255;ba = (byte) j;
912                         for (i = 0;i < m->numverts;i++)
913                         {
914                                 bcolor[i].c[0] = br;
915                                 bcolor[i].c[1] = bg;
916                                 bcolor[i].c[2] = bb;
917                                 bcolor[i].c[3] = ba;
918                         }
919                 }
920         }
921
922         for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
923         {
924                 if (j >= backendunits)
925                         Sys_Error("R_DrawMesh: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
926                 for (i = 0, in = m->texcoords[j];i < m->numverts;i++, (int)in += m->texcoordstep[j])
927                 {
928                         texcoord[j][i].t[0] = in[0];
929                         texcoord[j][i].t[1] = in[1];
930                 }
931         }
932         for (;j < backendunits;j++)
933         {
934                 for (i = 0;i < m->numverts;i++)
935                 {
936                         texcoord[j][i].t[0] = 0;
937                         texcoord[j][i].t[1] = 0;
938                 }
939         }
940
941         if (m->transparent)
942         {
943                 // transmesh is only for storage of tranparent meshs until they
944                 // are inserted into the main mesh array
945                 mesh = &buf_transmesh[currenttransmesh++];
946                 mesh->blendfunc1 = m->blendfunc1;
947                 mesh->blendfunc2 = m->blendfunc2;
948                 mesh->depthmask = false;
949                 mesh->depthtest = !m->depthdisable;
950                 j = -1;
951                 for (i = 0;i < backendunits;i++)
952                 {
953                         if ((mesh->textures[i] = m->tex[i]))
954                                 j = i;
955                         mesh->texturergbscale[i] = m->texrgbscale[i];
956                         if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
957                                 mesh->texturergbscale[i] = 1;
958                 }
959                 if (overbright && j >= 0)
960                         mesh->texturergbscale[j] = 4;
961
962                 // transparent meshs are broken up into individual triangles which can
963                 // be sorted by depth
964                 index = m->index;
965                 for (i = 0;i < m->numtriangles;i++)
966                 {
967                         tri = &buf_transtri[currenttranstriangle++];
968                         tri->mesh = mesh;
969                         tri->index[0] = *index++ + currenttransvertex;
970                         tri->index[1] = *index++ + currenttransvertex;
971                         tri->index[2] = *index++ + currenttransvertex;
972                 }
973                 currenttransvertex += m->numverts;
974         }
975         else
976         {
977                 mesh = &buf_mesh[currentmesh++];
978                 mesh->blendfunc1 = m->blendfunc1;
979                 mesh->blendfunc2 = m->blendfunc2;
980                 mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
981                 mesh->depthtest = !m->depthdisable;
982                 mesh->firsttriangle = currenttriangle;
983                 mesh->triangles = m->numtriangles;
984                 j = -1;
985                 for (i = 0;i < backendunits;i++)
986                 {
987                         if ((mesh->textures[i] = m->tex[i]))
988                                 j = i;
989                         mesh->texturergbscale[i] = m->texrgbscale[i];
990                         if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
991                                 mesh->texturergbscale[i] = 1;
992                 }
993                 if (overbright && j >= 0)
994                         mesh->texturergbscale[j] = 4;
995
996                 // opaque meshs are rendered directly
997                 index = (int *)&buf_tri[currenttriangle];
998                 for (i = 0;i < m->numtriangles * 3;i++)
999                         index[i] = m->index[i] + currentvertex;
1000                 mesh->firstvert = currentvertex;
1001                 currenttriangle += m->numtriangles;
1002                 currentvertex += m->numverts;
1003                 mesh->lastvert = currentvertex - 1;
1004         }
1005
1006         c_meshtris += m->numtriangles;
1007 }
1008
1009 void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
1010 {
1011         m->index = polyindexarray;
1012         m->numverts = numverts;
1013         m->numtriangles = numverts - 2;
1014         if (m->numtriangles < 1)
1015         {
1016                 Con_Printf("R_Mesh_DrawPolygon: invalid vertex count\n");
1017                 return;
1018         }
1019         if (m->numtriangles >= 256)
1020         {
1021                 Con_Printf("R_Mesh_DrawPolygon: only up to 256 triangles (258 verts) supported\n");
1022                 return;
1023         }
1024         R_Mesh_Draw(m);
1025 }