]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rsurf.c
stencil is now supported (optional, off by default, use vid_stencil to enable)
[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_lightmapscalebit = r_lightmapscalebit;
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 + r_lightmapscalebit + 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_lightmapscalebit = r_lightmapscalebit;
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 + r_lightmapscalebit + 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.depthwrite = true;
787         R_Mesh_State(&m);
788         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
789         {
790                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
791                 {
792                         R_Mesh_ResizeCheck(mesh->numverts);
793                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
794                         if (skyrendermasked)
795                                 memset(varray_color, 0, mesh->numverts * sizeof(float[4]));
796                         else
797                                 R_FillColors(varray_color, mesh->numverts, fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, 1);
798                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
799                 }
800         }
801 }
802
803 static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
804 {
805         const entity_render_t *ent = calldata1;
806         const msurface_t *surf = ent->model->surfaces + calldata2;
807         float f, colorscale;
808         const surfmesh_t *mesh;
809         rmeshstate_t m;
810         float alpha = ent->alpha * (surf->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value);
811         float modelorg[3];
812         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
813
814         R_Mesh_Matrix(&ent->matrix);
815
816         memset(&m, 0, sizeof(m));
817         if (ent->effects & EF_ADDITIVE)
818         {
819                 m.blendfunc1 = GL_SRC_ALPHA;
820                 m.blendfunc2 = GL_ONE;
821         }
822         else if (surf->currenttexture->fogtexture != NULL || alpha < 1)
823         {
824                 m.blendfunc1 = GL_SRC_ALPHA;
825                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
826         }
827         else
828         {
829                 m.blendfunc1 = GL_ONE;
830                 m.blendfunc2 = GL_ZERO;
831         }
832         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
833         colorscale = r_colorscale;
834         if (gl_combine.integer)
835         {
836                 m.texrgbscale[0] = 4;
837                 colorscale *= 0.25f;
838         }
839         R_Mesh_State(&m);
840         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
841         {
842                 R_Mesh_ResizeCheck(mesh->numverts);
843                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
844                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
845                 f = surf->flags & SURF_DRAWFULLBRIGHT ? 1.0f : ((surf->flags & SURF_LIGHTMAP) ? 0 : 0.5f);
846                 R_FillColors(varray_color, mesh->numverts, f, f, f, alpha);
847                 if (!(surf->flags & SURF_DRAWFULLBRIGHT || ent->effects & EF_FULLBRIGHT))
848                 {
849                         if (surf->dlightframe == r_framecount)
850                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, mesh->numverts, varray_vertex, varray_color);
851                         if (surf->flags & SURF_LIGHTMAP)
852                                 RSurf_AddLightmapToVertexColors(mesh->lightmapoffsets, varray_color, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
853                 }
854                 RSurf_FogColors(varray_vertex, varray_color, colorscale, mesh->numverts, modelorg);
855                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
856         }
857
858         if (fogenabled)
859         {
860                 memset(&m, 0, sizeof(m));
861                 m.blendfunc1 = GL_SRC_ALPHA;
862                 m.blendfunc2 = GL_ONE;
863                 m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
864                 R_Mesh_State(&m);
865                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
866                 {
867                         R_Mesh_ResizeCheck(mesh->numverts);
868                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
869                         if (m.tex[0])
870                                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
871                         RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], alpha, r_colorscale, mesh->numverts, modelorg);
872                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
873                 }
874         }
875 }
876
877 static void RSurfShader_Water(const entity_render_t *ent, const texture_t *texture)
878 {
879         const msurface_t *surf;
880         vec3_t center;
881         if ((r_wateralpha.value < 1 && !(texture->flags & SURF_DRAWNOALPHA)) || ent->effects & EF_ADDITIVE || texture->fogtexture)
882         {
883                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
884                 {
885                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
886                         R_MeshQueue_AddTransparent(center, RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
887                 }
888         }
889         else
890                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
891                         RSurfShader_Water_Callback(ent, surf - ent->model->surfaces);
892 }
893
894 static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf)
895 {
896         float base, colorscale;
897         const surfmesh_t *mesh;
898         rmeshstate_t m;
899         float modelorg[3];
900         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
901         memset(&m, 0, sizeof(m));
902         if (ent->effects & EF_ADDITIVE)
903         {
904                 m.blendfunc1 = GL_SRC_ALPHA;
905                 m.blendfunc2 = GL_ONE;
906         }
907         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
908         {
909                 m.blendfunc1 = GL_SRC_ALPHA;
910                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
911         }
912         else
913         {
914                 m.blendfunc1 = GL_ONE;
915                 m.blendfunc2 = GL_ZERO;
916         }
917         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
918         colorscale = r_colorscale;
919         if (gl_combine.integer)
920         {
921                 m.texrgbscale[0] = 4;
922                 colorscale *= 0.25f;
923         }
924         base = ent->effects & EF_FULLBRIGHT ? 2.0f : r_ambient.value * (1.0f / 64.0f);
925         R_Mesh_State(&m);
926         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
927         {
928                 R_Mesh_ResizeCheck(mesh->numverts);
929                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
930                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
931                 R_FillColors(varray_color, mesh->numverts, base, base, base, ent->alpha);
932                 if (!(ent->effects & EF_FULLBRIGHT))
933                 {
934                         if (surf->dlightframe == r_framecount)
935                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, mesh->numverts, varray_vertex, varray_color);
936                         if (surf->flags & SURF_LIGHTMAP)
937                                 RSurf_AddLightmapToVertexColors(mesh->lightmapoffsets, varray_color, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
938                 }
939                 RSurf_FogColors(varray_vertex, varray_color, colorscale, mesh->numverts, modelorg);
940                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
941         }
942 }
943
944 static void RSurfShader_Wall_Pass_BaseFullbright(const entity_render_t *ent, const msurface_t *surf)
945 {
946         const surfmesh_t *mesh;
947         rmeshstate_t m;
948         float modelorg[3];
949         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
950         memset(&m, 0, sizeof(m));
951         if (ent->effects & EF_ADDITIVE)
952         {
953                 m.blendfunc1 = GL_SRC_ALPHA;
954                 m.blendfunc2 = GL_ONE;
955         }
956         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
957         {
958                 m.blendfunc1 = GL_SRC_ALPHA;
959                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
960         }
961         else
962         {
963                 m.blendfunc1 = GL_ONE;
964                 m.blendfunc2 = GL_ZERO;
965         }
966         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
967         R_Mesh_State(&m);
968         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
969         {
970                 R_Mesh_ResizeCheck(mesh->numverts);
971                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
972                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
973                 RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, ent->alpha, r_colorscale, mesh->numverts, modelorg);
974                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
975         }
976 }
977
978 static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
979 {
980         const surfmesh_t *mesh;
981         rmeshstate_t m;
982         float modelorg[3];
983         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
984         memset(&m, 0, sizeof(m));
985         m.blendfunc1 = GL_SRC_ALPHA;
986         m.blendfunc2 = GL_ONE;
987         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
988         R_Mesh_State(&m);
989         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
990         {
991                 R_Mesh_ResizeCheck(mesh->numverts);
992                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
993                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
994                 RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, ent->alpha, r_colorscale, mesh->numverts, modelorg);
995                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
996         }
997 }
998
999 static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1000 {
1001         const surfmesh_t *mesh;
1002         rmeshstate_t m;
1003         float modelorg[3];
1004         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1005         memset(&m, 0, sizeof(m));
1006         m.blendfunc1 = GL_SRC_ALPHA;
1007         m.blendfunc2 = GL_ONE;
1008         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1009         R_Mesh_State(&m);
1010         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1011         {
1012                 R_Mesh_ResizeCheck(mesh->numverts);
1013                 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1014                 if (m.tex[0])
1015                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1016                 RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, r_colorscale, mesh->numverts, modelorg);
1017                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1018         }
1019 }
1020
1021 static void RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(const entity_render_t *ent, const texture_t *texture)
1022 {
1023         const msurface_t *surf;
1024         const surfmesh_t *mesh;
1025         rmeshstate_t m;
1026         int lightmaptexturenum;
1027         float cl;
1028         memset(&m, 0, sizeof(m));
1029         m.blendfunc1 = GL_ONE;
1030         m.blendfunc2 = GL_ZERO;
1031         m.tex[0] = R_GetTexture(texture->texture);
1032         m.tex[1] = R_GetTexture(texture->surfacechain->lightmaptexture);
1033         m.tex[2] = R_GetTexture(texture->detailtexture);
1034         m.texrgbscale[0] = 1;
1035         m.texrgbscale[1] = 4;
1036         m.texrgbscale[2] = 2;
1037         R_Mesh_State(&m);
1038         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1039         {
1040                 lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
1041                 if (m.tex[1] != lightmaptexturenum)
1042                 {
1043                         m.tex[1] = lightmaptexturenum;
1044                         R_Mesh_State(&m);
1045                 }
1046                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1047                 {
1048                         R_Mesh_ResizeCheck(mesh->numverts);
1049                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1050                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1051                         memcpy(varray_texcoord[1], mesh->uv, mesh->numverts * sizeof(float[2]));
1052                         memcpy(varray_texcoord[2], mesh->ab, mesh->numverts * sizeof(float[2]));
1053                         cl = (float) (1 << r_lightmapscalebit) * r_colorscale;
1054                         R_FillColors(varray_color, mesh->numverts, cl, cl, cl, 1);
1055                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1056                 }
1057         }
1058 }
1059
1060 static void RSurfShader_OpaqueWall_Pass_BaseDoubleTex(const entity_render_t *ent, const texture_t *texture)
1061 {
1062         const msurface_t *surf;
1063         const surfmesh_t *mesh;
1064         rmeshstate_t m;
1065         int lightmaptexturenum;
1066         memset(&m, 0, sizeof(m));
1067         m.blendfunc1 = GL_ONE;
1068         m.blendfunc2 = GL_ZERO;
1069         m.tex[0] = R_GetTexture(texture->texture);
1070         m.tex[1] = R_GetTexture(texture->surfacechain->lightmaptexture);
1071         if (gl_combine.integer)
1072                 m.texrgbscale[1] = 4;
1073         R_Mesh_State(&m);
1074         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1075         {
1076                 lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
1077                 if (m.tex[1] != lightmaptexturenum)
1078                 {
1079                         m.tex[1] = lightmaptexturenum;
1080                         R_Mesh_State(&m);
1081                 }
1082                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1083                 {
1084                         R_Mesh_ResizeCheck(mesh->numverts);
1085                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1086                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1087                         memcpy(varray_texcoord[1], mesh->uv, mesh->numverts * sizeof(float[2]));
1088                         R_FillColors(varray_color, mesh->numverts, r_colorscale, r_colorscale, r_colorscale, 1);
1089                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1090                 }
1091         }
1092 }
1093
1094 static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent, const texture_t *texture)
1095 {
1096         const msurface_t *surf;
1097         const surfmesh_t *mesh;
1098         rmeshstate_t m;
1099         memset(&m, 0, sizeof(m));
1100         m.blendfunc1 = GL_ONE;
1101         m.blendfunc2 = GL_ZERO;
1102         m.tex[0] = R_GetTexture(texture->texture);
1103         R_Mesh_State(&m);
1104         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1105         {
1106                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1107                 {
1108                         R_Mesh_ResizeCheck(mesh->numverts);
1109                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1110                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1111                         R_FillColors(varray_color, mesh->numverts, 1, 1, 1, 1);
1112                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1113                 }
1114         }
1115 }
1116
1117 static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent, const texture_t *texture)
1118 {
1119         const msurface_t *surf;
1120         const surfmesh_t *mesh;
1121         rmeshstate_t m;
1122         int lightmaptexturenum;
1123         memset(&m, 0, sizeof(m));
1124         m.blendfunc1 = GL_ZERO;
1125         m.blendfunc2 = GL_SRC_COLOR;
1126         m.tex[0] = R_GetTexture(texture->surfacechain->lightmaptexture);
1127         if (gl_combine.integer)
1128                 m.texrgbscale[0] = 4;
1129         R_Mesh_State(&m);
1130         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1131         {
1132                 lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
1133                 if (m.tex[0] != lightmaptexturenum)
1134                 {
1135                         m.tex[0] = lightmaptexturenum;
1136                         R_Mesh_State(&m);
1137                 }
1138                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1139                 {
1140                         R_Mesh_ResizeCheck(mesh->numverts);
1141                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1142                         memcpy(varray_texcoord[0], mesh->uv, mesh->numverts * sizeof(float[2]));
1143                         R_FillColors(varray_color, mesh->numverts, r_colorscale, r_colorscale, r_colorscale, 1);
1144                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1145                 }
1146         }
1147 }
1148
1149 static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const texture_t *texture)
1150 {
1151         const msurface_t *surf;
1152         const surfmesh_t *mesh;
1153         float colorscale;
1154         rmeshstate_t m;
1155
1156         memset(&m, 0, sizeof(m));
1157         m.blendfunc1 = GL_SRC_ALPHA;
1158         m.blendfunc2 = GL_ONE;
1159         m.tex[0] = R_GetTexture(texture->texture);
1160         colorscale = r_colorscale;
1161         if (gl_combine.integer)
1162         {
1163                 m.texrgbscale[0] = 4;
1164                 colorscale *= 0.25f;
1165         }
1166         R_Mesh_State(&m);
1167         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1168         {
1169                 if (surf->dlightframe == r_framecount)
1170                 {
1171                         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1172                         {
1173                                 if (RSurf_LightCheck(&ent->inversematrix, surf->dlightbits, mesh))
1174                                 {
1175                                         R_Mesh_ResizeCheck(mesh->numverts);
1176                                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1177                                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1178                                         R_FillColors(varray_color, mesh->numverts, 0, 0, 0, 1);
1179                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, mesh->numverts, varray_vertex, varray_color);
1180                                         RSurf_ScaleColors(varray_color, colorscale, mesh->numverts);
1181                                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1182                                 }
1183                         }
1184                 }
1185         }
1186 }
1187
1188 static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const texture_t *texture)
1189 {
1190         const msurface_t *surf;
1191         const surfmesh_t *mesh;
1192         rmeshstate_t m;
1193         float modelorg[3];
1194         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1195         memset(&m, 0, sizeof(m));
1196         m.blendfunc1 = GL_SRC_ALPHA;
1197         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1198         R_Mesh_State(&m);
1199         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1200         {
1201                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1202                 {
1203                         R_Mesh_ResizeCheck(mesh->numverts);
1204                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1205                         if (m.tex[0])
1206                                 memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1207                         RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], 1, r_colorscale, mesh->numverts, modelorg);
1208                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1209                 }
1210         }
1211 }
1212
1213 static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, const texture_t *texture)
1214 {
1215         const msurface_t *surf;
1216         const surfmesh_t *mesh;
1217         rmeshstate_t m;
1218         memset(&m, 0, sizeof(m));
1219         m.blendfunc1 = GL_DST_COLOR;
1220         m.blendfunc2 = GL_SRC_COLOR;
1221         m.tex[0] = R_GetTexture(texture->detailtexture);
1222         R_Mesh_State(&m);
1223         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1224         {
1225                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1226                 {
1227                         R_Mesh_ResizeCheck(mesh->numverts);
1228                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1229                         memcpy(varray_texcoord[0], mesh->ab, mesh->numverts * sizeof(float[2]));
1230                         R_FillColors(varray_color, mesh->numverts, 1, 1, 1, 1);
1231                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1232                 }
1233         }
1234 }
1235
1236 static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const texture_t *texture)
1237 {
1238         const msurface_t *surf;
1239         const surfmesh_t *mesh;
1240         rmeshstate_t m;
1241         memset(&m, 0, sizeof(m));
1242         m.blendfunc1 = GL_SRC_ALPHA;
1243         m.blendfunc2 = GL_ONE;
1244         m.tex[0] = R_GetTexture(texture->glowtexture);
1245         R_Mesh_State(&m);
1246         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1247         {
1248                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1249                 {
1250                         R_Mesh_ResizeCheck(mesh->numverts);
1251                         memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1252                         memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
1253                         R_FillColors(varray_color, mesh->numverts, r_colorscale, r_colorscale, r_colorscale, 1);
1254                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
1255                 }
1256         }
1257 }
1258
1259 static void RSurfShader_Wall_Fullbright_Callback(const void *calldata1, int calldata2)
1260 {
1261         const entity_render_t *ent = calldata1;
1262         const msurface_t *surf = ent->model->surfaces + calldata2;
1263         R_Mesh_Matrix(&ent->matrix);
1264         RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1265         if (surf->currenttexture->glowtexture)
1266                 RSurfShader_Wall_Pass_Glow(ent, surf);
1267         if (fogenabled)
1268                 RSurfShader_Wall_Pass_Fog(ent, surf);
1269 }
1270
1271 static void RSurfShader_Wall_Fullbright(const entity_render_t *ent, const texture_t *texture)
1272 {
1273         const msurface_t *surf;
1274         vec3_t center;
1275         if (ent->effects & EF_ADDITIVE || ent->alpha < 1 || texture->fogtexture != NULL)
1276         {
1277                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1278                 {
1279                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1280                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1281                 }
1282         }
1283         else
1284         {
1285                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1286                         RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1287                 if (texture->glowtexture)
1288                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1289                                 RSurfShader_Wall_Pass_Glow(ent, surf);
1290                 if (fogenabled)
1291                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1292                                 RSurfShader_Wall_Pass_Fog(ent, surf);
1293         }
1294 }
1295
1296 static void RSurfShader_Wall_Vertex_Callback(const void *calldata1, int calldata2)
1297 {
1298         const entity_render_t *ent = calldata1;
1299         const msurface_t *surf = ent->model->surfaces + calldata2;
1300         R_Mesh_Matrix(&ent->matrix);
1301         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1302         if (surf->currenttexture->glowtexture)
1303                 RSurfShader_Wall_Pass_Glow(ent, surf);
1304         if (fogenabled)
1305                 RSurfShader_Wall_Pass_Fog(ent, surf);
1306 }
1307
1308 static void RSurfShader_Wall_Lightmap(const entity_render_t *ent, const texture_t *texture)
1309 {
1310         const msurface_t *surf;
1311         vec3_t center;
1312         if (ent->effects & EF_ADDITIVE || ent->alpha < 1 || texture->fogtexture != NULL)
1313         {
1314                 // transparent vertex shaded from lightmap
1315                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1316                 {
1317                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1318                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1319                 }
1320         }
1321         else if (r_vertexsurfaces.integer)
1322         {
1323                 // opaque vertex shaded from lightmap
1324                 for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1325                         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1326                 if (texture->glowtexture)
1327                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1328                                 RSurfShader_Wall_Pass_Glow(ent, surf);
1329                 if (fogenabled)
1330                         for (surf = texture->surfacechain;surf;surf = surf->texturechain)
1331                                 RSurfShader_Wall_Pass_Fog(ent, surf);
1332         }
1333         else
1334         {
1335                 // opaque lightmapped
1336                 if (r_textureunits.integer >= 2)
1337                 {
1338                         if (r_textureunits.integer >= 3 && gl_combine.integer && r_detailtextures.integer)
1339                                 RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(ent, texture);
1340                         else
1341                         {
1342                                 RSurfShader_OpaqueWall_Pass_BaseDoubleTex(ent, texture);
1343                                 if (r_detailtextures.integer)
1344                                         RSurfShader_OpaqueWall_Pass_BaseDetail(ent, texture);
1345                         }
1346                 }
1347                 else
1348                 {
1349                         RSurfShader_OpaqueWall_Pass_BaseTexture(ent, texture);
1350                         RSurfShader_OpaqueWall_Pass_BaseLightmap(ent, texture);
1351                         if (r_detailtextures.integer)
1352                                 RSurfShader_OpaqueWall_Pass_BaseDetail(ent, texture);
1353                 }
1354                 if (!r_dlightmap.integer && !(ent->effects & EF_FULLBRIGHT))
1355                         RSurfShader_OpaqueWall_Pass_Light(ent, texture);
1356                 if (texture->glowtexture)
1357                         RSurfShader_OpaqueWall_Pass_Glow(ent, texture);
1358                 if (fogenabled)
1359                         RSurfShader_OpaqueWall_Pass_Fog(ent, texture);
1360         }
1361 }
1362
1363 Cshader_t Cshader_wall_lightmap = {{NULL, RSurfShader_Wall_Lightmap}, SHADERFLAGS_NEEDLIGHTMAP};
1364 Cshader_t Cshader_wall_fullbright = {{NULL, RSurfShader_Wall_Fullbright}, 0};
1365 Cshader_t Cshader_water = {{NULL, RSurfShader_Water}, 0};
1366 Cshader_t Cshader_sky = {{RSurfShader_Sky, NULL}, 0};
1367
1368 int Cshader_count = 4;
1369 Cshader_t *Cshaders[4] =
1370 {
1371         &Cshader_wall_lightmap,
1372         &Cshader_wall_fullbright,
1373         &Cshader_water,
1374         &Cshader_sky
1375 };
1376
1377 void R_DrawSurfaces(entity_render_t *ent, int sky, int normal)
1378 {
1379         int i, alttextures, texframe, framecount, numtextures, numsurfaces, *surfacevisframes;
1380         texture_t *t, *textures;
1381         model_t *model;
1382         msurface_t *surf, *surfaces;
1383         vec3_t modelorg;
1384
1385         if (!ent->model)
1386                 return;
1387
1388         // mark the surfaces touched by dynamic lights
1389         if (normal && r_dynamic.integer)
1390                 R_MarkLights(ent);
1391
1392         R_Mesh_Matrix(&ent->matrix);
1393
1394         model = ent->model;
1395         alttextures = ent->frame != 0;
1396         texframe = (int)(cl.time * 5.0f);
1397
1398         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1399
1400         numtextures = model->numtextures;
1401         textures = model->textures;
1402         numsurfaces = model->nummodelsurfaces;
1403         surfaces = model->surfaces + model->firstmodelsurface;
1404         surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
1405
1406         for (i = 0;i < numtextures;i++)
1407                 textures[i].surfacechain = NULL;
1408
1409         for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
1410         {
1411                 if (surfacevisframes[i] == r_framecount)
1412                 {
1413 #if !WORLDNODECULLBACKFACES
1414                         // mark any backface surfaces as not visible
1415                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1416                         {
1417                                 if (!(surf->flags & SURF_PLANEBACK))
1418                                         surfacevisframes[i] = -1;
1419                         }
1420                         else
1421                         {
1422                                 if ((surf->flags & SURF_PLANEBACK))
1423                                         surfacevisframes[i] = -1;
1424                         }
1425                         if (surfacevisframes[i] == r_framecount)
1426 #endif
1427                         {
1428                                 c_faces++;
1429                                 t = surf->texinfo->texture;
1430                                 if (t->animated)
1431                                 {
1432                                         framecount = t->anim_total[alttextures];
1433                                         if (framecount >= 2)
1434                                                 t = t->anim_frames[alttextures][texframe % framecount];
1435                                         else
1436                                                 t = t->anim_frames[alttextures][0];
1437                                 }
1438                                 surf->currenttexture = t;
1439                                 surf->texturechain = t->surfacechain;
1440                                 t->surfacechain = surf;
1441                                 if (!r_vertexsurfaces.integer && surf->lightmaptexture != NULL)
1442                                 {
1443                                         if (surf->cached_dlight
1444                                         || surf->cached_ambient != r_ambient.value
1445                                         || surf->cached_lightmapscalebit != r_lightmapscalebit)
1446                                                 R_BuildLightMap(ent, surf, false); // base lighting changed
1447                                         else if (r_dynamic.integer)
1448                                         {
1449                                                 if  (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0]
1450                                                 || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
1451                                                 || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
1452                                                 || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
1453                                                         R_BuildLightMap(ent, surf, false); // base lighting changed
1454                                                 else if (surf->dlightframe == r_framecount && r_dlightmap.integer)
1455                                                         R_BuildLightMap(ent, surf, true); // only dlights
1456                                         }
1457                                 }
1458                         }
1459                 }
1460         }
1461
1462         if (sky)
1463                 for (i = 0, t = textures;i < numtextures;i++, t++)
1464                         if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_SKY])
1465                                 t->shader->shaderfunc[SHADERSTAGE_SKY](ent, t);
1466
1467         if (normal)
1468                 for (i = 0, t = textures;i < numtextures;i++, t++)
1469                         if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_NORMAL])
1470                                 t->shader->shaderfunc[SHADERSTAGE_NORMAL](ent, t);
1471 }
1472
1473 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
1474 {
1475         int i;
1476         float *v;
1477         rmeshstate_t m;
1478         const entity_render_t *ent = calldata1;
1479         const mportal_t *portal = ent->model->portals + calldata2;
1480         memset(&m, 0, sizeof(m));
1481         m.blendfunc1 = GL_SRC_ALPHA;
1482         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1483         R_Mesh_Matrix(&ent->matrix);
1484         R_Mesh_State(&m);
1485         R_Mesh_ResizeCheck(portal->numpoints);
1486         i = portal - ent->model->portals;
1487         R_FillColors(varray_color, portal->numpoints,
1488                 ((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_colorscale,
1489                 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_colorscale,
1490                 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_colorscale,
1491                 0.125f);
1492         if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1493         {
1494                 for (i = portal->numpoints - 1, v = varray_vertex;i >= 0;i--, v += 4)
1495                         VectorCopy(portal->points[i].position, v);
1496         }
1497         else
1498                 for (i = 0, v = varray_vertex;i < portal->numpoints;i++, v += 4)
1499                         VectorCopy(portal->points[i].position, v);
1500         R_Mesh_Draw(portal->numpoints, portal->numpoints - 2, polygonelements);
1501 }
1502
1503 static void R_DrawPortals(entity_render_t *ent)
1504 {
1505         int i;
1506         mportal_t *portal, *endportal;
1507         float temp[3], center[3], f;
1508
1509         if (r_drawportals.integer < 1)
1510                 return;
1511
1512         for (portal = ent->model->portals, endportal = portal + ent->model->numportals;portal < endportal;portal++)
1513         {
1514                 if (portal->here->pvsframe == r_pvsframecount || portal->past->pvsframe == r_pvsframecount)
1515                 {
1516                         if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS)
1517                         {
1518                                 VectorClear(temp);
1519                                 for (i = 0;i < portal->numpoints;i++)
1520                                         VectorAdd(temp, portal->points[i].position, temp);
1521                                 f = ixtable[portal->numpoints];
1522                                 VectorScale(temp, f, temp);
1523                                 Matrix4x4_Transform(&ent->matrix, temp, center);
1524                                 R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, ent, portal - ent->model->portals);
1525                         }
1526                 }
1527         }
1528 }
1529
1530 void R_DrawBrushModel(entity_render_t *ent, int sky, int normal)
1531 {
1532         int i, numsurfaces, *surfacevisframes, *surfacepvsframes;
1533         msurface_t *surf;
1534         model_t *model;
1535 #if WORLDNODECULLBACKFACES
1536         vec3_t modelorg;
1537 #endif
1538
1539         // because bmodels can be reused, we have to decide which things to render
1540         // from scratch every time
1541         model = ent->model;
1542 #if WORLDNODECULLBACKFACES
1543         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1544 #endif
1545         numsurfaces = model->nummodelsurfaces;
1546         surf = model->surfaces + model->firstmodelsurface;
1547         surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
1548         surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface;
1549         for (i = 0;i < numsurfaces;i++, surf++)
1550         {
1551 #if WORLDNODECULLBACKFACES
1552                 // mark any backface surfaces as not visible
1553                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1554                 {
1555                         if ((surf->flags & SURF_PLANEBACK))
1556                         {
1557                                 surfacevisframes[i] = r_framecount;
1558                                 surfacepvsframes[i] = r_pvsframecount;
1559                         }
1560                 }
1561                 else
1562                 {
1563                         if (!(surf->flags & SURF_PLANEBACK))
1564                         {
1565                                 surfacevisframes[i] = r_framecount;
1566                                 surfacepvsframes[i] = r_pvsframecount;
1567                         }
1568                 }
1569 #else
1570                 surfacevisframes[i] = r_framecount;
1571                 surfacepvsframes[i] = r_pvsframecount;
1572 #endif
1573                 surf->dlightframe = -1;
1574         }
1575         R_DrawSurfaces(ent, sky, normal);
1576 }
1577
1578 void R_SurfaceWorldNode (entity_render_t *ent)
1579 {
1580         int i, numsurfaces, *surfacevisframes, *surfacepvsframes;
1581         msurface_t *surfaces, *surf;
1582         model_t *model;
1583         vec3_t modelorg;
1584
1585         model = ent->model;
1586         numsurfaces = model->nummodelsurfaces;
1587         surfaces = model->surfaces + model->firstmodelsurface;
1588         surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
1589         surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface;
1590         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1591
1592         for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
1593         {
1594                 if (surfacepvsframes[i] == r_pvsframecount)
1595                 {
1596 #if WORLDNODECULLBACKFACES
1597                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1598                         {
1599                                 if ((surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
1600                                         surfacevisframes[i] = r_framecount;
1601                         }
1602                         else
1603                         {
1604                                 if (!(surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
1605                                         surfacevisframes[i] = r_framecount;
1606                         }
1607 #else
1608                         if (R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
1609                                 surfacevisframes[i] = r_framecount;
1610 #endif
1611                 }
1612         }
1613 }
1614
1615 /*
1616 static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
1617 {
1618         int portalstack, i;
1619         mportal_t *p, *pstack[8192];
1620         msurface_t *surf, **mark, **endmark;
1621         mleaf_t *leaf;
1622         // LordHavoc: portal-passage worldnode with PVS;
1623         // follows portals leading outward from viewleaf, does not venture
1624         // offscreen or into leafs that are not visible, faster than Quake's
1625         // RecursiveWorldNode
1626         leaf = viewleaf;
1627         leaf->worldnodeframe = r_framecount;
1628         portalstack = 0;
1629 loc0:
1630         c_leafs++;
1631         if (leaf->nummarksurfaces)
1632         {
1633                 for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1634                 {
1635                         surf = *mark++;
1636                         // make sure surfaces are only processed once
1637                         if (surf->worldnodeframe != r_framecount)
1638                         {
1639                                 surf->worldnodeframe = r_framecount;
1640                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1641                                 {
1642                                         if (surf->flags & SURF_PLANEBACK)
1643                                                 surf->visframe = r_framecount;
1644                                 }
1645                                 else
1646                                 {
1647                                         if (!(surf->flags & SURF_PLANEBACK))
1648                                                 surf->visframe = r_framecount;
1649                                 }
1650                         }
1651                 }
1652         }
1653         // follow portals into other leafs
1654         for (p = leaf->portals;p;p = p->next)
1655         {
1656                 leaf = p->past;
1657                 if (leaf->worldnodeframe != r_framecount)
1658                 {
1659                         leaf->worldnodeframe = r_framecount;
1660                         // FIXME: R_NotCulledBox is absolute, should be done relative
1661                         if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
1662                         {
1663                                 p->visframe = r_framecount;
1664                                 pstack[portalstack++] = p;
1665                                 goto loc0;
1666 loc1:
1667                                 p = pstack[--portalstack];
1668                         }
1669                 }
1670         }
1671         if (portalstack)
1672                 goto loc1;
1673 }
1674 */
1675
1676 static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
1677 {
1678         int c, leafstackpos, *mark, *surfacevisframes;
1679 #if WORLDNODECULLBACKFACES
1680         int n;
1681         msurface_t *surf;
1682 #endif
1683         mleaf_t *leaf, *leafstack[8192];
1684         mportal_t *p;
1685         vec3_t modelorg;
1686         msurface_t *surfaces;
1687         // LordHavoc: portal-passage worldnode with PVS;
1688         // follows portals leading outward from viewleaf, does not venture
1689         // offscreen or into leafs that are not visible, faster than Quake's
1690         // RecursiveWorldNode
1691         surfaces = ent->model->surfaces;
1692         surfacevisframes = ent->model->surfacevisframes;
1693         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1694         viewleaf->worldnodeframe = r_framecount;
1695         leafstack[0] = viewleaf;
1696         leafstackpos = 1;
1697         while (leafstackpos)
1698         {
1699                 c_leafs++;
1700                 leaf = leafstack[--leafstackpos];
1701                 // draw any surfaces bounding this leaf
1702                 if (leaf->nummarksurfaces)
1703                 {
1704                         for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1705                         {
1706 #if WORLDNODECULLBACKFACES
1707                                 n = *mark++;
1708                                 if (surfacevisframes[n] != r_framecount)
1709                                 {
1710                                         surf = surfaces + n;
1711                                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1712                                         {
1713                                                 if ((surf->flags & SURF_PLANEBACK))
1714                                                         surfacevisframes[n] = r_framecount;
1715                                         }
1716                                         else
1717                                         {
1718                                                 if (!(surf->flags & SURF_PLANEBACK))
1719                                                         surfacevisframes[n] = r_framecount;
1720                                         }
1721                                 }
1722 #else
1723                                 surfacevisframes[*mark++] = r_framecount;
1724 #endif
1725                         }
1726                 }
1727                 // follow portals into other leafs
1728                 for (p = leaf->portals;p;p = p->next)
1729                 {
1730                         // LordHavoc: this DotProduct hurts less than a cache miss
1731                         // (which is more likely to happen if backflowing through leafs)
1732                         if (DotProduct(modelorg, p->plane.normal) < (p->plane.dist + 1))
1733                         {
1734                                 leaf = p->past;
1735                                 if (leaf->worldnodeframe != r_framecount)
1736                                 {
1737                                         leaf->worldnodeframe = r_framecount;
1738                                         // FIXME: R_NotCulledBox is absolute, should be done relative
1739                                         if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
1740                                                 leafstack[leafstackpos++] = leaf;
1741                                 }
1742                         }
1743                 }
1744         }
1745         if (r_drawportals.integer)
1746                 R_DrawPortals(ent);
1747 }
1748
1749 void R_PVSUpdate (mleaf_t *viewleaf)
1750 {
1751         int i, j, l, c, bits, *surfacepvsframes, *mark;
1752         mleaf_t *leaf;
1753         qbyte *vis;
1754
1755         if (r_pvsviewleaf == viewleaf && r_pvsviewleafnovis == r_novis.integer)
1756                 return;
1757
1758         r_pvsframecount++;
1759         r_pvsviewleaf = viewleaf;
1760         r_pvsviewleafnovis = r_novis.integer;
1761
1762         if (viewleaf)
1763         {
1764                 surfacepvsframes = cl.worldmodel->surfacepvsframes;
1765                 vis = Mod_LeafPVS (viewleaf, cl.worldmodel);
1766                 for (j = 0;j < cl.worldmodel->numleafs;j += 8)
1767                 {
1768                         bits = *vis++;
1769                         if (bits)
1770                         {
1771                                 l = cl.worldmodel->numleafs - j;
1772                                 if (l > 8)
1773                                         l = 8;
1774                                 for (i = 0;i < l;i++)
1775                                 {
1776                                         if (bits & (1 << i))
1777                                         {
1778                                                 leaf = &cl.worldmodel->leafs[j + i + 1];
1779                                                 leaf->pvsframe = r_pvsframecount;
1780                                                 // mark surfaces bounding this leaf as visible
1781                                                 for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1782                                                         surfacepvsframes[*mark++] = r_pvsframecount;
1783                                         }
1784                                 }
1785                         }
1786                 }
1787         }
1788 }
1789
1790 /*
1791 =============
1792 R_DrawWorld
1793 =============
1794 */
1795 void R_DrawWorld (entity_render_t *ent)
1796 {
1797         mleaf_t *viewleaf;
1798         viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
1799         R_PVSUpdate(viewleaf);
1800         if (!viewleaf)
1801                 return;
1802         if (r_surfaceworldnode.integer || viewleaf->contents == CONTENTS_SOLID)
1803                 R_SurfaceWorldNode (ent);
1804         else
1805                 R_PortalWorldNode (ent, viewleaf);
1806         R_DrawSurfaces(ent, true, true);
1807 }
1808
1809 /*
1810 =================
1811 R_DrawBrushModel
1812 =================
1813 */
1814 void R_DrawBrushModelSky (entity_render_t *ent)
1815 {
1816         R_DrawBrushModel(ent, true, false);
1817 }
1818
1819 void R_DrawBrushModelNormal (entity_render_t *ent)
1820 {
1821         c_bmodels++;
1822         R_DrawBrushModel(ent, false, true);
1823 }
1824
1825 static void gl_surf_start(void)
1826 {
1827 }
1828
1829 static void gl_surf_shutdown(void)
1830 {
1831 }
1832
1833 static void gl_surf_newmap(void)
1834 {
1835         // reset pvs visibility variables so it will update on first frame
1836         r_pvsframecount = 1;
1837         r_pvsviewleaf = NULL;
1838         r_pvsviewleafnovis = false;
1839 }
1840
1841 void GL_Surf_Init(void)
1842 {
1843         int i;
1844         dlightdivtable[0] = 4194304;
1845         for (i = 1;i < 32768;i++)
1846                 dlightdivtable[i] = 4194304 / (i << 7);
1847
1848         Cvar_RegisterVariable(&r_ambient);
1849         Cvar_RegisterVariable(&r_vertexsurfaces);
1850         Cvar_RegisterVariable(&r_dlightmap);
1851         Cvar_RegisterVariable(&r_drawportals);
1852         Cvar_RegisterVariable(&r_testvis);
1853         Cvar_RegisterVariable(&r_floatbuildlightmap);
1854         Cvar_RegisterVariable(&r_detailtextures);
1855         Cvar_RegisterVariable(&r_surfaceworldnode);
1856
1857         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
1858 }
1859