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