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