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