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