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