]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rsurf.c
864d4d3b65c481a0d0d08d8312802d59436c5609
[xonotic/darkplaces.git] / gl_rsurf.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_surf.c: surface-related refresh code
21
22 #include "quakedef.h"
23
24 #define MAX_LIGHTMAP_SIZE 256
25
26 static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
27 static float floatblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
28
29 static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
30
31 cvar_t r_ambient = {0, "r_ambient", "0"};
32 cvar_t r_vertexsurfaces = {0, "r_vertexsurfaces", "0"};
33 cvar_t r_dlightmap = {CVAR_SAVE, "r_dlightmap", "1"};
34 cvar_t r_drawportals = {0, "r_drawportals", "0"};
35 cvar_t r_testvis = {0, "r_testvis", "0"};
36 cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
37 cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
38 cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"};
39
40 static int dlightdivtable[32768];
41
42 // variables used by R_PVSUpdate
43 int r_pvsframecount = 0;
44 mleaf_t *r_pvsviewleaf = NULL;
45 int r_pvsviewleafnovis = 0;
46
47 static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf)
48 {
49         int sdtable[256], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, smax3, red, green, blue, lit, dist2, impacts, impactt, subtract, k;
50         unsigned int *bl;
51         float dist, impact[3], local[3];
52
53         lit = false;
54
55         smax = (surf->extents[0] >> 4) + 1;
56         tmax = (surf->extents[1] >> 4) + 1;
57         smax3 = smax * 3;
58
59         for (lnum = 0; lnum < r_numdlights; lnum++)
60         {
61                 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
62                         continue;                                       // not lit by this light
63
64                 Matrix4x4_Transform(matrix, r_dlight[lnum].origin, local);
65                 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
66
67                 // for comparisons to minimum acceptable light
68                 // compensate for LIGHTOFFSET
69                 maxdist = (int) r_dlight[lnum].cullradius2 + LIGHTOFFSET;
70
71                 dist2 = dist * dist;
72                 dist2 += LIGHTOFFSET;
73                 if (dist2 >= maxdist)
74                         continue;
75
76                 if (surf->plane->type < 3)
77                 {
78                         VectorCopy(local, impact);
79                         impact[surf->plane->type] -= dist;
80                 }
81                 else
82                 {
83                         impact[0] = local[0] - surf->plane->normal[0] * dist;
84                         impact[1] = local[1] - surf->plane->normal[1] * dist;
85                         impact[2] = local[2] - surf->plane->normal[2] * dist;
86                 }
87
88                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
89                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
90
91                 s = bound(0, impacts, smax * 16) - impacts;
92                 t = bound(0, impactt, tmax * 16) - impactt;
93                 i = s * s + t * t + dist2;
94                 if (i > maxdist)
95                         continue;
96
97                 // reduce calculations
98                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
99                         sdtable[s] = i * i + dist2;
100
101                 maxdist3 = maxdist - dist2;
102
103                 // convert to 8.8 blocklights format
104                 red = r_dlight[lnum].light[0] * (1.0f / 128.0f);
105                 green = r_dlight[lnum].light[1] * (1.0f / 128.0f);
106                 blue = r_dlight[lnum].light[2] * (1.0f / 128.0f);
107                 subtract = (int) (r_dlight[lnum].subtract * 4194304.0f);
108                 bl = intblocklights;
109
110                 i = impactt;
111                 for (t = 0;t < tmax;t++, i -= 16)
112                 {
113                         td = i * i;
114                         // make sure some part of it is visible on this line
115                         if (td < maxdist3)
116                         {
117                                 maxdist2 = maxdist - td;
118                                 for (s = 0;s < smax;s++)
119                                 {
120                                         if (sdtable[s] < maxdist2)
121                                         {
122                                                 k = dlightdivtable[(sdtable[s] + td) >> 7] - subtract;
123                                                 if (k > 0)
124                                                 {
125                                                         bl[0] += (red   * k);
126                                                         bl[1] += (green * k);
127                                                         bl[2] += (blue  * k);
128                                                         lit = true;
129                                                 }
130                                         }
131                                         bl += 3;
132                                 }
133                         }
134                         else // skip line
135                                 bl += smax3;
136                 }
137         }
138         return lit;
139 }
140
141 static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf)
142 {
143         int lnum, s, t, smax, tmax, smax3, lit, impacts, impactt;
144         float sdtable[256], *bl, k, dist, dist2, maxdist, maxdist2, maxdist3, td1, td, red, green, blue, impact[3], local[3], subtract;
145
146         lit = false;
147
148         smax = (surf->extents[0] >> 4) + 1;
149         tmax = (surf->extents[1] >> 4) + 1;
150         smax3 = smax * 3;
151
152         for (lnum = 0; lnum < r_numdlights; lnum++)
153         {
154                 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
155                         continue;                                       // not lit by this light
156
157                 Matrix4x4_Transform(matrix, r_dlight[lnum].origin, local);
158                 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
159
160                 // for comparisons to minimum acceptable light
161                 // compensate for LIGHTOFFSET
162                 maxdist = (int) r_dlight[lnum].cullradius2 + LIGHTOFFSET;
163
164                 dist2 = dist * dist;
165                 dist2 += LIGHTOFFSET;
166                 if (dist2 >= maxdist)
167                         continue;
168
169                 if (surf->plane->type < 3)
170                 {
171                         VectorCopy(local, impact);
172                         impact[surf->plane->type] -= dist;
173                 }
174                 else
175                 {
176                         impact[0] = local[0] - surf->plane->normal[0] * dist;
177                         impact[1] = local[1] - surf->plane->normal[1] * dist;
178                         impact[2] = local[2] - surf->plane->normal[2] * dist;
179                 }
180
181                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
182                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
183
184                 td = bound(0, impacts, smax * 16) - impacts;
185                 td1 = bound(0, impactt, tmax * 16) - impactt;
186                 td = td * td + td1 * td1 + dist2;
187                 if (td > maxdist)
188                         continue;
189
190                 // reduce calculations
191                 for (s = 0, td1 = impacts; s < smax; s++, td1 -= 16.0f)
192                         sdtable[s] = td1 * td1 + dist2;
193
194                 maxdist3 = maxdist - dist2;
195
196                 // convert to 8.8 blocklights format
197                 red = r_dlight[lnum].light[0];
198                 green = r_dlight[lnum].light[1];
199                 blue = r_dlight[lnum].light[2];
200                 subtract = r_dlight[lnum].subtract * 32768.0f;
201                 bl = floatblocklights;
202
203                 td1 = impactt;
204                 for (t = 0;t < tmax;t++, td1 -= 16.0f)
205                 {
206                         td = td1 * td1;
207                         // make sure some part of it is visible on this line
208                         if (td < maxdist3)
209                         {
210                                 maxdist2 = maxdist - td;
211                                 for (s = 0;s < smax;s++)
212                                 {
213                                         if (sdtable[s] < maxdist2)
214                                         {
215                                                 k = (32768.0f / (sdtable[s] + td)) - subtract;
216                                                 bl[0] += red   * k;
217                                                 bl[1] += green * k;
218                                                 bl[2] += blue  * k;
219                                                 lit = true;
220                                         }
221                                         bl += 3;
222                                 }
223                         }
224                         else // skip line
225                                 bl += smax3;
226                 }
227         }
228         return lit;
229 }
230
231 /*
232 ===============
233 R_BuildLightMap
234
235 Combine and scale multiple lightmaps into the 8.8 format in blocklights
236 ===============
237 */
238 static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surf, int dlightchanged)
239 {
240         if (!r_floatbuildlightmap.integer)
241         {
242                 int smax, tmax, i, j, size, size3, shift, maps, stride, l;
243                 unsigned int *bl, scale;
244                 qbyte *lightmap, *out, *stain;
245
246                 // update cached lighting info
247                 surf->cached_dlight = 0;
248                 surf->cached_lightscalebit = lightscalebit;
249                 surf->cached_ambient = r_ambient.value;
250                 surf->cached_light[0] = d_lightstylevalue[surf->styles[0]];
251                 surf->cached_light[1] = d_lightstylevalue[surf->styles[1]];
252                 surf->cached_light[2] = d_lightstylevalue[surf->styles[2]];
253                 surf->cached_light[3] = d_lightstylevalue[surf->styles[3]];
254
255                 smax = (surf->extents[0]>>4)+1;
256                 tmax = (surf->extents[1]>>4)+1;
257                 size = smax*tmax;
258                 size3 = size*3;
259                 lightmap = surf->samples;
260
261         // set to full bright if no light data
262                 bl = intblocklights;
263                 if ((ent->effects & EF_FULLBRIGHT) || !ent->model->lightdata)
264                 {
265                         for (i = 0;i < size3;i++)
266                                 bl[i] = 255*256;
267                 }
268                 else
269                 {
270         // clear to no light
271                         j = r_ambient.value * 512.0f; // would be 128.0f logically, but using 512.0f to match winquake style
272                         if (j)
273                         {
274                                 for (i = 0;i < size3;i++)
275                                         *bl++ = j;
276                         }
277                         else
278                                 memset(bl, 0, size*3*sizeof(unsigned int));
279
280                         if (surf->dlightframe == r_framecount && r_dlightmap.integer)
281                         {
282                                 surf->cached_dlight = R_IntAddDynamicLights(&ent->inversematrix, surf);
283                                 if (surf->cached_dlight)
284                                         c_light_polys++;
285                                 else if (dlightchanged)
286                                         return; // don't upload if only updating dlights and none mattered
287                         }
288
289         // add all the lightmaps
290                         if (lightmap)
291                         {
292                                 bl = intblocklights;
293                                 for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++, lightmap += size3)
294                                         for (scale = d_lightstylevalue[surf->styles[maps]], i = 0;i < size3;i++)
295                                                 bl[i] += lightmap[i] * scale;
296                         }
297                 }
298
299                 stain = surf->stainsamples;
300                 bl = intblocklights;
301                 out = templight;
302                 // deal with lightmap brightness scale
303                 shift = 7 + lightscalebit + 8;
304                 if (ent->model->lightmaprgba)
305                 {
306                         stride = (surf->lightmaptexturestride - smax) * 4;
307                         for (i = 0;i < tmax;i++, out += stride)
308                         {
309                                 for (j = 0;j < smax;j++)
310                                 {
311                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
312                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
313                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
314                                         *out++ = 255;
315                                 }
316                         }
317                 }
318                 else
319                 {
320                         stride = (surf->lightmaptexturestride - smax) * 3;
321                         for (i = 0;i < tmax;i++, out += stride)
322                         {
323                                 for (j = 0;j < smax;j++)
324                                 {
325                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
326                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
327                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
328                                 }
329                         }
330                 }
331
332                 R_UpdateTexture(surf->lightmaptexture, templight);
333         }
334         else
335         {
336                 int smax, tmax, i, j, size, size3, maps, stride, l;
337                 float *bl, scale;
338                 qbyte *lightmap, *out, *stain;
339
340                 // update cached lighting info
341                 surf->cached_dlight = 0;
342                 surf->cached_lightscalebit = lightscalebit;
343                 surf->cached_ambient = r_ambient.value;
344                 surf->cached_light[0] = d_lightstylevalue[surf->styles[0]];
345                 surf->cached_light[1] = d_lightstylevalue[surf->styles[1]];
346                 surf->cached_light[2] = d_lightstylevalue[surf->styles[2]];
347                 surf->cached_light[3] = d_lightstylevalue[surf->styles[3]];
348
349                 smax = (surf->extents[0]>>4)+1;
350                 tmax = (surf->extents[1]>>4)+1;
351                 size = smax*tmax;
352                 size3 = size*3;
353                 lightmap = surf->samples;
354
355         // set to full bright if no light data
356                 bl = floatblocklights;
357                 if ((ent->effects & EF_FULLBRIGHT) || !ent->model->lightdata)
358                         j = 255*256;
359                 else
360                         j = r_ambient.value * 512.0f; // would be 128.0f logically, but using 512.0f to match winquake style
361
362                 // clear to no light
363                 if (j)
364                 {
365                         for (i = 0;i < size3;i++)
366                                 *bl++ = j;
367                 }
368                 else
369                         memset(bl, 0, size*3*sizeof(float));
370
371                 if (surf->dlightframe == r_framecount && r_dlightmap.integer)
372                 {
373                         surf->cached_dlight = R_FloatAddDynamicLights(&ent->inversematrix, surf);
374                         if (surf->cached_dlight)
375                                 c_light_polys++;
376                         else if (dlightchanged)
377                                 return; // don't upload if only updating dlights and none mattered
378                 }
379
380                 // add all the lightmaps
381                 if (lightmap)
382                 {
383                         bl = floatblocklights;
384                         for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++, lightmap += size3)
385                                 for (scale = d_lightstylevalue[surf->styles[maps]], i = 0;i < size3;i++)
386                                         bl[i] += lightmap[i] * scale;
387                 }
388
389                 stain = surf->stainsamples;
390                 bl = floatblocklights;
391                 out = templight;
392                 // deal with lightmap brightness scale
393                 scale = 1.0f / (1 << (7 + lightscalebit + 8));
394                 if (ent->model->lightmaprgba)
395                 {
396                         stride = (surf->lightmaptexturestride - smax) * 4;
397                         for (i = 0;i < tmax;i++, out += stride)
398                         {
399                                 for (j = 0;j < smax;j++)
400                                 {
401                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
402                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
403                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
404                                         *out++ = 255;
405                                 }
406                         }
407                 }
408                 else
409                 {
410                         stride = (surf->lightmaptexturestride - smax) * 3;
411                         for (i = 0;i < tmax;i++, out += stride)
412                         {
413                                 for (j = 0;j < smax;j++)
414                                 {
415                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
416                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
417                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
418                                 }
419                         }
420                 }
421
422                 R_UpdateTexture(surf->lightmaptexture, templight);
423         }
424 }
425
426 void R_StainNode (mnode_t *node, model_t *model, vec3_t origin, float radius, float fcolor[8])
427 {
428         float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2;
429         msurface_t *surf, *endsurf;
430         int i, s, t, smax, tmax, smax3, impacts, impactt, stained;
431         qbyte *bl;
432         vec3_t impact;
433
434         maxdist = radius * radius;
435         invradius = 1.0f / radius;
436
437 loc0:
438         if (node->contents < 0)
439                 return;
440         ndist = PlaneDiff(origin, node->plane);
441         if (ndist > radius)
442         {
443                 node = node->children[0];
444                 goto loc0;
445         }
446         if (ndist < -radius)
447         {
448                 node = node->children[1];
449                 goto loc0;
450         }
451
452         dist2 = ndist * ndist;
453         maxdist3 = maxdist - dist2;
454
455         if (node->plane->type < 3)
456         {
457                 VectorCopy(origin, impact);
458                 impact[node->plane->type] -= ndist;
459         }
460         else
461         {
462                 impact[0] = origin[0] - node->plane->normal[0] * ndist;
463                 impact[1] = origin[1] - node->plane->normal[1] * ndist;
464                 impact[2] = origin[2] - node->plane->normal[2] * ndist;
465         }
466
467         for (surf = model->surfaces + node->firstsurface, endsurf = surf + node->numsurfaces;surf < endsurf;surf++)
468         {
469                 if (surf->stainsamples)
470                 {
471                         smax = (surf->extents[0] >> 4) + 1;
472                         tmax = (surf->extents[1] >> 4) + 1;
473
474                         impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
475                         impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
476
477                         s = bound(0, impacts, smax * 16) - impacts;
478                         t = bound(0, impactt, tmax * 16) - impactt;
479                         i = s * s + t * t + dist2;
480                         if (i > maxdist)
481                                 continue;
482
483                         // reduce calculations
484                         for (s = 0, i = impacts; s < smax; s++, i -= 16)
485                                 sdtable[s] = i * i + dist2;
486
487                         bl = surf->stainsamples;
488                         smax3 = smax * 3;
489                         stained = false;
490
491                         i = impactt;
492                         for (t = 0;t < tmax;t++, i -= 16)
493                         {
494                                 td = i * i;
495                                 // make sure some part of it is visible on this line
496                                 if (td < maxdist3)
497                                 {
498                                         maxdist2 = maxdist - td;
499                                         for (s = 0;s < smax;s++)
500                                         {
501                                                 if (sdtable[s] < maxdist2)
502                                                 {
503                                                         ratio = lhrandom(0.0f, 1.0f);
504                                                         a = (fcolor[3] + ratio * fcolor[7]) * (1.0f - sqrt(sdtable[s] + td) * invradius);
505                                                         if (a >= (1.0f / 64.0f))
506                                                         {
507                                                                 if (a > 1)
508                                                                         a = 1;
509                                                                 bl[0] = (qbyte) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
510                                                                 bl[1] = (qbyte) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
511                                                                 bl[2] = (qbyte) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
512                                                                 stained = true;
513                                                         }
514                                                 }
515                                                 bl += 3;
516                                         }
517                                 }
518                                 else // skip line
519                                         bl += smax3;
520                         }
521                         // force lightmap upload
522                         if (stained)
523                                 surf->cached_dlight = true;
524                 }
525         }
526
527         if (node->children[0]->contents >= 0)
528         {
529                 if (node->children[1]->contents >= 0)
530                 {
531                         R_StainNode(node->children[0], model, origin, radius, fcolor);
532                         node = node->children[1];
533                         goto loc0;
534                 }
535                 else
536                 {
537                         node = node->children[0];
538                         goto loc0;
539                 }
540         }
541         else if (node->children[1]->contents >= 0)
542         {
543                 node = node->children[1];
544                 goto loc0;
545         }
546 }
547
548 void R_Stain (vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2)
549 {
550         int n;
551         float fcolor[8];
552         entity_render_t *ent;
553         model_t *model;
554         vec3_t org;
555         fcolor[0] = cr1;
556         fcolor[1] = cg1;
557         fcolor[2] = cb1;
558         fcolor[3] = ca1 * (1.0f / 64.0f);
559         fcolor[4] = cr2 - cr1;
560         fcolor[5] = cg2 - cg1;
561         fcolor[6] = cb2 - cb1;
562         fcolor[7] = (ca2 - ca1) * (1.0f / 64.0f);
563
564         model = cl.worldmodel;
565         if (model)
566                 R_StainNode(model->nodes + model->hulls[0].firstclipnode, model, origin, radius, fcolor);
567
568         // look for embedded bmodels
569         for (n = 0;n < cl_num_brushmodel_entities;n++)
570         {
571                 ent = cl_brushmodel_entities[n];
572                 model = ent->model;
573                 if (model && model->name[0] == '*')
574                 {
575                         Mod_CheckLoaded(model);
576                         if (model->type == mod_brush)
577                         {
578                                 Matrix4x4_Transform(&ent->inversematrix, origin, org);
579                                 R_StainNode(model->nodes + model->hulls[0].firstclipnode, model, org, radius, fcolor);
580                         }
581                 }
582         }
583 }
584
585
586 /*
587 =============================================================
588
589         BRUSH MODELS
590
591 =============================================================
592 */
593
594 static void RSurf_AddLightmapToVertexColors(const int *lightmapoffsets, float *c, int numverts, const qbyte *samples, int size3, const qbyte *styles)
595 {
596         int i;
597         float scale;
598         const qbyte *lm;
599         if (styles[0] != 255)
600         {
601                 for (i = 0;i < numverts;i++, c += 4)
602                 {
603                         lm = samples + lightmapoffsets[i];
604                         scale = d_lightstylevalue[styles[0]] * (1.0f / 32768.0f);
605                         VectorMA(c, scale, lm, c);
606                         if (styles[1] != 255)
607                         {
608                                 lm += size3;
609                                 scale = d_lightstylevalue[styles[1]] * (1.0f / 32768.0f);
610                                 VectorMA(c, scale, lm, c);
611                                 if (styles[2] != 255)
612                                 {
613                                         lm += size3;
614                                         scale = d_lightstylevalue[styles[2]] * (1.0f / 32768.0f);
615                                         VectorMA(c, scale, lm, c);
616                                         if (styles[3] != 255)
617                                         {
618                                                 lm += size3;
619                                                 scale = d_lightstylevalue[styles[3]] * (1.0f / 32768.0f);
620                                                 VectorMA(c, scale, lm, c);
621                                         }
622                                 }
623                         }
624                 }
625         }
626 }
627
628 static void RSurf_FogColors(const float *v, float *c, float colorscale, int numverts, const float *modelorg)
629 {
630         int i;
631         float diff[3], f;
632         if (fogenabled)
633         {
634                 for (i = 0;i < numverts;i++, v += 4, c += 4)
635                 {
636                         VectorSubtract(v, modelorg, diff);
637                         f = colorscale * (1 - exp(fogdensity/DotProduct(diff, diff)));
638                         VectorScale(c, f, c);
639                 }
640         }
641         else if (colorscale != 1)
642                 for (i = 0;i < numverts;i++, c += 4)
643                         VectorScale(c, colorscale, c);
644 }
645
646 static void RSurf_FoggedColors(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
647 {
648         int i;
649         float diff[3], f;
650         r *= colorscale;
651         g *= colorscale;
652         b *= colorscale;
653         if (fogenabled)
654         {
655                 for (i = 0;i < numverts;i++, v += 4, c += 4)
656                 {
657                         VectorSubtract(v, modelorg, diff);
658                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
659                         c[0] = r * f;
660                         c[1] = g * f;
661                         c[2] = b * f;
662                         c[3] = a;
663                 }
664         }
665         else
666         {
667                 for (i = 0;i < numverts;i++, c += 4)
668                 {
669                         c[0] = r;
670                         c[1] = g;
671                         c[2] = b;
672                         c[3] = a;
673                 }
674         }
675 }
676
677 static void RSurf_FogPassColors(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
678 {
679         int i;
680         float diff[3], f;
681         r *= colorscale;
682         g *= colorscale;
683         b *= colorscale;
684         for (i = 0;i < numverts;i++, v += 4, c += 4)
685         {
686                 VectorSubtract(v, modelorg, diff);
687                 f = exp(fogdensity/DotProduct(diff, diff));
688                 c[0] = r;
689                 c[1] = g;
690                 c[2] = b;
691                 c[3] = a * f;
692         }
693 }
694
695 static void RSurf_ScaleColors(float *c, float scale, int numverts)
696 {
697         int i;
698         if (scale != 1)
699                 for (i = 0;i < numverts;i++, c += 4)
700                         VectorScale(c, scale, c);
701 }
702
703 static int RSurf_LightSeparate(const matrix4x4_t *matrix, const int *dlightbits, int numverts, const float *vert, float *color)
704 {
705         float f;
706         const float *v;
707         float *c;
708         int i, l, lit = false;
709         const rdlight_t *rd;
710         vec3_t lightorigin;
711         for (l = 0;l < r_numdlights;l++)
712         {
713                 if (dlightbits[l >> 5] & (1 << (l & 31)))
714                 {
715                         rd = &r_dlight[l];
716                         Matrix4x4_Transform(matrix, rd->origin, lightorigin);
717                         for (i = 0, v = vert, c = color;i < numverts;i++, v += 4, c += 4)
718                         {
719                                 f = VectorDistance2(v, lightorigin) + LIGHTOFFSET;
720                                 if (f < rd->cullradius2)
721                                 {
722                                         f = (1.0f / f) - rd->subtract;
723                                         VectorMA(c, f, rd->light, c);
724                                         lit = true;
725                                 }
726                         }
727                 }
728         }
729         return lit;
730 }
731
732 // note: this untransforms lights to do the checking,
733 // and takes surf->mesh->verts data
734 static int RSurf_LightCheck(const matrix4x4_t *matrix, const int *dlightbits, const surfmesh_t *mesh)
735 {
736         int i, l;
737         const rdlight_t *rd;
738         vec3_t lightorigin;
739         const float *v;
740         for (l = 0;l < r_numdlights;l++)
741         {
742                 if (dlightbits[l >> 5] & (1 << (l & 31)))
743                 {
744                         rd = &r_dlight[l];
745                         Matrix4x4_Transform(matrix, rd->origin, lightorigin);
746                         for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4)
747                                 if (VectorDistance2(v, lightorigin) < rd->cullradius2)
748                                         return true;
749                 }
750         }
751         return false;
752 }
753
754 static void RSurfShader_Sky(const entity_render_t *ent, const texture_t *texture)
755 {
756         const msurface_t *surf;
757         const surfmesh_t *mesh;
758         rmeshstate_t m;
759
760         // LordHavoc: HalfLife maps have freaky skypolys...
761         if (ent->model->ishlbsp)
762                 return;
763
764         if (skyrendernow)
765         {
766                 skyrendernow = false;
767                 if (skyrendermasked)
768                         R_Sky();
769         }
770
771         R_Mesh_Matrix(&ent->matrix);
772
773         // draw depth-only polys
774         memset(&m, 0, sizeof(m));
775         if (skyrendermasked)
776         {
777                 m.blendfunc1 = GL_ZERO;
778                 m.blendfunc2 = GL_ONE;
779         }
780         else
781         {
782                 // fog sky
783                 m.blendfunc1 = GL_ONE;
784                 m.blendfunc2 = GL_ZERO;
785         }
786         m.wantoverbright = false;
787         m.depthwrite = true;
788         R_Mesh_State(&m);
789         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
790         {
791                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
792                 {
793                         R_Mesh_ResizeCheck(mesh->numverts);
794                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
795                         if (skyrendermasked)
796                                 memset(varray_color, 0, mesh->numverts * sizeof(float[4]));
797                         else
798                                 R_FillColors(varray_color, mesh->numverts, fogcolor[0] * mesh_colorscale, fogcolor[1] * mesh_colorscale, fogcolor[2] * mesh_colorscale, 1);
799                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
800                 }
801         }
802 }
803
804 static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
805 {
806         const entity_render_t *ent = calldata1;
807         const msurface_t *surf = ent->model->surfaces + calldata2;
808         float f;
809         const surfmesh_t *mesh;
810         rmeshstate_t m;
811         float alpha = ent->alpha * (surf->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value);
812         float modelorg[3];
813         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
814
815         R_Mesh_Matrix(&ent->matrix);
816
817         memset(&m, 0, sizeof(m));
818         if (ent->effects & EF_ADDITIVE)
819         {
820                 m.blendfunc1 = GL_SRC_ALPHA;
821                 m.blendfunc2 = GL_ONE;
822         }
823         else if (surf->currenttexture->fogtexture != NULL || alpha < 1)
824         {
825                 m.blendfunc1 = GL_SRC_ALPHA;
826                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
827         }
828         else
829         {
830                 m.blendfunc1 = GL_ONE;
831                 m.blendfunc2 = GL_ZERO;
832         }
833         m.wantoverbright = true;
834         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
835         R_Mesh_State(&m);
836         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
837         {
838                 R_Mesh_ResizeCheck(mesh->numverts);
839                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
840                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
841                 f = surf->flags & SURF_DRAWFULLBRIGHT ? 1.0f : ((surf->flags & SURF_LIGHTMAP) ? 0 : 0.5f);
842                 R_FillColors(varray_color, mesh->numverts, f, f, f, alpha);
843                 if (!(surf->flags & SURF_DRAWFULLBRIGHT || ent->effects & EF_FULLBRIGHT))
844                 {
845                         if (surf->dlightframe == r_framecount)
846                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, mesh->numverts, varray_vertex, varray_color);
847                         if (surf->flags & SURF_LIGHTMAP)
848                                 RSurf_AddLightmapToVertexColors(mesh->lightmapoffsets, varray_color, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
849                 }
850                 RSurf_FogColors(varray_vertex, varray_color, mesh_colorscale, mesh->numverts, modelorg);
851                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
852         }
853
854         if (fogenabled)
855         {
856                 memset(&m, 0, sizeof(m));
857                 m.blendfunc1 = GL_SRC_ALPHA;
858                 m.blendfunc2 = GL_ONE;
859                 m.wantoverbright = false;
860                 m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
861                 R_Mesh_State(&m);
862                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
863                 {
864                         R_Mesh_ResizeCheck(mesh->numverts);
865                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
866                         if (m.tex[0])
867                                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
868                         RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], alpha, mesh_colorscale, mesh->numverts, modelorg);
869                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
870                 }
871         }
872 }
873
874 static void RSurfShader_Water(const entity_render_t *ent, const texture_t *texture)
875 {
876         const msurface_t *surf;
877         vec3_t center;
878         if ((r_wateralpha.value < 1 && !(texture->flags & SURF_DRAWNOALPHA)) || ent->effects & EF_ADDITIVE || texture->fogtexture)
879         {
880                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
881                 {
882                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
883                         R_MeshQueue_AddTransparent(center, RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
884                 }
885         }
886         else
887                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
888                         RSurfShader_Water_Callback(ent, surf - ent->model->surfaces);
889 }
890
891 static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf)
892 {
893         float base;
894         const surfmesh_t *mesh;
895         rmeshstate_t m;
896         float modelorg[3];
897         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
898         memset(&m, 0, sizeof(m));
899         if (ent->effects & EF_ADDITIVE)
900         {
901                 m.blendfunc1 = GL_SRC_ALPHA;
902                 m.blendfunc2 = GL_ONE;
903         }
904         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
905         {
906                 m.blendfunc1 = GL_SRC_ALPHA;
907                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
908         }
909         else
910         {
911                 m.blendfunc1 = GL_ONE;
912                 m.blendfunc2 = GL_ZERO;
913         }
914         m.wantoverbright = true;
915         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
916         base = ent->effects & EF_FULLBRIGHT ? 2.0f : r_ambient.value * (1.0f / 64.0f);
917         R_Mesh_State(&m);
918         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
919         {
920                 R_Mesh_ResizeCheck(mesh->numverts);
921                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
922                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
923                 R_FillColors(varray_color, mesh->numverts, base, base, base, ent->alpha);
924                 if (!(ent->effects & EF_FULLBRIGHT))
925                 {
926                         if (surf->dlightframe == r_framecount)
927                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, mesh->numverts, varray_vertex, varray_color);
928                         if (surf->flags & SURF_LIGHTMAP)
929                                 RSurf_AddLightmapToVertexColors(mesh->lightmapoffsets, varray_color, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
930                 }
931                 RSurf_FogColors(varray_vertex, varray_color, mesh_colorscale, mesh->numverts, modelorg);
932                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
933         }
934 }
935
936 static void RSurfShader_Wall_Pass_BaseFullbright(const entity_render_t *ent, const msurface_t *surf)
937 {
938         const surfmesh_t *mesh;
939         rmeshstate_t m;
940         float modelorg[3];
941         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
942         memset(&m, 0, sizeof(m));
943         if (ent->effects & EF_ADDITIVE)
944         {
945                 m.blendfunc1 = GL_SRC_ALPHA;
946                 m.blendfunc2 = GL_ONE;
947         }
948         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
949         {
950                 m.blendfunc1 = GL_SRC_ALPHA;
951                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
952         }
953         else
954         {
955                 m.blendfunc1 = GL_ONE;
956                 m.blendfunc2 = GL_ZERO;
957         }
958         m.wantoverbright = false;
959         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
960         R_Mesh_State(&m);
961         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
962         {
963                 R_Mesh_ResizeCheck(mesh->numverts);
964                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
965                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
966                 RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, ent->alpha, mesh_colorscale, mesh->numverts, modelorg);
967                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
968         }
969 }
970
971 static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
972 {
973         const surfmesh_t *mesh;
974         rmeshstate_t m;
975         float modelorg[3];
976         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
977         memset(&m, 0, sizeof(m));
978         m.blendfunc1 = GL_SRC_ALPHA;
979         m.blendfunc2 = GL_ONE;
980         m.wantoverbright = false;
981         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
982         R_Mesh_State(&m);
983         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
984         {
985                 R_Mesh_ResizeCheck(mesh->numverts);
986                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
987                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
988                 RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, ent->alpha, mesh_colorscale, mesh->numverts, modelorg);
989                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
990         }
991 }
992
993 static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
994 {
995         const surfmesh_t *mesh;
996         rmeshstate_t m;
997         float modelorg[3];
998         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
999         memset(&m, 0, sizeof(m));
1000         m.blendfunc1 = GL_SRC_ALPHA;
1001         m.blendfunc2 = GL_ONE;
1002         m.wantoverbright = false;
1003         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1004         R_Mesh_State(&m);
1005         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1006         {
1007                 R_Mesh_ResizeCheck(mesh->numverts);
1008                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1009                 if (m.tex[0])
1010                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1011                 RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, mesh_colorscale, mesh->numverts, modelorg);
1012                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1013         }
1014 }
1015
1016 static void RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(const entity_render_t *ent, const texture_t *texture)
1017 {
1018         const msurface_t *surf;
1019         const surfmesh_t *mesh;
1020         rmeshstate_t m;
1021         int lightmaptexturenum;
1022         float cl;
1023         memset(&m, 0, sizeof(m));
1024         m.blendfunc1 = GL_ONE;
1025         m.blendfunc2 = GL_ZERO;
1026         //m.wantoverbright = false;
1027         m.tex[0] = R_GetTexture(texture->texture);
1028         m.tex[1] = R_GetTexture(texture->surfacechain->lightmaptexture);
1029         m.tex[2] = R_GetTexture(texture->detailtexture);
1030         m.texrgbscale[0] = 1;
1031         m.texrgbscale[1] = 4;
1032         m.texrgbscale[2] = 2;
1033         R_Mesh_State(&m);
1034         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1035         {
1036                 lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
1037                 if (m.tex[1] != lightmaptexturenum)
1038                 {
1039                         m.tex[1] = lightmaptexturenum;
1040                         R_Mesh_State(&m);
1041                 }
1042                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1043                 {
1044                         R_Mesh_ResizeCheck(mesh->numverts);
1045                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1046                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1047                         memcpy(varray_texcoord[1], mesh->uv, mesh->numverts * sizeof(float[2]));
1048                         memcpy(varray_texcoord[2], mesh->ab, mesh->numverts * sizeof(float[2]));
1049                         cl = (float) (1 << lightscalebit) * mesh_colorscale;
1050                         R_FillColors(varray_color, mesh->numverts, cl, cl, cl, 1);
1051                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1052                 }
1053         }
1054 }
1055
1056 static void RSurfShader_OpaqueWall_Pass_BaseDoubleTex(const entity_render_t *ent, const texture_t *texture)
1057 {
1058         const msurface_t *surf;
1059         const surfmesh_t *mesh;
1060         rmeshstate_t m;
1061         int lightmaptexturenum;
1062         float cl;
1063         memset(&m, 0, sizeof(m));
1064         m.blendfunc1 = GL_ONE;
1065         m.blendfunc2 = GL_ZERO;
1066         m.wantoverbright = true;
1067         m.tex[0] = R_GetTexture(texture->texture);
1068         m.tex[1] = R_GetTexture(texture->surfacechain->lightmaptexture);
1069         R_Mesh_State(&m);
1070         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1071         {
1072                 lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
1073                 if (m.tex[1] != lightmaptexturenum)
1074                 {
1075                         m.tex[1] = lightmaptexturenum;
1076                         R_Mesh_State(&m);
1077                 }
1078                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1079                 {
1080                         R_Mesh_ResizeCheck(mesh->numverts);
1081                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1082                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1083                         memcpy(varray_texcoord[1], mesh->uv, mesh->numverts * sizeof(float[2]));
1084                         cl = (float) (1 << lightscalebit) * mesh_colorscale;
1085                         R_FillColors(varray_color, mesh->numverts, cl, cl, cl, 1);
1086                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1087                 }
1088         }
1089 }
1090
1091 static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent, const texture_t *texture)
1092 {
1093         const msurface_t *surf;
1094         const surfmesh_t *mesh;
1095         rmeshstate_t m;
1096         memset(&m, 0, sizeof(m));
1097         m.blendfunc1 = GL_ONE;
1098         m.blendfunc2 = GL_ZERO;
1099         //m.wantoverbright = false;
1100         m.tex[0] = R_GetTexture(texture->texture);
1101         R_Mesh_State(&m);
1102         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1103         {
1104                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1105                 {
1106                         R_Mesh_ResizeCheck(mesh->numverts);
1107                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1108                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1109                         R_FillColors(varray_color, mesh->numverts, 1, 1, 1, 1);
1110                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1111                 }
1112         }
1113 }
1114
1115 static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent, const texture_t *texture)
1116 {
1117         const msurface_t *surf;
1118         const surfmesh_t *mesh;
1119         rmeshstate_t m;
1120         int lightmaptexturenum;
1121         float cl;
1122         memset(&m, 0, sizeof(m));
1123         m.blendfunc1 = GL_ZERO;
1124         m.blendfunc2 = GL_SRC_COLOR;
1125         m.wantoverbright = true;
1126         m.tex[0] = R_GetTexture(texture->surfacechain->lightmaptexture);
1127         R_Mesh_State(&m);
1128         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1129         {
1130                 lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
1131                 if (m.tex[0] != lightmaptexturenum)
1132                 {
1133                         m.tex[0] = lightmaptexturenum;
1134                         R_Mesh_State(&m);
1135                 }
1136                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1137                 {
1138                         R_Mesh_ResizeCheck(mesh->numverts);
1139                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1140                         memcpy(varray_texcoord[0], mesh->uv, mesh->numverts * sizeof(float[2]));
1141                         cl = (float) (1 << lightscalebit) * mesh_colorscale;
1142                         R_FillColors(varray_color, mesh->numverts, cl, cl, cl, 1);
1143                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1144                 }
1145         }
1146 }
1147
1148 static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const texture_t *texture)
1149 {
1150         const msurface_t *surf;
1151         const surfmesh_t *mesh;
1152         rmeshstate_t m;
1153
1154         memset(&m, 0, sizeof(m));
1155         m.blendfunc1 = GL_SRC_ALPHA;
1156         m.blendfunc2 = GL_ONE;
1157         m.wantoverbright = true;
1158         m.tex[0] = R_GetTexture(texture->texture);
1159         R_Mesh_State(&m);
1160         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1161         {
1162                 if (surf->dlightframe == r_framecount)
1163                 {
1164                         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1165                         {
1166                                 if (RSurf_LightCheck(&ent->inversematrix, surf->dlightbits, mesh))
1167                                 {
1168                                         R_Mesh_ResizeCheck(mesh->numverts);
1169                                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1170                                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1171                                         R_FillColors(varray_color, mesh->numverts, 0, 0, 0, 1);
1172                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, mesh->numverts, varray_vertex, varray_color);
1173                                         RSurf_ScaleColors(varray_color, mesh_colorscale, mesh->numverts);
1174                                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1175                                 }
1176                         }
1177                 }
1178         }
1179 }
1180
1181 static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const texture_t *texture)
1182 {
1183         const msurface_t *surf;
1184         const surfmesh_t *mesh;
1185         rmeshstate_t m;
1186         float modelorg[3];
1187         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1188         memset(&m, 0, sizeof(m));
1189         m.blendfunc1 = GL_SRC_ALPHA;
1190         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1191         //m.wantoverbright = false;
1192         //m.tex[0] = 0;
1193         R_Mesh_State(&m);
1194         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1195         {
1196                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1197                 {
1198                         R_Mesh_ResizeCheck(mesh->numverts);
1199                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1200                         if (m.tex[0])
1201                                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1202                         RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], 1, mesh_colorscale, mesh->numverts, modelorg);
1203                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1204                 }
1205         }
1206 }
1207
1208 static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, const texture_t *texture)
1209 {
1210         const msurface_t *surf;
1211         const surfmesh_t *mesh;
1212         rmeshstate_t m;
1213         memset(&m, 0, sizeof(m));
1214         m.blendfunc1 = GL_DST_COLOR;
1215         m.blendfunc2 = GL_SRC_COLOR;
1216         //m.wantoverbright = false;
1217         m.tex[0] = R_GetTexture(texture->detailtexture);
1218         R_Mesh_State(&m);
1219         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1220         {
1221                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1222                 {
1223                         R_Mesh_ResizeCheck(mesh->numverts);
1224                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1225                         memcpy(varray_texcoord[0], mesh->ab, mesh->numverts * sizeof(float[2]));
1226                         R_FillColors(varray_color, mesh->numverts, 1, 1, 1, 1);
1227                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1228                 }
1229         }
1230 }
1231
1232 static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const texture_t *texture)
1233 {
1234         const msurface_t *surf;
1235         const surfmesh_t *mesh;
1236         rmeshstate_t m;
1237         memset(&m, 0, sizeof(m));
1238         m.blendfunc1 = GL_SRC_ALPHA;
1239         m.blendfunc2 = GL_ONE;
1240         //m.wantoverbright = false;
1241         m.tex[0] = R_GetTexture(texture->glowtexture);
1242         R_Mesh_State(&m);
1243         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1244         {
1245                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1246                 {
1247                         R_Mesh_ResizeCheck(mesh->numverts);
1248                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1249                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1250                         R_FillColors(varray_color, mesh->numverts, mesh_colorscale, mesh_colorscale, mesh_colorscale, 1);
1251                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1252                 }
1253         }
1254 }
1255
1256 static void RSurfShader_Wall_Fullbright_Callback(const void *calldata1, int calldata2)
1257 {
1258         const entity_render_t *ent = calldata1;
1259         const msurface_t *surf = ent->model->surfaces + calldata2;
1260         R_Mesh_Matrix(&ent->matrix);
1261         RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1262         if (surf->currenttexture->glowtexture)
1263                 RSurfShader_Wall_Pass_Glow(ent, surf);
1264         if (fogenabled)
1265                 RSurfShader_Wall_Pass_Fog(ent, surf);
1266 }
1267
1268 static void RSurfShader_Wall_Fullbright(const entity_render_t *ent, const texture_t *texture)
1269 {
1270         const msurface_t *surf;
1271         vec3_t center;
1272         if (ent->effects & EF_ADDITIVE || ent->alpha < 1 || texture->fogtexture != NULL)
1273         {
1274                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1275                 {
1276                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1277                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1278                 }
1279         }
1280         else
1281         {
1282                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1283                         RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1284                 if (texture->glowtexture)
1285                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1286                                 RSurfShader_Wall_Pass_Glow(ent, surf);
1287                 if (fogenabled)
1288                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1289                                 RSurfShader_Wall_Pass_Fog(ent, surf);
1290         }
1291 }
1292
1293 static void RSurfShader_Wall_Vertex_Callback(const void *calldata1, int calldata2)
1294 {
1295         const entity_render_t *ent = calldata1;
1296         const msurface_t *surf = ent->model->surfaces + calldata2;
1297         R_Mesh_Matrix(&ent->matrix);
1298         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1299         if (surf->currenttexture->glowtexture)
1300                 RSurfShader_Wall_Pass_Glow(ent, surf);
1301         if (fogenabled)
1302                 RSurfShader_Wall_Pass_Fog(ent, surf);
1303 }
1304
1305 static void RSurfShader_Wall_Lightmap(const entity_render_t *ent, const texture_t *texture)
1306 {
1307         const msurface_t *surf;
1308         vec3_t center;
1309         if (ent->effects & EF_ADDITIVE || ent->alpha < 1 || texture->fogtexture != NULL)
1310         {
1311                 // transparent vertex shaded from lightmap
1312                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1313                 {
1314                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1315                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1316                 }
1317         }
1318         else if (r_vertexsurfaces.integer)
1319         {
1320                 // opaque vertex shaded from lightmap
1321                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1322                         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1323                 if (texture->glowtexture)
1324                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1325                                 RSurfShader_Wall_Pass_Glow(ent, surf);
1326                 if (fogenabled)
1327                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1328                                 RSurfShader_Wall_Pass_Fog(ent, surf);
1329         }
1330         else
1331         {
1332                 // opaque lightmapped
1333                 if (r_textureunits.integer >= 2)
1334                 {
1335                         if (r_textureunits.integer >= 3 && gl_combine.integer && r_detailtextures.integer)
1336                                 RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(ent, texture);
1337                         else
1338                         {
1339                                 RSurfShader_OpaqueWall_Pass_BaseDoubleTex(ent, texture);
1340                                 if (r_detailtextures.integer)
1341                                         RSurfShader_OpaqueWall_Pass_BaseDetail(ent, texture);
1342                         }
1343                 }
1344                 else
1345                 {
1346                         RSurfShader_OpaqueWall_Pass_BaseTexture(ent, texture);
1347                         RSurfShader_OpaqueWall_Pass_BaseLightmap(ent, texture);
1348                         if (r_detailtextures.integer)
1349                                 RSurfShader_OpaqueWall_Pass_BaseDetail(ent, texture);
1350                 }
1351                 if (!r_dlightmap.integer && !(ent->effects & EF_FULLBRIGHT))
1352                         RSurfShader_OpaqueWall_Pass_Light(ent, texture);
1353                 if (texture->glowtexture)
1354                         RSurfShader_OpaqueWall_Pass_Glow(ent, texture);
1355                 if (fogenabled)
1356                         RSurfShader_OpaqueWall_Pass_Fog(ent, texture);
1357         }
1358 }
1359
1360 Cshader_t Cshader_wall_lightmap = {{NULL, RSurfShader_Wall_Lightmap}, SHADERFLAGS_NEEDLIGHTMAP};
1361 Cshader_t Cshader_wall_fullbright = {{NULL, RSurfShader_Wall_Fullbright}, 0};
1362 Cshader_t Cshader_water = {{NULL, RSurfShader_Water}, 0};
1363 Cshader_t Cshader_sky = {{RSurfShader_Sky, NULL}, 0};
1364
1365 int Cshader_count = 4;
1366 Cshader_t *Cshaders[4] =
1367 {
1368         &Cshader_wall_lightmap,
1369         &Cshader_wall_fullbright,
1370         &Cshader_water,
1371         &Cshader_sky
1372 };
1373
1374 void R_DrawSurfaces(entity_render_t *ent, int sky, int normal)
1375 {
1376         int i, alttextures, texframe, framecount, numtextures, numsurfaces, *surfacevisframes;
1377         texture_t *t, *textures;
1378         model_t *model;
1379         msurface_t *surf, *surfaces;
1380         vec3_t modelorg;
1381
1382         if (!ent->model)
1383                 return;
1384
1385         // mark the surfaces touched by dynamic lights
1386         if (normal && r_dynamic.integer)
1387                 R_MarkLights(ent);
1388
1389         R_Mesh_Matrix(&ent->matrix);
1390
1391         model = ent->model;
1392         alttextures = ent->frame != 0;
1393         texframe = (int)(cl.time * 5.0f);
1394
1395         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1396
1397         numtextures = model->numtextures;
1398         textures = model->textures;
1399         numsurfaces = model->nummodelsurfaces;
1400         surfaces = model->surfaces + model->firstmodelsurface;
1401         surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
1402
1403         for (i = 0;i < numtextures;i++)
1404                 textures[i].surfacechain = NULL;
1405
1406         for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
1407         {
1408                 if (surfacevisframes[i] == r_framecount)
1409                 {
1410 #if !WORLDNODECULLBACKFACES
1411                         // mark any backface surfaces as not visible
1412                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1413                         {
1414                                 if (!(surf->flags & SURF_PLANEBACK))
1415                                         surfacevisframes[i] = -1;
1416                         }
1417                         else
1418                         {
1419                                 if ((surf->flags & SURF_PLANEBACK))
1420                                         surfacevisframes[i] = -1;
1421                         }
1422                         if (surfacevisframes[i] == r_framecount)
1423 #endif
1424                         {
1425                                 c_faces++;
1426                                 t = surf->texinfo->texture;
1427                                 if (t->animated)
1428                                 {
1429                                         framecount = t->anim_total[alttextures];
1430                                         if (framecount >= 2)
1431                                                 t = t->anim_frames[alttextures][texframe % framecount];
1432                                         else
1433                                                 t = t->anim_frames[alttextures][0];
1434                                 }
1435                                 surf->currenttexture = t;
1436                                 surf->texturechain = t->surfacechain;
1437                                 t->surfacechain = surf;
1438                                 if (!r_vertexsurfaces.integer && surf->lightmaptexture != NULL)
1439                                 {
1440                                         if (surf->cached_dlight
1441                                         || surf->cached_ambient != r_ambient.value
1442                                         || surf->cached_lightscalebit != lightscalebit)
1443                                                 R_BuildLightMap(ent, surf, false); // base lighting changed
1444                                         else if (r_dynamic.integer)
1445                                         {
1446                                                 if  (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0]
1447                                                 || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
1448                                                 || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
1449                                                 || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
1450                                                         R_BuildLightMap(ent, surf, false); // base lighting changed
1451                                                 else if (surf->dlightframe == r_framecount && r_dlightmap.integer)
1452                                                         R_BuildLightMap(ent, surf, true); // only dlights
1453                                         }
1454                                 }
1455                         }
1456                 }
1457         }
1458
1459         if (sky)
1460                 for (i = 0, t = textures;i < numtextures;i++, t++)
1461                         if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_SKY])
1462                                 t->shader->shaderfunc[SHADERSTAGE_SKY](ent, t);
1463
1464         if (normal)
1465                 for (i = 0, t = textures;i < numtextures;i++, t++)
1466                         if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_NORMAL])
1467                                 t->shader->shaderfunc[SHADERSTAGE_NORMAL](ent, t);
1468 }
1469
1470 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
1471 {
1472         int i;
1473         float *v;
1474         rmeshstate_t m;
1475         const entity_render_t *ent = calldata1;
1476         const mportal_t *portal = ent->model->portals + calldata2;
1477         memset(&m, 0, sizeof(m));
1478         m.blendfunc1 = GL_SRC_ALPHA;
1479         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1480         //m.wantoverbright = false;
1481         R_Mesh_Matrix(&ent->matrix);
1482         R_Mesh_State(&m);
1483         R_Mesh_ResizeCheck(portal->numpoints);
1484         i = portal - ent->model->portals;
1485         R_FillColors(varray_color, portal->numpoints,
1486                 ((i & 0x0007) >> 0) * (1.0f / 7.0f) * mesh_colorscale,
1487                 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * mesh_colorscale,
1488                 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * mesh_colorscale,
1489                 0.125f);
1490         if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1491         {
1492                 for (i = portal->numpoints - 1, v = varray_vertex;i >= 0;i--, v += 4)
1493                         VectorCopy(portal->points[i].position, v);
1494         }
1495         else
1496                 for (i = 0, v = varray_vertex;i < portal->numpoints;i++, v += 4)
1497                         VectorCopy(portal->points[i].position, v);
1498         R_Mesh_Draw(portal->numpoints, portal->numpoints - 2, polygonelements);
1499 }
1500
1501 static void R_DrawPortals(entity_render_t *ent)
1502 {
1503         int i;
1504         mportal_t *portal, *endportal;
1505         float temp[3], center[3], f;
1506
1507         if (r_drawportals.integer < 1)
1508                 return;
1509
1510         for (portal = ent->model->portals, endportal = portal + ent->model->numportals;portal < endportal;portal++)
1511         {
1512                 if (portal->here->pvsframe == r_pvsframecount || portal->past->pvsframe == r_pvsframecount)
1513                 {
1514                         if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS)
1515                         {
1516                                 VectorClear(temp);
1517                                 for (i = 0;i < portal->numpoints;i++)
1518                                         VectorAdd(temp, portal->points[i].position, temp);
1519                                 f = ixtable[portal->numpoints];
1520                                 VectorScale(temp, f, temp);
1521                                 Matrix4x4_Transform(&ent->matrix, temp, center);
1522                                 R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, ent, portal - ent->model->portals);
1523                         }
1524                 }
1525         }
1526 }
1527
1528 void R_DrawBrushModel(entity_render_t *ent, int sky, int normal)
1529 {
1530         int i, numsurfaces, *surfacevisframes, *surfacepvsframes;
1531         msurface_t *surf;
1532         model_t *model;
1533 #if WORLDNODECULLBACKFACES
1534         vec3_t modelorg;
1535 #endif
1536
1537         // because bmodels can be reused, we have to decide which things to render
1538         // from scratch every time
1539         model = ent->model;
1540 #if WORLDNODECULLBACKFACES
1541         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1542 #endif
1543         numsurfaces = model->nummodelsurfaces;
1544         surf = model->surfaces + model->firstmodelsurface;
1545         surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
1546         surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface;
1547         for (i = 0;i < numsurfaces;i++, surf++)
1548         {
1549 #if WORLDNODECULLBACKFACES
1550                 // mark any backface surfaces as not visible
1551                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1552                 {
1553                         if ((surf->flags & SURF_PLANEBACK))
1554                         {
1555                                 surfacevisframes[i] = r_framecount;
1556                                 surfacepvsframes[i] = r_pvsframecount;
1557                         }
1558                 }
1559                 else
1560                 {
1561                         if (!(surf->flags & SURF_PLANEBACK))
1562                         {
1563                                 surfacevisframes[i] = r_framecount;
1564                                 surfacepvsframes[i] = r_pvsframecount;
1565                         }
1566                 }
1567 #else
1568                 surfacevisframes[i] = r_framecount;
1569                 surfacepvsframes[i] = r_pvsframecount;
1570 #endif
1571                 surf->dlightframe = -1;
1572         }
1573         R_DrawSurfaces(ent, sky, normal);
1574 }
1575
1576 void R_SurfaceWorldNode (entity_render_t *ent)
1577 {
1578         int i, numsurfaces, *surfacevisframes, *surfacepvsframes;
1579         msurface_t *surfaces, *surf;
1580         model_t *model;
1581         vec3_t modelorg;
1582
1583         model = ent->model;
1584         numsurfaces = model->nummodelsurfaces;
1585         surfaces = model->surfaces + model->firstmodelsurface;
1586         surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
1587         surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface;
1588         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1589
1590         for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
1591         {
1592                 if (surfacepvsframes[i] == r_pvsframecount)
1593                 {
1594 #if WORLDNODECULLBACKFACES
1595                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1596                         {
1597                                 if ((surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
1598                                         surfacevisframes[i] = r_framecount;
1599                         }
1600                         else
1601                         {
1602                                 if (!(surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
1603                                         surfacevisframes[i] = r_framecount;
1604                         }
1605 #else
1606                         if (R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
1607                                 surfacevisframes[i] = r_framecount;
1608 #endif
1609                 }
1610         }
1611 }
1612
1613 /*
1614 static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
1615 {
1616         int portalstack, i;
1617         mportal_t *p, *pstack[8192];
1618         msurface_t *surf, **mark, **endmark;
1619         mleaf_t *leaf;
1620         // LordHavoc: portal-passage worldnode with PVS;
1621         // follows portals leading outward from viewleaf, does not venture
1622         // offscreen or into leafs that are not visible, faster than Quake's
1623         // RecursiveWorldNode
1624         leaf = viewleaf;
1625         leaf->worldnodeframe = r_framecount;
1626         portalstack = 0;
1627 loc0:
1628         c_leafs++;
1629         if (leaf->nummarksurfaces)
1630         {
1631                 for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1632                 {
1633                         surf = *mark++;
1634                         // make sure surfaces are only processed once
1635                         if (surf->worldnodeframe != r_framecount)
1636                         {
1637                                 surf->worldnodeframe = r_framecount;
1638                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1639                                 {
1640                                         if (surf->flags & SURF_PLANEBACK)
1641                                                 surf->visframe = r_framecount;
1642                                 }
1643                                 else
1644                                 {
1645                                         if (!(surf->flags & SURF_PLANEBACK))
1646                                                 surf->visframe = r_framecount;
1647                                 }
1648                         }
1649                 }
1650         }
1651         // follow portals into other leafs
1652         for (p = leaf->portals;p;p = p->next)
1653         {
1654                 leaf = p->past;
1655                 if (leaf->worldnodeframe != r_framecount)
1656                 {
1657                         leaf->worldnodeframe = r_framecount;
1658                         // FIXME: R_NotCulledBox is absolute, should be done relative
1659                         if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
1660                         {
1661                                 p->visframe = r_framecount;
1662                                 pstack[portalstack++] = p;
1663                                 goto loc0;
1664 loc1:
1665                                 p = pstack[--portalstack];
1666                         }
1667                 }
1668         }
1669         if (portalstack)
1670                 goto loc1;
1671 }
1672 */
1673
1674 static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
1675 {
1676         int c, leafstackpos, *mark, *surfacevisframes;
1677 #if WORLDNODECULLBACKFACES
1678         int n;
1679         msurface_t *surf;
1680 #endif
1681         mleaf_t *leaf, *leafstack[8192];
1682         mportal_t *p;
1683         vec3_t modelorg;
1684         msurface_t *surfaces;
1685         // LordHavoc: portal-passage worldnode with PVS;
1686         // follows portals leading outward from viewleaf, does not venture
1687         // offscreen or into leafs that are not visible, faster than Quake's
1688         // RecursiveWorldNode
1689         surfaces = ent->model->surfaces;
1690         surfacevisframes = ent->model->surfacevisframes;
1691         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1692         viewleaf->worldnodeframe = r_framecount;
1693         leafstack[0] = viewleaf;
1694         leafstackpos = 1;
1695         while (leafstackpos)
1696         {
1697                 c_leafs++;
1698                 leaf = leafstack[--leafstackpos];
1699                 // draw any surfaces bounding this leaf
1700                 if (leaf->nummarksurfaces)
1701                 {
1702                         for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1703                         {
1704 #if WORLDNODECULLBACKFACES
1705                                 n = *mark++;
1706                                 if (surfacevisframes[n] != r_framecount)
1707                                 {
1708                                         surf = surfaces + n;
1709                                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1710                                         {
1711                                                 if ((surf->flags & SURF_PLANEBACK))
1712                                                         surfacevisframes[n] = r_framecount;
1713                                         }
1714                                         else
1715                                         {
1716                                                 if (!(surf->flags & SURF_PLANEBACK))
1717                                                         surfacevisframes[n] = r_framecount;
1718                                         }
1719                                 }
1720 #else
1721                                 surfacevisframes[*mark++] = r_framecount;
1722 #endif
1723                         }
1724                 }
1725                 // follow portals into other leafs
1726                 for (p = leaf->portals;p;p = p->next)
1727                 {
1728                         // LordHavoc: this DotProduct hurts less than a cache miss
1729                         // (which is more likely to happen if backflowing through leafs)
1730                         if (DotProduct(modelorg, p->plane.normal) < (p->plane.dist + 1))
1731                         {
1732                                 leaf = p->past;
1733                                 if (leaf->worldnodeframe != r_framecount)
1734                                 {
1735                                         leaf->worldnodeframe = r_framecount;
1736                                         // FIXME: R_NotCulledBox is absolute, should be done relative
1737                                         if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
1738                                                 leafstack[leafstackpos++] = leaf;
1739                                 }
1740                         }
1741                 }
1742         }
1743         if (r_drawportals.integer)
1744                 R_DrawPortals(ent);
1745 }
1746
1747 void R_PVSUpdate (mleaf_t *viewleaf)
1748 {
1749         int i, j, l, c, bits, *surfacepvsframes, *mark;
1750         mleaf_t *leaf;
1751         qbyte *vis;
1752
1753         if (r_pvsviewleaf == viewleaf && r_pvsviewleafnovis == r_novis.integer)
1754                 return;
1755
1756         r_pvsframecount++;
1757         r_pvsviewleaf = viewleaf;
1758         r_pvsviewleafnovis = r_novis.integer;
1759
1760         if (viewleaf)
1761         {
1762                 surfacepvsframes = cl.worldmodel->surfacepvsframes;
1763                 vis = Mod_LeafPVS (viewleaf, cl.worldmodel);
1764                 for (j = 0;j < cl.worldmodel->numleafs;j += 8)
1765                 {
1766                         bits = *vis++;
1767                         if (bits)
1768                         {
1769                                 l = cl.worldmodel->numleafs - j;
1770                                 if (l > 8)
1771                                         l = 8;
1772                                 for (i = 0;i < l;i++)
1773                                 {
1774                                         if (bits & (1 << i))
1775                                         {
1776                                                 leaf = &cl.worldmodel->leafs[j + i + 1];
1777                                                 leaf->pvsframe = r_pvsframecount;
1778                                                 // mark surfaces bounding this leaf as visible
1779                                                 for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1780                                                         surfacepvsframes[*mark++] = r_pvsframecount;
1781                                         }
1782                                 }
1783                         }
1784                 }
1785         }
1786 }
1787
1788 /*
1789 =============
1790 R_DrawWorld
1791 =============
1792 */
1793 void R_DrawWorld (entity_render_t *ent)
1794 {
1795         mleaf_t *viewleaf;
1796         viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
1797         R_PVSUpdate(viewleaf);
1798         if (!viewleaf)
1799                 return;
1800         if (r_surfaceworldnode.integer || viewleaf->contents == CONTENTS_SOLID)
1801                 R_SurfaceWorldNode (ent);
1802         else
1803                 R_PortalWorldNode (ent, viewleaf);
1804         R_DrawSurfaces(ent, true, true);
1805 }
1806
1807 /*
1808 =================
1809 R_DrawBrushModel
1810 =================
1811 */
1812 void R_DrawBrushModelSky (entity_render_t *ent)
1813 {
1814         R_DrawBrushModel(ent, true, false);
1815 }
1816
1817 void R_DrawBrushModelNormal (entity_render_t *ent)
1818 {
1819         c_bmodels++;
1820         R_DrawBrushModel(ent, false, true);
1821 }
1822
1823 static void gl_surf_start(void)
1824 {
1825 }
1826
1827 static void gl_surf_shutdown(void)
1828 {
1829 }
1830
1831 static void gl_surf_newmap(void)
1832 {
1833         // reset pvs visibility variables so it will update on first frame
1834         r_pvsframecount = 1;
1835         r_pvsviewleaf = NULL;
1836         r_pvsviewleafnovis = false;
1837 }
1838
1839 void GL_Surf_Init(void)
1840 {
1841         int i;
1842         dlightdivtable[0] = 4194304;
1843         for (i = 1;i < 32768;i++)
1844                 dlightdivtable[i] = 4194304 / (i << 7);
1845
1846         Cvar_RegisterVariable(&r_ambient);
1847         Cvar_RegisterVariable(&r_vertexsurfaces);
1848         Cvar_RegisterVariable(&r_dlightmap);
1849         Cvar_RegisterVariable(&r_drawportals);
1850         Cvar_RegisterVariable(&r_testvis);
1851         Cvar_RegisterVariable(&r_floatbuildlightmap);
1852         Cvar_RegisterVariable(&r_detailtextures);
1853         Cvar_RegisterVariable(&r_surfaceworldnode);
1854
1855         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
1856 }
1857