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