added r_surfaceworldnode and r_cullsurface cvars (it is recommended that these both...
[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_CopyXYZ(const surfvertex_t *in, float *out, int numverts)
628 {
629         int i;
630         for (i = 0;i < numverts;i++, in++, out += 4)
631         {
632                 VectorCopy(in->v, out);
633                 out[3] = 1;
634         }
635 }
636
637 static void RSurf_CopyST(const surfvertex_t *in, float *out, int numverts)
638 {
639         int i;
640         for (i = 0;i < numverts;i++, in++, out += 2)
641         {
642                 out[0] = in->st[0];
643                 out[1] = in->st[1];
644         }
645 }
646
647 static void RSurf_CopyUV(const surfvertex_t *in, float *out, int numverts)
648 {
649         int i;
650         for (i = 0;i < numverts;i++, in++, out += 2)
651         {
652                 out[0] = in->uv[0];
653                 out[1] = in->uv[1];
654         }
655 }
656
657 static void RSurf_CopyAB(const surfvertex_t *in, float *out, int numverts)
658 {
659         int i;
660         for (i = 0;i < numverts;i++, in++, out += 2)
661         {
662                 out[0] = in->ab[0];
663                 out[1] = in->ab[1];
664         }
665 }
666
667 static void RSurf_AddLightmapToVertexColors(const surfvertex_t *in, float *c, int numverts, const qbyte *samples, int size3, const qbyte *styles)
668 {
669         int i;
670         float scale;
671         const qbyte *lm;
672         if (styles[0] != 255)
673         {
674                 for (i = 0;i < numverts;i++, in++, c += 4)
675                 {
676                         lm = samples + in->lightmapoffset;
677                         scale = d_lightstylevalue[styles[0]] * (1.0f / 32768.0f);
678                         VectorMA(c, scale, lm, c);
679                         if (styles[1] != 255)
680                         {
681                                 lm += size3;
682                                 scale = d_lightstylevalue[styles[1]] * (1.0f / 32768.0f);
683                                 VectorMA(c, scale, lm, c);
684                                 if (styles[2] != 255)
685                                 {
686                                         lm += size3;
687                                         scale = d_lightstylevalue[styles[2]] * (1.0f / 32768.0f);
688                                         VectorMA(c, scale, lm, c);
689                                         if (styles[3] != 255)
690                                         {
691                                                 lm += size3;
692                                                 scale = d_lightstylevalue[styles[3]] * (1.0f / 32768.0f);
693                                                 VectorMA(c, scale, lm, c);
694                                         }
695                                 }
696                         }
697                 }
698         }
699 }
700
701 static void RSurf_FogColors(const float *v, float *c, float colorscale, int numverts, const float *modelorg)
702 {
703         int i;
704         float diff[3], f;
705         if (fogenabled)
706         {
707                 for (i = 0;i < numverts;i++, v += 4, c += 4)
708                 {
709                         VectorSubtract(v, modelorg, diff);
710                         f = colorscale * (1 - exp(fogdensity/DotProduct(diff, diff)));
711                         VectorScale(c, f, c);
712                 }
713         }
714         else if (colorscale != 1)
715                 for (i = 0;i < numverts;i++, c += 4)
716                         VectorScale(c, colorscale, c);
717 }
718
719 static void RSurf_FoggedColors(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
720 {
721         int i;
722         float diff[3], f;
723         r *= colorscale;
724         g *= colorscale;
725         b *= colorscale;
726         if (fogenabled)
727         {
728                 for (i = 0;i < numverts;i++, v += 4, c += 4)
729                 {
730                         VectorSubtract(v, modelorg, diff);
731                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
732                         c[0] = r * f;
733                         c[1] = g * f;
734                         c[2] = b * f;
735                         c[3] = a;
736                 }
737         }
738         else
739         {
740                 for (i = 0;i < numverts;i++, c += 4)
741                 {
742                         c[0] = r;
743                         c[1] = g;
744                         c[2] = b;
745                         c[3] = a;
746                 }
747         }
748 }
749
750 static void RSurf_FogPassColors(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
751 {
752         int i;
753         float diff[3], f;
754         r *= colorscale;
755         g *= colorscale;
756         b *= colorscale;
757         for (i = 0;i < numverts;i++, v += 4, c += 4)
758         {
759                 VectorSubtract(v, modelorg, diff);
760                 f = exp(fogdensity/DotProduct(diff, diff));
761                 c[0] = r;
762                 c[1] = g;
763                 c[2] = b;
764                 c[3] = a * f;
765         }
766 }
767
768 static void RSurf_ScaleColors(float *c, float scale, int numverts)
769 {
770         int i;
771         if (scale != 1)
772                 for (i = 0;i < numverts;i++, c += 4)
773                         VectorScale(c, scale, c);
774 }
775
776 static int RSurf_LightSeparate(const matrix4x4_t *matrix, const int *dlightbits, int numverts, const float *vert, float *color)
777 {
778         float f;
779         const float *v;
780         float *c;
781         int i, l, lit = false;
782         rdlight_t *rd;
783         vec3_t lightorigin;
784         for (l = 0;l < r_numdlights;l++)
785         {
786                 if (dlightbits[l >> 5] & (1 << (l & 31)))
787                 {
788                         rd = &r_dlight[l];
789                         Matrix4x4_Transform(matrix, rd->origin, lightorigin);
790                         for (i = 0, v = vert, c = color;i < numverts;i++, v += 4, c += 4)
791                         {
792                                 f = VectorDistance2(v, lightorigin) + LIGHTOFFSET;
793                                 if (f < rd->cullradius2)
794                                 {
795                                         f = (1.0f / f) - rd->subtract;
796                                         VectorMA(c, f, rd->light, c);
797                                         lit = true;
798                                 }
799                         }
800                 }
801         }
802         return lit;
803 }
804
805 // note: this untransforms lights to do the checking,
806 // and takes surf->mesh->vertex data
807 static int RSurf_LightCheck(const matrix4x4_t *matrix, const int *dlightbits, surfmesh_t *mesh)
808 {
809         int i, l;
810         rdlight_t *rd;
811         vec3_t lightorigin;
812         surfvertex_t *sv;
813         for (l = 0;l < r_numdlights;l++)
814         {
815                 if (dlightbits[l >> 5] & (1 << (l & 31)))
816                 {
817                         rd = &r_dlight[l];
818                         Matrix4x4_Transform(matrix, rd->origin, lightorigin);
819                         for (i = 0, sv = mesh->vertex;i < mesh->numverts;i++, sv++)
820                                 if (VectorDistance2(sv->v, lightorigin) < rd->cullradius2)
821                                         return true;
822                 }
823         }
824         return false;
825 }
826
827 static void RSurfShader_Sky(const entity_render_t *ent, const msurface_t *firstsurf)
828 {
829         const msurface_t *surf;
830         surfmesh_t *mesh;
831         rmeshbufferinfo_t m;
832
833         // LordHavoc: HalfLife maps have freaky skypolys...
834         if (ent->model->ishlbsp)
835                 return;
836
837         if (skyrendernow)
838         {
839                 skyrendernow = false;
840                 if (skyrendermasked)
841                         R_Sky();
842         }
843
844         // draw depth-only polys
845         memset(&m, 0, sizeof(m));
846         if (skyrendermasked)
847         {
848                 m.blendfunc1 = GL_ZERO;
849                 m.blendfunc2 = GL_ONE;
850         }
851         else
852         {
853                 // fog sky
854                 m.blendfunc1 = GL_ONE;
855                 m.blendfunc2 = GL_ZERO;
856         }
857         m.depthwrite = true;
858         m.matrix = ent->matrix;
859         for (surf = firstsurf;surf;surf = surf->chain)
860         {
861                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
862                 {
863                         m.numtriangles = mesh->numtriangles;
864                         m.numverts = mesh->numverts;
865                         if (R_Mesh_Draw_GetBuffer(&m, false))
866                         {
867                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
868                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
869                                 if (skyrendermasked)
870                                         memset(m.color, 0, m.numverts * sizeof(float[4]));
871                                 else
872                                         R_FillColors(m.color, m.numverts, fogcolor[0] * m.colorscale, fogcolor[1] * m.colorscale, fogcolor[2] * m.colorscale, 1);
873                                 R_Mesh_Render();
874                         }
875                 }
876         }
877 }
878
879 static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
880 {
881         const entity_render_t *ent = calldata1;
882         msurface_t *surf = ent->model->surfaces + calldata2;
883         float f;
884         surfmesh_t *mesh;
885         rmeshbufferinfo_t m;
886         float alpha = ent->alpha * (surf->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value);
887         float modelorg[3];
888         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
889
890         memset(&m, 0, sizeof(m));
891         if (ent->effects & EF_ADDITIVE)
892         {
893                 m.blendfunc1 = GL_SRC_ALPHA;
894                 m.blendfunc2 = GL_ONE;
895         }
896         else if (surf->currenttexture->fogtexture != NULL || alpha < 1)
897         {
898                 m.blendfunc1 = GL_SRC_ALPHA;
899                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
900         }
901         else
902         {
903                 m.blendfunc1 = GL_ONE;
904                 m.blendfunc2 = GL_ZERO;
905         }
906         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
907         m.matrix = ent->matrix;
908         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
909         {
910                 m.numtriangles = mesh->numtriangles;
911                 m.numverts = mesh->numverts;
912                 if (R_Mesh_Draw_GetBuffer(&m, true))
913                 {
914                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
915                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
916                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
917                         f = surf->flags & SURF_DRAWFULLBRIGHT ? 1.0f : ((surf->flags & SURF_LIGHTMAP) ? 0 : 0.5f);
918                         R_FillColors(m.color, m.numverts, f, f, f, alpha);
919                         if (!(surf->flags & SURF_DRAWFULLBRIGHT || ent->effects & EF_FULLBRIGHT))
920                         {
921                                 if (surf->dlightframe == r_framecount)
922                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
923                                 if (surf->flags & SURF_LIGHTMAP)
924                                         RSurf_AddLightmapToVertexColors(mesh->vertex, m.color, m.numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
925                         }
926                         RSurf_FogColors(m.vertex, m.color, m.colorscale, m.numverts, modelorg);
927                         R_Mesh_Render();
928                 }
929         }
930
931         if (fogenabled)
932         {
933                 memset(&m, 0, sizeof(m));
934                 m.blendfunc1 = GL_SRC_ALPHA;
935                 m.blendfunc2 = GL_ONE;
936                 m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
937                 m.matrix = ent->matrix;
938                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
939                 {
940                         m.numtriangles = mesh->numtriangles;
941                         m.numverts = mesh->numverts;
942                         if (R_Mesh_Draw_GetBuffer(&m, false))
943                         {
944                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
945                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
946                                 if (m.tex[0])
947                                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
948                                 RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], alpha, m.colorscale, m.numverts, modelorg);
949                                 R_Mesh_Render();
950                         }
951                 }
952         }
953 }
954
955 static void RSurfShader_Water(const entity_render_t *ent, const msurface_t *firstsurf)
956 {
957         const msurface_t *surf;
958         vec3_t center;
959         for (surf = firstsurf;surf;surf = surf->chain)
960         {
961                 if ((r_wateralpha.value < 1 && !(surf->flags & SURF_DRAWNOALPHA)) || ent->effects & EF_ADDITIVE || surf->currenttexture->fogtexture)
962                 {
963                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
964                         R_MeshQueue_AddTransparent(center, RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
965                 }
966                 else
967                         R_MeshQueue_Add(RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
968         }
969 }
970
971 static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf)
972 {
973         float base;
974         surfmesh_t *mesh;
975         rmeshbufferinfo_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.tex[0] = R_GetTexture(surf->currenttexture->texture);
995         base = ent->effects & EF_FULLBRIGHT ? 2.0f : r_ambient.value * (1.0f / 64.0f);
996         m.matrix = ent->matrix;
997         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
998         {
999                 m.numtriangles = mesh->numtriangles;
1000                 m.numverts = mesh->numverts;
1001                 if (R_Mesh_Draw_GetBuffer(&m, true))
1002                 {
1003                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1004                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1005                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1006                         R_FillColors(m.color, m.numverts, base, base, base, ent->alpha);
1007                         if (!(ent->effects & EF_FULLBRIGHT))
1008                         {
1009                                 if (surf->dlightframe == r_framecount)
1010                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
1011                                 if (surf->flags & SURF_LIGHTMAP)
1012                                         RSurf_AddLightmapToVertexColors(mesh->vertex, m.color, m.numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
1013                         }
1014                         RSurf_FogColors(m.vertex, m.color, m.colorscale, m.numverts, modelorg);
1015                         R_Mesh_Render();
1016                 }
1017         }
1018 }
1019
1020 static void RSurfShader_Wall_Pass_BaseFullbright(const entity_render_t *ent, const msurface_t *surf)
1021 {
1022         surfmesh_t *mesh;
1023         rmeshbufferinfo_t m;
1024         float modelorg[3];
1025         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1026         memset(&m, 0, sizeof(m));
1027         if (ent->effects & EF_ADDITIVE)
1028         {
1029                 m.blendfunc1 = GL_SRC_ALPHA;
1030                 m.blendfunc2 = GL_ONE;
1031         }
1032         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
1033         {
1034                 m.blendfunc1 = GL_SRC_ALPHA;
1035                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1036         }
1037         else
1038         {
1039                 m.blendfunc1 = GL_ONE;
1040                 m.blendfunc2 = GL_ZERO;
1041         }
1042         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1043         m.matrix = ent->matrix;
1044         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1045         {
1046                 m.numtriangles = mesh->numtriangles;
1047                 m.numverts = mesh->numverts;
1048                 if (R_Mesh_Draw_GetBuffer(&m, false))
1049                 {
1050                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1051                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1052                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1053                         RSurf_FoggedColors(m.vertex, m.color, 1, 1, 1, ent->alpha, m.colorscale, m.numverts, modelorg);
1054                         R_Mesh_Render();
1055                 }
1056         }
1057 }
1058
1059 static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
1060 {
1061         surfmesh_t *mesh;
1062         rmeshbufferinfo_t m;
1063         float modelorg[3];
1064         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1065         memset(&m, 0, sizeof(m));
1066         m.blendfunc1 = GL_SRC_ALPHA;
1067         m.blendfunc2 = GL_ONE;
1068         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1069         m.matrix = ent->matrix;
1070         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1071         {
1072                 m.numtriangles = mesh->numtriangles;
1073                 m.numverts = mesh->numverts;
1074                 if (R_Mesh_Draw_GetBuffer(&m, false))
1075                 {
1076                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1077                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1078                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1079                         RSurf_FoggedColors(m.vertex, m.color, 1, 1, 1, ent->alpha, m.colorscale, m.numverts, modelorg);
1080                         R_Mesh_Render();
1081                 }
1082         }
1083 }
1084
1085 static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1086 {
1087         surfmesh_t *mesh;
1088         rmeshbufferinfo_t m;
1089         float modelorg[3];
1090         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1091         memset(&m, 0, sizeof(m));
1092         m.blendfunc1 = GL_SRC_ALPHA;
1093         m.blendfunc2 = GL_ONE;
1094         m.matrix = ent->matrix;
1095         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1096         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1097         {
1098                 m.numtriangles = mesh->numtriangles;
1099                 m.numverts = mesh->numverts;
1100                 if (R_Mesh_Draw_GetBuffer(&m, false))
1101                 {
1102                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1103                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1104                         if (m.tex[0])
1105                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1106                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, m.colorscale, m.numverts, modelorg);
1107                         R_Mesh_Render();
1108                 }
1109         }
1110 }
1111
1112 static void RSurfShader_OpaqueWall_Pass_TripleTexCombine(const entity_render_t *ent, const msurface_t *surf)
1113 {
1114         surfmesh_t *mesh;
1115         rmeshbufferinfo_t m;
1116         float cl;
1117         memset(&m, 0, sizeof(m));
1118         m.blendfunc1 = GL_ONE;
1119         m.blendfunc2 = GL_ZERO;
1120         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1121         m.texrgbscale[0] = 1.0f;
1122         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1123         m.texrgbscale[1] = 4.0f;
1124         m.tex[2] = R_GetTexture(surf->currenttexture->detailtexture);
1125         m.texrgbscale[2] = 2.0f;
1126         m.matrix = ent->matrix;
1127         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1128         {
1129                 m.numtriangles = mesh->numtriangles;
1130                 m.numverts = mesh->numverts;
1131                 if (R_Mesh_Draw_GetBuffer(&m, false))
1132                 {
1133                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1134                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1135                         cl = (float) (1 << lightscalebit) * m.colorscale;
1136                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1137                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1138                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1139                         RSurf_CopyAB(mesh->vertex, m.texcoords[2], m.numverts);
1140                         R_Mesh_Render();
1141                 }
1142         }
1143 }
1144
1145 static void RSurfShader_OpaqueWall_Pass_BaseMTex(const entity_render_t *ent, const msurface_t *surf)
1146 {
1147         surfmesh_t *mesh;
1148         rmeshbufferinfo_t m;
1149         float cl;
1150         memset(&m, 0, sizeof(m));
1151         m.blendfunc1 = GL_ONE;
1152         m.blendfunc2 = GL_ZERO;
1153         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1154         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1155         m.matrix = ent->matrix;
1156         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1157         {
1158                 m.numtriangles = mesh->numtriangles;
1159                 m.numverts = mesh->numverts;
1160                 if (R_Mesh_Draw_GetBuffer(&m, true))
1161                 {
1162                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1163                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1164                         cl = (float) (1 << lightscalebit) * m.colorscale;
1165                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1166                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1167                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1168                         R_Mesh_Render();
1169                 }
1170         }
1171 }
1172
1173 static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent, const msurface_t *surf)
1174 {
1175         surfmesh_t *mesh;
1176         rmeshbufferinfo_t m;
1177         float cl;
1178         memset(&m, 0, sizeof(m));
1179         m.blendfunc1 = GL_ONE;
1180         m.blendfunc2 = GL_ZERO;
1181         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1182         m.matrix = ent->matrix;
1183         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1184         {
1185                 m.numtriangles = mesh->numtriangles;
1186                 m.numverts = mesh->numverts;
1187                 if (R_Mesh_Draw_GetBuffer(&m, false))
1188                 {
1189                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1190                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1191                         cl = m.colorscale;
1192                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1193                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1194                         R_Mesh_Render();
1195                 }
1196         }
1197 }
1198
1199 static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent, const msurface_t *surf)
1200 {
1201         surfmesh_t *mesh;
1202         rmeshbufferinfo_t m;
1203         float cl;
1204         memset(&m, 0, sizeof(m));
1205         m.blendfunc1 = GL_ZERO;
1206         m.blendfunc2 = GL_SRC_COLOR;
1207         m.tex[0] = R_GetTexture(surf->lightmaptexture);
1208         m.matrix = ent->matrix;
1209         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1210         {
1211                 m.numtriangles = mesh->numtriangles;
1212                 m.numverts = mesh->numverts;
1213                 if (R_Mesh_Draw_GetBuffer(&m, true))
1214                 {
1215                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1216                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1217                         cl = (float) (1 << lightscalebit) * m.colorscale;
1218                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1219                         RSurf_CopyUV(mesh->vertex, m.texcoords[0], m.numverts);
1220                         R_Mesh_Render();
1221                 }
1222         }
1223 }
1224
1225 static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const msurface_t *surf)
1226 {
1227         surfmesh_t *mesh;
1228         rmeshbufferinfo_t m;
1229
1230         if (surf->dlightframe != r_framecount)
1231                 return;
1232         if (ent->effects & EF_FULLBRIGHT)
1233                 return;
1234
1235         memset(&m, 0, sizeof(m));
1236         m.blendfunc1 = GL_SRC_ALPHA;
1237         m.blendfunc2 = GL_ONE;
1238         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1239         m.matrix = ent->matrix;
1240         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1241         {
1242                 if (RSurf_LightCheck(&ent->inversematrix, surf->dlightbits, mesh))
1243                 {
1244                         m.numtriangles = mesh->numtriangles;
1245                         m.numverts = mesh->numverts;
1246                         if (R_Mesh_Draw_GetBuffer(&m, true))
1247                         {
1248                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1249                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1250                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1251                                 R_FillColors(m.color, m.numverts, 0, 0, 0, 1);
1252                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
1253                                 RSurf_ScaleColors(m.color, m.colorscale, m.numverts);
1254                                 R_Mesh_Render();
1255                         }
1256                 }
1257         }
1258 }
1259
1260 static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1261 {
1262         surfmesh_t *mesh;
1263         rmeshbufferinfo_t m;
1264         float modelorg[3];
1265         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1266         memset(&m, 0, sizeof(m));
1267         m.blendfunc1 = GL_SRC_ALPHA;
1268         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1269         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1270         m.matrix = ent->matrix;
1271         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1272         {
1273                 m.numtriangles = mesh->numtriangles;
1274                 m.numverts = mesh->numverts;
1275                 if (R_Mesh_Draw_GetBuffer(&m, false))
1276                 {
1277                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1278                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1279                         if (m.tex[0])
1280                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1281                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], 1, m.colorscale, m.numverts, modelorg);
1282                         R_Mesh_Render();
1283                 }
1284         }
1285 }
1286
1287 static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, const msurface_t *surf)
1288 {
1289         surfmesh_t *mesh;
1290         rmeshbufferinfo_t m;
1291         memset(&m, 0, sizeof(m));
1292         m.blendfunc1 = GL_DST_COLOR;
1293         m.blendfunc2 = GL_SRC_COLOR;
1294         m.tex[0] = R_GetTexture(surf->currenttexture->detailtexture);
1295         m.matrix = ent->matrix;
1296         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1297         {
1298                 m.numtriangles = mesh->numtriangles;
1299                 m.numverts = mesh->numverts;
1300                 if (R_Mesh_Draw_GetBuffer(&m, false))
1301                 {
1302                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1303                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1304                         R_FillColors(m.color, m.numverts, 1, 1, 1, 1);
1305                         RSurf_CopyAB(mesh->vertex, m.texcoords[0], m.numverts);
1306                         R_Mesh_Render();
1307                 }
1308         }
1309 }
1310
1311 static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
1312 {
1313         surfmesh_t *mesh;
1314         rmeshbufferinfo_t m;
1315         memset(&m, 0, sizeof(m));
1316         m.blendfunc1 = GL_SRC_ALPHA;
1317         m.blendfunc2 = GL_ONE;
1318         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1319         m.matrix = ent->matrix;
1320         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1321         {
1322                 m.numtriangles = mesh->numtriangles;
1323                 m.numverts = mesh->numverts;
1324                 if (R_Mesh_Draw_GetBuffer(&m, false))
1325                 {
1326                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1327                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1328                         R_FillColors(m.color, m.numverts, m.colorscale, m.colorscale, m.colorscale, 1);
1329                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1330                         R_Mesh_Render();
1331                 }
1332         }
1333 }
1334
1335 static void RSurfShader_Wall_Fullbright_Callback(const void *calldata1, int calldata2)
1336 {
1337         const entity_render_t *ent = calldata1;
1338         const msurface_t *surf = ent->model->surfaces + calldata2;
1339         RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1340         if (surf->currenttexture->glowtexture)
1341                 RSurfShader_Wall_Pass_Glow(ent, surf);
1342         if (fogenabled)
1343                 RSurfShader_Wall_Pass_Fog(ent, surf);
1344 }
1345
1346 static void RSurfShader_Wall_Fullbright(const entity_render_t *ent, const msurface_t *firstsurf)
1347 {
1348         const msurface_t *surf;
1349         vec3_t center;
1350         if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
1351         {
1352                 for (surf = firstsurf;surf;surf = surf->chain)
1353                 {
1354                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1355                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1356                 }
1357         }
1358         else
1359         {
1360                 for (surf = firstsurf;surf;surf = surf->chain)
1361                 {
1362                         if (surf->currenttexture->fogtexture != NULL)
1363                         {
1364                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1365                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1366                         }
1367                         else
1368                                 RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1369                 }
1370                 for (surf = firstsurf;surf;surf = surf->chain)
1371                         if (surf->currenttexture->glowtexture)
1372                                 if (surf->currenttexture->fogtexture == NULL)
1373                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1374                 if (fogenabled)
1375                         for (surf = firstsurf;surf;surf = surf->chain)
1376                                 if (surf->currenttexture->fogtexture == NULL)
1377                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1378         }
1379 }
1380
1381 static void RSurfShader_Wall_Vertex_Callback(const void *calldata1, int calldata2)
1382 {
1383         const entity_render_t *ent = calldata1;
1384         const msurface_t *surf = ent->model->surfaces + calldata2;
1385         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1386         if (surf->currenttexture->glowtexture)
1387                 RSurfShader_Wall_Pass_Glow(ent, surf);
1388         if (fogenabled)
1389                 RSurfShader_Wall_Pass_Fog(ent, surf);
1390 }
1391
1392 static void RSurfShader_Wall_Vertex(const entity_render_t *ent, const msurface_t *firstsurf)
1393 {
1394         const msurface_t *surf;
1395         vec3_t center;
1396         if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
1397         {
1398                 for (surf = firstsurf;surf;surf = surf->chain)
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         }
1404         else
1405         {
1406                 for (surf = firstsurf;surf;surf = surf->chain)
1407                 {
1408                         if (surf->currenttexture->fogtexture != NULL)
1409                         {
1410                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1411                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1412                         }
1413                         else
1414                                 RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1415                 }
1416                 for (surf = firstsurf;surf;surf = surf->chain)
1417                         if (surf->currenttexture->glowtexture)
1418                                 if (surf->currenttexture->fogtexture == NULL)
1419                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1420                 if (fogenabled)
1421                         for (surf = firstsurf;surf;surf = surf->chain)
1422                                 if (surf->currenttexture->fogtexture == NULL)
1423                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1424         }
1425 }
1426
1427 static void RSurfShader_Wall_Lightmap(const entity_render_t *ent, const msurface_t *firstsurf)
1428 {
1429         const msurface_t *surf;
1430         vec3_t center;
1431         if (ent->alpha < 1 || ent->effects & EF_ADDITIVE)
1432         {
1433                 for (surf = firstsurf;surf;surf = surf->chain)
1434                 {
1435                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1436                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1437                 }
1438         }
1439         else if (r_vertexsurfaces.integer || ent->alpha < 1 || ent->effects & EF_ADDITIVE)
1440         {
1441                 for (surf = firstsurf;surf;surf = surf->chain)
1442                 {
1443                         if (surf->currenttexture->fogtexture != NULL)
1444                         {
1445                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1446                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1447                         }
1448                         else
1449                                 RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1450                 }
1451                 for (surf = firstsurf;surf;surf = surf->chain)
1452                         if (surf->currenttexture->glowtexture)
1453                                 if (surf->currenttexture->fogtexture == NULL)
1454                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1455                 if (fogenabled)
1456                         for (surf = firstsurf;surf;surf = surf->chain)
1457                                 if (surf->currenttexture->fogtexture == NULL)
1458                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1459         }
1460         else
1461         {
1462                 if (r_textureunits.integer >= 2)
1463                 {
1464                         if (r_textureunits.integer >= 3 && gl_combine.integer && r_detailtextures.integer)
1465                         {
1466                                 for (surf = firstsurf;surf;surf = surf->chain)
1467                                 {
1468                                         if (surf->currenttexture->fogtexture != NULL)
1469                                         {
1470                                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1471                                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1472                                         }
1473                                         else
1474                                                 RSurfShader_OpaqueWall_Pass_TripleTexCombine(ent, surf);
1475                                 }
1476                         }
1477                         else
1478                         {
1479                                 for (surf = firstsurf;surf;surf = surf->chain)
1480                                 {
1481                                         if (surf->currenttexture->fogtexture != NULL)
1482                                         {
1483                                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1484                                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1485                                         }
1486                                         else
1487                                                 RSurfShader_OpaqueWall_Pass_BaseMTex(ent, surf);
1488                                 }
1489                                 if (r_detailtextures.integer)
1490                                         for (surf = firstsurf;surf;surf = surf->chain)
1491                                                 if (surf->currenttexture->fogtexture == NULL)
1492                                                         RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1493                         }
1494                 }
1495                 else
1496                 {
1497                         for (surf = firstsurf;surf;surf = surf->chain)
1498                         {
1499                                 if (surf->currenttexture->fogtexture != NULL)
1500                                 {
1501                                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1502                                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1503                                 }
1504                                 else
1505                                         RSurfShader_OpaqueWall_Pass_BaseTexture(ent, surf);
1506                         }
1507                         for (surf = firstsurf;surf;surf = surf->chain)
1508                                 if (surf->currenttexture->fogtexture == NULL)
1509                                         RSurfShader_OpaqueWall_Pass_BaseLightmap(ent, surf);
1510                         if (r_detailtextures.integer)
1511                                 for (surf = firstsurf;surf;surf = surf->chain)
1512                                         if (surf->currenttexture->fogtexture == NULL)
1513                                                 RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1514                 }
1515                 if (!r_dlightmap.integer)
1516                         for (surf = firstsurf;surf;surf = surf->chain)
1517                                 if (surf->dlightframe == r_framecount)
1518                                         if (surf->currenttexture->fogtexture == NULL)
1519                                                 RSurfShader_OpaqueWall_Pass_Light(ent, surf);
1520                 for (surf = firstsurf;surf;surf = surf->chain)
1521                         if (surf->currenttexture->glowtexture)
1522                                 if (surf->currenttexture->fogtexture == NULL)
1523                                         RSurfShader_OpaqueWall_Pass_Glow(ent, surf);
1524                 if (fogenabled)
1525                         for (surf = firstsurf;surf;surf = surf->chain)
1526                                 if (surf->currenttexture->fogtexture == NULL)
1527                                         RSurfShader_OpaqueWall_Pass_Fog(ent, surf);
1528         }
1529 }
1530
1531 Cshader_t Cshader_wall_vertex = {{NULL, RSurfShader_Wall_Vertex}, NULL};
1532 Cshader_t Cshader_wall_lightmap = {{NULL, RSurfShader_Wall_Lightmap}, NULL};
1533 Cshader_t Cshader_wall_fullbright = {{NULL, RSurfShader_Wall_Fullbright}, NULL};
1534 Cshader_t Cshader_water = {{NULL, RSurfShader_Water}, NULL};
1535 Cshader_t Cshader_sky = {{RSurfShader_Sky, NULL}, NULL};
1536
1537 int Cshader_count = 5;
1538 Cshader_t *Cshaders[5] =
1539 {
1540         &Cshader_wall_vertex,
1541         &Cshader_wall_lightmap,
1542         &Cshader_wall_fullbright,
1543         &Cshader_water,
1544         &Cshader_sky
1545 };
1546
1547 void R_DrawSurfaces(entity_render_t *ent, int sky, int normal)
1548 {
1549         int i, alttextures, texframe, framecount;
1550         texture_t *t;
1551         model_t *model;
1552         msurface_t *surf;
1553         vec3_t modelorg;
1554         Cshader_t *shader;
1555
1556         if (!ent->model)
1557                 return;
1558
1559         for (i = 0;i < Cshader_count;i++)
1560                 Cshaders[i]->chain = NULL;
1561
1562         model = ent->model;
1563         alttextures = ent->frame != 0;
1564         texframe = (int)(cl.time * 5.0f);
1565
1566         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1567         for (i = 0;i < model->nummodelsurfaces;i++)
1568         {
1569                 surf = model->modelsortedsurfaces[i];
1570                 if (surf->visframe == r_framecount)
1571                 {
1572                         // mark any backface surfaces as not visible
1573                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1574                         {
1575                                 if (!(surf->flags & SURF_PLANEBACK))
1576                                         surf->visframe = -1;
1577                         }
1578                         else
1579                         {
1580                                 if (surf->flags & SURF_PLANEBACK)
1581                                         surf->visframe = -1;
1582                         }
1583                         if (surf->visframe == r_framecount)
1584                         {
1585                                 if (r_cullsurface.integer && R_CullBox (surf->poly_mins, surf->poly_maxs))
1586                                         surf->visframe = -1;
1587                                 else
1588                                 {
1589                                         c_faces++;
1590                                         t = surf->texinfo->texture;
1591                                         if (t->animated)
1592                                         {
1593                                                 framecount = t->anim_total[alttextures];
1594                                                 if (framecount >= 2)
1595                                                         surf->currenttexture = t->anim_frames[alttextures][texframe % framecount];
1596                                                 else
1597                                                         surf->currenttexture = t->anim_frames[alttextures][0];
1598                                         }
1599                                         else
1600                                                 surf->currenttexture = t;
1601                                         surf->chain = surf->shader->chain;
1602                                         surf->shader->chain = surf;
1603                                 }
1604                         }
1605                 }
1606         }
1607
1608         if (sky)
1609         {
1610                 for (i = 0;i < Cshader_count;i++)
1611                 {
1612                         shader = Cshaders[i];
1613                         if (shader->chain && shader->shaderfunc[SHADERSTAGE_SKY])
1614                                 shader->shaderfunc[SHADERSTAGE_SKY](ent, shader->chain);
1615                 }
1616         }
1617
1618         if (normal)
1619         {
1620                 if (r_dynamic.integer)
1621                         R_MarkLights(ent);
1622
1623                 if (!r_vertexsurfaces.integer)
1624                 {
1625                         for (i = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;i < ent->model->nummodelsurfaces;i++, surf++)
1626                         {
1627                                 if (surf->visframe == r_framecount && surf->lightmaptexture != NULL)
1628                                 {
1629                                         if (surf->cached_dlight
1630                                         || surf->cached_ambient != r_ambient.value
1631                                         || surf->cached_lightscalebit != lightscalebit)
1632                                                 R_BuildLightMap(ent, surf, false); // base lighting changed
1633                                         else if (r_dynamic.integer)
1634                                         {
1635                                                 if  (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0]
1636                                                 || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
1637                                                 || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
1638                                                 || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
1639                                                         R_BuildLightMap(ent, surf, false); // base lighting changed
1640                                                 else if (surf->dlightframe == r_framecount && r_dlightmap.integer)
1641                                                         R_BuildLightMap(ent, surf, true); // only dlights
1642                                         }
1643                                 }
1644                         }
1645                 }
1646
1647                 for (i = 0;i < Cshader_count;i++)
1648                 {
1649                         shader = Cshaders[i];
1650                         if (shader->chain && shader->shaderfunc[SHADERSTAGE_NORMAL])
1651                                 shader->shaderfunc[SHADERSTAGE_NORMAL](ent, shader->chain);
1652                 }
1653         }
1654 }
1655
1656 /*
1657 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
1658 {
1659         int i;
1660         float *v;
1661         rmeshbufferinfo_t m;
1662         const entity_render_t *ent = calldata1;
1663         const mportal_t *portal = ent->model->portals + calldata2;
1664         memset(&m, 0, sizeof(m));
1665         m.blendfunc1 = GL_SRC_ALPHA;
1666         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1667         m.numverts = portal->numpoints;
1668         m.numtriangles = portal->numpoints - 2;
1669         m.matrix = ent->matrix;
1670         if (R_Mesh_Draw_GetBuffer(&m, false))
1671         {
1672                 for (i = 0;i < m.numtriangles;i++)
1673                 {
1674                         m.index[i * 3 + 0] = 0;
1675                         m.index[i * 3 + 1] = i + 1;
1676                         m.index[i * 3 + 2] = i + 2;
1677                 }
1678                 i = portal - ent->model->portals;
1679                 R_FillColors(m.color, m.numverts,
1680                         ((i & 0x0007) >> 0) * (1.0f / 7.0f) * m.colorscale,
1681                         ((i & 0x0038) >> 3) * (1.0f / 7.0f) * m.colorscale,
1682                         ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * m.colorscale,
1683                         0.125f);
1684                 if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1685                 {
1686                         for (i = portal->numpoints - 1, v = m.vertex;i >= 0;i--, v += 4)
1687                                 VectorCopy(portal->points[i].position, v);
1688                 }
1689                 else
1690                         for (i = 0, v = m.vertex;i < portal->numpoints;i++, v += 4)
1691                                 VectorCopy(portal->points[i].position, v);
1692                 R_Mesh_Render();
1693         }
1694 }
1695
1696 static void R_DrawPortals(entity_render_t *ent)
1697 {
1698         int i;
1699         mportal_t *portal, *endportal;
1700         float temp[3], center[3], f;
1701
1702         if (r_drawportals.integer < 1)
1703                 return;
1704
1705         for (portal = ent->model->portals, endportal = portal + ent->model->numportals;portal < endportal;portal++)
1706         {
1707                 if (portal->here->visframe == r_framecount || portal->past->visframe == r_framecount)
1708                 {
1709                         VectorClear(temp);
1710                         for (i = 0;i < portal->numpoints;i++)
1711                                 VectorAdd(temp, portal->points[i].position, temp);
1712                         f = ixtable[portal->numpoints];
1713                         VectorScale(temp, f, temp);
1714                         Matrix4x4_Transform(&ent->matrix, temp, center);
1715                         R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, ent, portal - ent->model->portals);
1716                 }
1717         }
1718 }
1719 */
1720
1721 void R_DrawBrushModel(entity_render_t *ent, int sky, int normal)
1722 {
1723         int i;
1724         msurface_t *surf;
1725         model_t *model;
1726         vec3_t modelorg;
1727
1728         // because bmodels can be reused, we have to decide which things to render
1729         // from scratch every time
1730         model = ent->model;
1731         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1732         for (i = 0;i < model->nummodelsurfaces;i++)
1733         {
1734                 surf = model->surfaces + model->firstmodelsurface + i;
1735                 surf->visframe = r_framecount;
1736                 surf->pvsframe = -1;
1737                 surf->worldnodeframe = -1;
1738                 surf->lightframe = -1;
1739                 surf->dlightframe = -1;
1740         }
1741         R_DrawSurfaces(ent, sky, normal);
1742 }
1743
1744 void R_SurfaceWorldNode (void)
1745 {
1746         msurface_t *surf;
1747         for (surf = r_pvsfirstsurface;surf;surf = surf->pvschain)
1748                 surf->visframe = r_framecount;
1749 }
1750
1751 /*
1752 static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
1753 {
1754         int portalstack, i;
1755         mportal_t *p, *pstack[8192];
1756         msurface_t *surf, **mark, **endmark;
1757         mleaf_t *leaf;
1758         // LordHavoc: portal-passage worldnode with PVS;
1759         // follows portals leading outward from viewleaf, does not venture
1760         // offscreen or into leafs that are not visible, faster than Quake's
1761         // RecursiveWorldNode
1762         leaf = viewleaf;
1763         leaf->worldnodeframe = r_framecount;
1764         portalstack = 0;
1765 loc0:
1766         c_leafs++;
1767         if (leaf->nummarksurfaces)
1768         {
1769                 for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1770                 {
1771                         surf = *mark++;
1772                         // make sure surfaces are only processed once
1773                         if (surf->worldnodeframe != r_framecount)
1774                         {
1775                                 surf->worldnodeframe = r_framecount;
1776                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1777                                 {
1778                                         if (surf->flags & SURF_PLANEBACK)
1779                                                 surf->visframe = r_framecount;
1780                                 }
1781                                 else
1782                                 {
1783                                         if (!(surf->flags & SURF_PLANEBACK))
1784                                                 surf->visframe = r_framecount;
1785                                 }
1786                         }
1787                 }
1788         }
1789         // follow portals into other leafs
1790         for (p = leaf->portals;p;p = p->next)
1791         {
1792                 leaf = p->past;
1793                 if (leaf->worldnodeframe != r_framecount)
1794                 {
1795                         leaf->worldnodeframe = r_framecount;
1796                         // FIXME: R_NotCulledBox is absolute, should be done relative
1797                         if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
1798                         {
1799                                 p->visframe = r_framecount;
1800                                 pstack[portalstack++] = p;
1801                                 goto loc0;
1802 loc1:
1803                                 p = pstack[--portalstack];
1804                         }
1805                 }
1806         }
1807         if (portalstack)
1808                 goto loc1;
1809 }
1810 */
1811
1812 static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
1813 {
1814         int c, leafstackpos;
1815         mleaf_t *leaf, *leafstack[8192];
1816         mportal_t *p;
1817         msurface_t **mark;
1818         vec3_t modelorg;
1819         // LordHavoc: portal-passage worldnode with PVS;
1820         // follows portals leading outward from viewleaf, does not venture
1821         // offscreen or into leafs that are not visible, faster than Quake's
1822         // RecursiveWorldNode
1823         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1824         viewleaf->worldnodeframe = r_framecount;
1825         leafstack[0] = viewleaf;
1826         leafstackpos = 1;
1827         while (leafstackpos)
1828         {
1829                 c_leafs++;
1830                 leaf = leafstack[--leafstackpos];
1831                 // only useful for drawing portals
1832                 //leaf->visframe = r_framecount;
1833                 // draw any surfaces bounding this leaf
1834                 if (leaf->nummarksurfaces)
1835                         for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1836                                 (*mark++)->visframe = r_framecount;
1837                 // follow portals into other leafs
1838                 for (p = leaf->portals;p;p = p->next)
1839                 {
1840                         leaf = p->past;
1841                         if (leaf->worldnodeframe != r_framecount)
1842                         {
1843                                 leaf->worldnodeframe = r_framecount;
1844                                 // FIXME: R_NotCulledBox is absolute, should be done relative
1845                                 if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
1846                                         leafstack[leafstackpos++] = leaf;
1847                         }
1848                 }
1849         }
1850         //if (r_drawportals.integer)
1851         //      R_DrawPortals(ent);
1852 }
1853
1854
1855 void R_PVSUpdate (mleaf_t *viewleaf)
1856 {
1857         int i, j, l, c, bits;
1858         mleaf_t *leaf;
1859         qbyte *vis;
1860         msurface_t **mark, *surf;
1861
1862         if (r_pvsviewleaf == viewleaf && r_pvsviewleafnovis == r_novis.integer)
1863                 return;
1864
1865         r_pvsframecount++;
1866         r_pvsviewleaf = viewleaf;
1867         r_pvsviewleafnovis = r_novis.integer;
1868
1869         if (viewleaf)
1870         {
1871                 vis = Mod_LeafPVS (viewleaf, cl.worldmodel);
1872                 for (j = 0;j < cl.worldmodel->numleafs;j += 8)
1873                 {
1874                         bits = *vis++;
1875                         if (bits)
1876                         {
1877                                 l = cl.worldmodel->numleafs - j;
1878                                 if (l > 8)
1879                                         l = 8;
1880                                 for (i = 0;i < l;i++)
1881                                 {
1882                                         if (bits & (1 << i))
1883                                         {
1884                                                 leaf = &cl.worldmodel->leafs[j + i + 1];
1885                                                 leaf->pvsframe = r_pvsframecount;
1886                                                 // mark surfaces bounding this leaf as visible
1887                                                 for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
1888                                                         (*mark++)->pvsframe = r_pvsframecount;
1889                                         }
1890                                 }
1891                         }
1892                 }
1893                 // build pvs surfacechain
1894                 r_pvsfirstsurface = NULL;
1895                 mark = &r_pvsfirstsurface;
1896                 for (c = cl.worldmodel->nummodelsurfaces, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;c;c--, surf++)
1897                 {
1898                         if (surf->pvsframe == r_pvsframecount)
1899                         {
1900                                 *mark = surf;
1901                                 mark = &surf->pvschain;
1902                         }
1903                 }
1904                 *mark = NULL;
1905         }
1906 }
1907
1908 /*
1909 =============
1910 R_DrawWorld
1911 =============
1912 */
1913 void R_DrawWorld (entity_render_t *ent)
1914 {
1915         mleaf_t *viewleaf;
1916         viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
1917         R_PVSUpdate(viewleaf);
1918         if (!viewleaf)
1919                 return;
1920         if (r_surfaceworldnode.integer || viewleaf->contents == CONTENTS_SOLID)
1921                 R_SurfaceWorldNode ();
1922         else
1923                 R_PortalWorldNode (ent, viewleaf);
1924         R_DrawSurfaces(ent, true, true);
1925 }
1926
1927 /*
1928 =================
1929 R_DrawBrushModel
1930 =================
1931 */
1932 void R_DrawBrushModelSky (entity_render_t *ent)
1933 {
1934         R_DrawBrushModel(ent, true, false);
1935 }
1936
1937 void R_DrawBrushModelNormal (entity_render_t *ent)
1938 {
1939         c_bmodels++;
1940         R_DrawBrushModel(ent, false, true);
1941 }
1942
1943 static void gl_surf_start(void)
1944 {
1945 }
1946
1947 static void gl_surf_shutdown(void)
1948 {
1949 }
1950
1951 static void gl_surf_newmap(void)
1952 {
1953         // reset pvs visibility variables so it will update on first frame
1954         r_pvsframecount = 1;
1955         r_pvsviewleaf = NULL;
1956         r_pvsviewleafnovis = false;
1957         r_pvsfirstsurface = NULL;
1958 }
1959
1960 void GL_Surf_Init(void)
1961 {
1962         int i;
1963         dlightdivtable[0] = 4194304;
1964         for (i = 1;i < 32768;i++)
1965                 dlightdivtable[i] = 4194304 / (i << 7);
1966
1967         Cvar_RegisterVariable(&r_ambient);
1968         Cvar_RegisterVariable(&r_vertexsurfaces);
1969         Cvar_RegisterVariable(&r_dlightmap);
1970         //Cvar_RegisterVariable(&r_drawportals);
1971         Cvar_RegisterVariable(&r_testvis);
1972         Cvar_RegisterVariable(&r_floatbuildlightmap);
1973         Cvar_RegisterVariable(&r_detailtextures);
1974         Cvar_RegisterVariable(&r_surfaceworldnode);
1975         Cvar_RegisterVariable(&r_cullsurface);
1976
1977         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
1978 }
1979