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