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