]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rsurf.c
added include unistd.h and fcntl.h on non-win32
[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 int             lightmap_textures;
25
26 #define BLOCK_WIDTH             256
27 #define BLOCK_HEIGHT    256
28 // LordHavoc: increased lightmap limit from 64 to 1024
29 #define MAX_LIGHTMAPS   1024
30 #define LIGHTMAPSIZE    (BLOCK_WIDTH*BLOCK_HEIGHT*4)
31
32 int                     active_lightmaps;
33
34 short allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
35
36 byte *lightmaps[MAX_LIGHTMAPS];
37 short lightmapupdate[MAX_LIGHTMAPS][2];
38
39 signed int blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; // LordHavoc: *3 for colored lighting
40
41 int lightmapalign, lightmapalignmask; // LordHavoc: NVIDIA's broken subimage fix, see BuildLightmaps for notes
42 cvar_t gl_lightmapalign = {0, "gl_lightmapalign", "4"};
43 cvar_t gl_lightmaprgba = {0, "gl_lightmaprgba", "1"};
44 cvar_t gl_nosubimagefragments = {0, "gl_nosubimagefragments", "0"};
45 cvar_t gl_nosubimage = {0, "gl_nosubimage", "0"};
46 cvar_t r_ambient = {0, "r_ambient", "0"};
47 cvar_t gl_vertex = {0, "gl_vertex", "0"};
48 cvar_t r_dlightmap = {CVAR_SAVE, "r_dlightmap", "1"};
49 cvar_t r_drawportals = {0, "r_drawportals", "0"};
50 cvar_t r_testvis = {0, "r_testvis", "0"};
51 cvar_t r_solidworldnode = {0, "r_solidworldnode", "3"};
52 cvar_t r_pvsworldnode = {0, "r_pvsworldnode", "1"};
53
54 qboolean lightmaprgba, nosubimagefragments, nosubimage;
55 int lightmapbytes;
56
57 int wateralpha;
58
59 void gl_surf_start(void)
60 {
61 }
62
63 void gl_surf_shutdown(void)
64 {
65 }
66
67 void gl_surf_newmap(void)
68 {
69 }
70
71 void GL_Surf_Init(void)
72 {
73         int i;
74         for (i = 0;i < MAX_LIGHTMAPS;i++)
75                 lightmaps[i] = NULL;
76         Cvar_RegisterVariable(&gl_lightmapalign);
77         Cvar_RegisterVariable(&gl_lightmaprgba);
78         Cvar_RegisterVariable(&gl_nosubimagefragments);
79         Cvar_RegisterVariable(&gl_nosubimage);
80         Cvar_RegisterVariable(&r_ambient);
81         Cvar_RegisterVariable(&gl_vertex);
82         Cvar_RegisterVariable(&r_dlightmap);
83         Cvar_RegisterVariable(&r_drawportals);
84         Cvar_RegisterVariable(&r_testvis);
85         Cvar_RegisterVariable(&r_solidworldnode);
86         Cvar_RegisterVariable(&r_pvsworldnode);
87
88         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
89 }
90
91 int dlightdivtable[32768];
92
93 /*
94         R_AddDynamicLights
95 */
96 int R_AddDynamicLights (msurface_t *surf)
97 {
98         int         sdtable[18], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, red, green, blue, lit, dist2, impacts, impactt;
99         unsigned int *bl;
100         float       dist;
101         vec3_t      impact, local;
102
103         // LordHavoc: use 64bit integer...  shame it's not very standardized...
104 #if _MSC_VER || __BORLANDC__
105         __int64     k;
106 #else
107         long long   k;
108 #endif
109
110         lit = false;
111
112         if (!dlightdivtable[1])
113         {
114                 dlightdivtable[0] = 4194304;
115                 for (s = 1; s < 32768; s++)
116                         dlightdivtable[s] = 4194304 / (s << 7);
117         }
118
119         smax = (surf->extents[0] >> 4) + 1;
120         tmax = (surf->extents[1] >> 4) + 1;
121
122         for (lnum = 0; lnum < MAX_DLIGHTS; lnum++)
123         {
124                 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
125                         continue;                                       // not lit by this light
126
127                 VectorSubtract (cl_dlights[lnum].origin, currententity->render.origin, local);
128                 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
129
130                 // for comparisons to minimum acceptable light
131                 maxdist = (int) ((cl_dlights[lnum].radius * cl_dlights[lnum].radius));
132
133                 // clamp radius to avoid exceeding 32768 entry division table
134                 if (maxdist > 4194304)
135                         maxdist = 4194304;
136
137                 dist2 = dist * dist;
138                 if (dist2 >= maxdist)
139                         continue;
140
141                 impact[0] = cl_dlights[lnum].origin[0] - surf->plane->normal[0] * dist;
142                 impact[1] = cl_dlights[lnum].origin[1] - surf->plane->normal[1] * dist;
143                 impact[2] = cl_dlights[lnum].origin[2] - surf->plane->normal[2] * dist;
144
145                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
146                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
147
148                 s = bound(0, impacts, smax * 16) - impacts;
149                 t = bound(0, impactt, tmax * 16) - impactt;
150                 i = s * s + t * t + dist2;
151                 if (i > maxdist)
152                         continue;
153
154                 // reduce calculations
155                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
156                         sdtable[s] = i * i + dist2 + LIGHTOFFSET;
157
158                 maxdist3 = maxdist - (int) (dist * dist);
159
160                 // convert to 8.8 blocklights format and scale up by radius
161                 red = cl_dlights[lnum].color[0] * maxdist;
162                 green = cl_dlights[lnum].color[1] * maxdist;
163                 blue = cl_dlights[lnum].color[2] * maxdist;
164                 bl = blocklights;
165
166                 i = impactt;
167                 for (t = 0; t < tmax; t++, i -= 16)
168                 {
169                         td = i * i;
170                         // make sure some part of it is visible on this line
171                         if (td < maxdist3)
172                         {
173                                 maxdist2 = maxdist - td;
174                                 for (s = 0; s < smax; s++)
175                                 {
176                                         if (sdtable[s] < maxdist2)
177                                         {
178                                                 k = dlightdivtable[(sdtable[s] + td) >> 7];
179                                                 bl[0] += (red   * k) >> 9;
180                                                 bl[1] += (green * k) >> 9;
181                                                 bl[2] += (blue  * k) >> 9;
182                                                 lit = true;
183                                         }
184                                         bl += 3;
185                                 }
186                         }
187                         else // skip line
188                                 bl += smax * 3;
189                 }
190         }
191         return lit;
192 }
193
194
195 void R_ConvertLightmap (int *in, byte *out, int width, int height, int stride)
196 {
197         int i, j;
198         stride -= (width*lightmapbytes);
199         if (lighthalf)
200         {
201                 // LordHavoc: I shift down by 8 unlike GLQuake's 7,
202                 // the image is brightened as a processing pass
203                 if (lightmaprgba)
204                 {
205                         for (i = 0;i < height;i++, out += stride)
206                         {
207                                 for (j = 0;j < width;j++, in += 3, out += 4)
208                                 {
209                                         out[0] = min(in[0] >> 8, 255);
210                                         out[1] = min(in[1] >> 8, 255);
211                                         out[2] = min(in[2] >> 8, 255);
212                                         out[3] = 255;
213                                 }
214                         }
215                 }
216                 else
217                 {
218                         for (i = 0;i < height;i++, out += stride)
219                         {
220                                 for (j = 0;j < width;j++, in += 3, out += 3)
221                                 {
222                                         out[0] = min(in[0] >> 8, 255);
223                                         out[1] = min(in[1] >> 8, 255);
224                                         out[2] = min(in[2] >> 8, 255);
225                                 }
226                         }
227                 }
228         }
229         else
230         {
231                 if (lightmaprgba)
232                 {
233                         for (i = 0;i < height;i++, out += stride)
234                         {
235                                 for (j = 0;j < width;j++, in += 3, out += 4)
236                                 {
237                                         out[0] = min(in[0] >> 7, 255);
238                                         out[1] = min(in[1] >> 7, 255);
239                                         out[2] = min(in[2] >> 7, 255);
240                                         out[3] = 255;
241                                 }
242                         }
243                 }
244                 else
245                 {
246                         for (i = 0;i < height;i++, out += stride)
247                         {
248                                 for (j = 0;j < width;j++, in += 3, out += 3)
249                                 {
250                                         out[0] = min(in[0] >> 7, 255);
251                                         out[1] = min(in[1] >> 7, 255);
252                                         out[2] = min(in[2] >> 7, 255);
253                                 }
254                         }
255                 }
256         }
257 }
258
259 /*
260 ===============
261 R_BuildLightMap
262
263 Combine and scale multiple lightmaps into the 8.8 format in blocklights
264 ===============
265 */
266 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
267 {
268         int             smax, tmax;
269         int             i, j, size, size3;
270         byte    *lightmap;
271         int             scale;
272         int             maps;
273         int             *bl;
274
275         surf->cached_dlight = 0;
276         surf->cached_lighthalf = lighthalf;
277         surf->cached_ambient = r_ambient.value;
278
279         smax = (surf->extents[0]>>4)+1;
280         tmax = (surf->extents[1]>>4)+1;
281         size = smax*tmax;
282         size3 = size*3;
283         lightmap = surf->samples;
284
285 // set to full bright if no light data
286         if ((currententity && (currententity->render.effects & EF_FULLBRIGHT)) || !cl.worldmodel->lightdata)
287         {
288                 bl = blocklights;
289                 for (i=0 ; i<size ; i++)
290                 {
291                         *bl++ = 255*256;
292                         *bl++ = 255*256;
293                         *bl++ = 255*256;
294                 }
295         }
296         else
297         {
298 // clear to no light
299                 j = r_ambient.value * 512.0f; // would be 256.0f logically, but using 512.0f to match winquake style
300                 if (j)
301                 {
302                         bl = blocklights;
303                         for (i = 0;i < size3;i++)
304                                 *bl++ = j;
305                 }
306                 else
307                         memset(&blocklights[0], 0, size*3*sizeof(int));
308
309 // add all the lightmaps
310                 if (lightmap)
311                 {
312                         for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
313                         {
314                                 scale = d_lightstylevalue[surf->styles[maps]];
315                                 surf->cached_light[maps] = scale;       // 8.8 fraction
316                                 bl = blocklights;
317                                 for (i = 0;i < size3;i++)
318                                         *bl++ += *lightmap++ * scale;
319                         }
320                 }
321                 if (r_dlightmap.value && surf->dlightframe == r_framecount)
322                         if ((surf->cached_dlight = R_AddDynamicLights(surf)))
323                                 c_light_polys++;
324         }
325         R_ConvertLightmap(blocklights, dest, smax, tmax, stride);
326 }
327
328 byte templight[BLOCK_WIDTH*BLOCK_HEIGHT*4];
329
330 void R_UpdateLightmap(msurface_t *s, int lnum)
331 {
332         int smax, tmax;
333         // upload the new lightmap texture fragment
334         if(r_upload.value)
335                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + lnum);
336         if (nosubimage || nosubimagefragments)
337         {
338                 if (lightmapupdate[lnum][0] > s->light_t)
339                         lightmapupdate[lnum][0] = s->light_t;
340                 if (lightmapupdate[lnum][1] < (s->light_t + ((s->extents[1]>>4)+1)))
341                         lightmapupdate[lnum][1] = (s->light_t + ((s->extents[1]>>4)+1));
342                 if (lightmaprgba)
343                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 4, BLOCK_WIDTH * 4);
344                 else
345                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 3, BLOCK_WIDTH * 3);
346         }
347         else
348         {
349                 smax = ((s->extents[0]>>4)+lightmapalign) & lightmapalignmask;
350                 tmax = (s->extents[1]>>4)+1;
351                 if (lightmaprgba)
352                 {
353                         R_BuildLightMap (s, templight, smax * 4);
354                         if(r_upload.value)
355                                 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
356                 }
357                 else
358                 {
359                         R_BuildLightMap (s, templight, smax * 3);
360                         if(r_upload.value)
361                                 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
362                 }
363         }
364 }
365
366
367 /*
368 ===============
369 R_TextureAnimation
370
371 Returns the proper texture for a given time and base texture
372 ===============
373 */
374 texture_t *R_TextureAnimation (texture_t *base)
375 {
376 //      texture_t *original;
377 //      int             relative;
378 //      int             count;
379
380         if (currententity->render.frame)
381         {
382                 if (base->alternate_anims)
383                         base = base->alternate_anims;
384         }
385         
386         if (!base->anim_total)
387                 return base;
388
389         return base->anim_frames[(int)(cl.time*5) % base->anim_total];
390
391         /*
392         original = base;
393
394         relative = (int)(cl.time*5) % base->anim_total;
395
396         count = 0;      
397         while (base->anim_min > relative || base->anim_max <= relative)
398         {
399                 base = base->anim_next;
400                 if (!base)
401                 {
402                         Con_Printf("R_TextureAnimation: broken cycle");
403                         return original;
404                 }
405                 if (++count > 100)
406                 {
407                         Con_Printf("R_TextureAnimation: infinite cycle");
408                         return original;
409                 }
410         }
411
412         return base;
413         */
414 }
415
416
417 /*
418 =============================================================
419
420         BRUSH MODELS
421
422 =============================================================
423 */
424
425
426 float   turbsin[256] =
427 {
428         #include "gl_warp_sin.h"
429 };
430 #define TURBSCALE (256.0 / (2 * M_PI))
431
432
433 void UploadLightmaps(void)
434 {
435         int i;
436         if (nosubimage || nosubimagefragments)
437         {
438                 for (i = 0;i < MAX_LIGHTMAPS;i++)
439                 {
440                         if (lightmapupdate[i][0] < lightmapupdate[i][1])
441                         {
442                                 if(r_upload.value)
443                                 {
444                                         glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
445                                         if (nosubimage)
446                                         {
447                                                 if (lightmaprgba)
448                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
449                                                 else
450                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
451                                         }
452                                         else
453                                         {
454                                                 if (lightmaprgba)
455                                                         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 4 * lightmapupdate[i][0]));
456                                                 else
457                                                         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 3 * lightmapupdate[i][0]));
458                                         }
459                                 }
460                         }
461                         lightmapupdate[i][0] = BLOCK_HEIGHT;
462                         lightmapupdate[i][1] = 0;
463                 }
464         }
465 }
466
467 float   wvert[1024*6]; // used by the following functions
468
469 void RSurf_DrawSky(msurface_t *s, int transform)
470 {
471         glpoly_t *p;
472         int i;
473         float *v;
474
475         // LordHavoc: HalfLife maps have freaky skypolys...
476         if (hlbsp)
477                 return;
478
479         for (p=s->polys ; p ; p=p->next)
480         {
481                 if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS)
482                 {
483                         skypoly[currentskypoly].firstvert = currentskyvert;
484                         skypoly[currentskypoly++].verts = p->numverts;
485                         if (transform)
486                         {
487                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
488                                 {
489                                         softwaretransform(v, skyvert[currentskyvert].v);
490                                         currentskyvert++;
491                                 }
492                         }
493                         else
494                         {
495                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
496                                 {
497                                         VectorCopy(v, skyvert[currentskyvert].v);
498                                         currentskyvert++;
499                                 }
500                         }
501                 }
502         }
503 }
504
505 int RSurf_Light(int *dlightbits, glpoly_t *polys)
506 {
507         float           cr, cg, cb, radius, radius2, f, *v, *wv;
508         int                     i, a, b, lit = false;
509         unsigned int c, d;
510         dlight_t        *light;
511         vec_t           *lightorigin;
512         glpoly_t        *p;
513         for (a = 0;a < 8;a++)
514         {
515                 if ((c = dlightbits[a]))
516                 {
517                         for (b = 0, d = 1;c;b++, d <<= 1)
518                         {
519                                 if (c & d)
520                                 {
521                                         c -= d;
522                                         light = &cl_dlights[a * 32 + b];
523                                         lightorigin = light->origin;
524                                         cr = light->color[0];
525                                         cg = light->color[1];
526                                         cb = light->color[2];
527                                         radius = light->radius*light->radius;
528                                         radius2 = radius * 256.0f;
529                                         wv = wvert;
530                                         for (p = polys;p;p = p->next)
531                                         {
532                                                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
533                                                 {
534                                                         f = VectorDistance2(wv, lightorigin);
535                                                         if (f < radius)
536                                                         {
537                                                                 f = radius2 / (f + LIGHTOFFSET);
538                                                                 wv[3] += cr * f;
539                                                                 wv[4] += cg * f;
540                                                                 wv[5] += cb * f;
541                                                                 lit = true;
542                                                         }
543                                                         wv += 6;
544                                                 }
545                                         }
546                                 }
547                         }
548                 }
549         }
550         return lit;
551 }
552
553 void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
554 {
555         int             i;
556         float   os = turbsin[(int)(cl.time * TURBSCALE) & 255], ot = turbsin[(int)(cl.time * TURBSCALE + 96.0) & 255];
557         glpoly_t *p;
558         float   *v;
559         // FIXME: make fog texture if water texture is transparent?
560
561         if (s->dlightframe != r_framecount)
562         {
563                 vec3_t temp;
564                 // LordHavoc: fast path for no vertex lighting cases
565                 if (transform)
566                 {
567                         if (r_waterripple.value)
568                         {
569                                 for (p=s->polys ; p ; p=p->next)
570                                 {
571                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
572                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
573                                         {
574                                                 softwaretransform(v, temp);
575                                                 transpolyvert(temp[0], temp[1], temp[2] + r_waterripple.value * turbsin[(int)((temp[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((temp[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f), (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
576                                         }
577                                         transpolyend();
578                                 }
579                         }
580                         else
581                         {
582                                 for (p=s->polys ; p ; p=p->next)
583                                 {
584                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
585                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
586                                         {
587                                                 softwaretransform(v, temp);
588                                                 transpolyvert(temp[0], temp[1], temp[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
589                                         }
590                                         transpolyend();
591                                 }
592                         }
593                 }
594                 else
595                 {
596                         if (r_waterripple.value)
597                         {
598                                 for (p=s->polys ; p ; p=p->next)
599                                 {
600                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
601                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
602                                                 transpolyvert(v[0], v[1], v[2] + r_waterripple.value * turbsin[(int)((v[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((v[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f), (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
603                                         transpolyend();
604                                 }
605                         }
606                         else
607                         {
608                                 for (p=s->polys ; p ; p=p->next)
609                                 {
610                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
611                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
612                                                 transpolyvert(v[0], v[1], v[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
613                                         transpolyend();
614                                 }
615                         }
616                 }
617         }
618         else
619         {
620                 float *wv;
621                 wv = wvert;
622                 for (p = s->polys;p;p = p->next)
623                 {
624                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
625                         {
626                                 if (transform)
627                                         softwaretransform(v, wv);
628                                 else
629                                         VectorCopy(v, wv);
630                                 if (r_waterripple.value)
631                                         wv[2] += r_waterripple.value * turbsin[(int)((wv[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((wv[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f);
632                                 wv[3] = wv[4] = wv[5] = 128.0f;
633                                 wv += 6;
634                         }
635                 }
636                 if (s->dlightframe == r_framecount)
637                         RSurf_Light(s->dlightbits, s->polys);
638                 wv = wvert;
639                 for (p=s->polys ; p ; p=p->next)
640                 {
641                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
642                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
643                                 transpolyvert(wv[0], wv[1], wv[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), wv[3], wv[4], wv[5], alpha);
644                         transpolyend();
645                 }
646         }
647 }
648
649 void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform)
650 {
651         int             i, lit = false, polys = 0, verts = 0;
652         float   *v;
653         glpoly_t *p;
654         wallpoly_t *wp;
655         wallvert_t *out;
656         wallvertcolor_t *outcolor;
657         // check for lightmap modification
658         if (s->cached_dlight
659          || (r_dynamic.value && r_dlightmap.value && s->dlightframe == r_framecount)
660          || r_ambient.value != s->cached_ambient
661          || lighthalf != s->cached_lighthalf
662          || (r_dynamic.value
663          && ((s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0])
664          || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1])
665          || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2])
666          || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))))
667                 R_UpdateLightmap(s, s->lightmaptexturenum);
668         if (s->dlightframe != r_framecount || r_dlightmap.value)
669         {
670                 // LordHavoc: fast path version for no vertex lighting cases
671                 wp = &wallpoly[currentwallpoly];
672                 out = &wallvert[currentwallvert];
673                 for (p = s->polys;p;p = p->next)
674                 {
675                         if ((currentwallpoly >= MAX_WALLPOLYS) || (currentwallvert+p->numverts > MAX_WALLVERTS))
676                                 return;
677                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
678                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
679                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
680                         wp->firstvert = currentwallvert;
681                         wp->numverts = p->numverts;
682                         wp->lit = false;
683                         wp++;
684                         currentwallpoly++;
685                         currentwallvert += p->numverts;
686                         v = p->verts[0];
687                         if (transform)
688                         {
689                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
690                                 {
691                                         softwaretransform(v, out->vert);
692                                         out->vert[3] = v[3];
693                                         out->vert[4] = v[4];
694                                         out->vert[5] = v[5];
695                                         out->vert[6] = v[6];
696                                 }
697                         }
698                         else
699                         {
700                                 /*
701                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
702                                 {
703                                         VectorCopy(v, out->vert);
704                                         out->vert[3] = v[3];
705                                         out->vert[4] = v[4];
706                                         out->vert[5] = v[5];
707                                         out->vert[6] = v[6];
708                                 }
709                                 */
710                                 memcpy(out, v, sizeof(vec_t) * VERTEXSIZE * p->numverts);
711                                 out += p->numverts;
712                         }
713                 }
714         }
715         else
716         {
717                 float *wv;
718                 wv = wvert;
719                 for (p = s->polys;p;p = p->next)
720                 {
721                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
722                         {
723                                 if (transform)
724                                         softwaretransform(v, wv);
725                                 else
726                                         VectorCopy(v, wv);
727                                 wv[3] = wv[4] = wv[5] = 0.0f;
728                                 wv += 6;
729                         }
730                         verts += p->numverts;
731                         polys++;
732                 }
733                 if ((currentwallpoly + polys > MAX_WALLPOLYS) || (currentwallvert+verts > MAX_WALLVERTS))
734                         return;
735                 if ((!r_dlightmap.value) && s->dlightframe == r_framecount)
736                         lit = RSurf_Light(s->dlightbits, s->polys);
737                 wv = wvert;
738                 wp = &wallpoly[currentwallpoly];
739                 out = &wallvert[currentwallvert];
740                 outcolor = &wallvertcolor[currentwallvert];
741                 currentwallpoly += polys;
742                 for (p = s->polys;p;p = p->next)
743                 {
744                         v = p->verts[0];
745                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
746                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
747                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
748                         wp->firstvert = currentwallvert;
749                         wp->numverts = p->numverts;
750                         wp->lit = lit;
751                         wp++;
752                         currentwallvert += p->numverts;
753                         for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++, outcolor++)
754                         {
755                                 if (lit)
756                                 {
757                                         if (lighthalf)
758                                         {
759                                                 outcolor->r = (byte) (bound(0, (int) wv[3] >> 1, 255));
760                                                 outcolor->g = (byte) (bound(0, (int) wv[4] >> 1, 255));
761                                                 outcolor->b = (byte) (bound(0, (int) wv[5] >> 1, 255));
762                                                 outcolor->a = 255;
763                                         }
764                                         else
765                                         {
766                                                 outcolor->r = (byte) (bound(0, (int) wv[3], 255));
767                                                 outcolor->g = (byte) (bound(0, (int) wv[4], 255));
768                                                 outcolor->b = (byte) (bound(0, (int) wv[5], 255));
769                                                 outcolor->a = 255;
770                                         }
771                                 }
772                                 out->vert[0] = wv[0];
773                                 out->vert[1] = wv[1];
774                                 out->vert[2] = wv[2];
775                                 out->vert[3] = v[3];
776                                 out->vert[4] = v[4];
777                                 out->vert[5] = v[5];
778                                 out->vert[6] = v[6];
779                         }
780                 }
781         }
782 }
783
784 // LordHavoc: transparent brush models
785 void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel)
786 {
787         int i, alpha, size3;
788         float *v, *wv, scale;
789         glpoly_t *p;
790         byte *lm;
791         alpha = (int) (modelalpha * 255.0f);
792         size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
793         wv = wvert;
794         for (p = s->polys;p;p = p->next)
795         {
796                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
797                 {
798                         if (transform)
799                                 softwaretransform(v, wv);
800                         else
801                                 VectorCopy(v, wv);
802                         wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f;
803                         if (s->styles[0] != 255)
804                         {
805                                 lm = (byte *)((long) s->samples + (int) v[7]);
806                                 scale = d_lightstylevalue[s->styles[0]] * (1.0f / 128.0f);wv[3] += lm[size3*0+0] * scale;wv[4] += lm[size3*0+1] * scale;wv[5] += lm[size3*0+2] * scale;
807                                 if (s->styles[1] != 255)
808                                 {
809                                         scale = d_lightstylevalue[s->styles[1]] * (1.0f / 128.0f);wv[3] += lm[size3*1+0] * scale;wv[4] += lm[size3*1+1] * scale;wv[5] += lm[size3*1+2] * scale;
810                                         if (s->styles[2] != 255)
811                                         {
812                                                 scale = d_lightstylevalue[s->styles[2]] * (1.0f / 128.0f);wv[3] += lm[size3*2+0] * scale;wv[4] += lm[size3*2+1] * scale;wv[5] += lm[size3*2+2] * scale;
813                                                 if (s->styles[3] != 255)
814                                                 {
815                                                         scale = d_lightstylevalue[s->styles[3]] * (1.0f / 128.0f);wv[3] += lm[size3*3+0] * scale;wv[4] += lm[size3*3+1] * scale;wv[5] += lm[size3*3+2] * scale;
816                                                 }
817                                         }
818                                 }
819                         }
820                         wv += 6;
821                 }
822         }
823         if (s->dlightframe == r_framecount)
824                 RSurf_Light(s->dlightbits, s->polys);
825         wv = wvert;
826         if (isbmodel && (currententity->render.colormod[0] != 1 || currententity->render.colormod[1] != 1 || currententity->render.colormod[2] != 1))
827         {
828                 for (p = s->polys;p;p = p->next)
829                 {
830                         v = p->verts[0];
831                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
832                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
833                                 transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->render.colormod[0], wv[4] * currententity->render.colormod[1], wv[5] * currententity->render.colormod[2], alpha);
834                         transpolyend();
835                 }
836         }
837         else
838         {
839                 for (p = s->polys;p;p = p->next)
840                 {
841                         v = p->verts[0];
842                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
843                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
844                                 transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha);
845                         transpolyend();
846                 }
847         }
848 }
849
850 void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model);
851
852 float bmverts[256*3];
853
854 int vertexworld;
855
856 /*
857 void RBrushModelSurf_DoVisible(msurface_t *surf)
858 {
859 //      float *v, *bmv, *endbmv;
860 //      glpoly_t *p;
861 //      for (p = surf->polys;p;p = p->next)
862 //      {
863 //              for (v = p->verts[0], bmv = bmpoints, endbmv = bmv + p->numverts * 3;bmv < endbmv;v += VERTEXSIZE, bmv += 3)
864 //                      softwaretransform(v, bmv);
865 //              if (R_Clip_Polygon(bmpoints, p->numverts, sizeof(float) * 3, surf->flags & SURF_CLIPSOLID))
866                         surf->visframe = r_framecount;
867 //      }
868 }
869 */
870
871 void RBrushModelSurf_Callback(void *data, void *data2)
872 {
873         entity_t *ent = data2;
874         msurface_t *surf = data;
875         texture_t *t;
876
877         /*
878         // FIXME: implement better dupe prevention in AddPolygon callback code
879         if (ent->render.model->firstmodelsurface != 0)
880         {
881                 // it's not an instanced model, so we already rely on there being only one of it (usually a valid assumption, but QC can break this)
882                 if (surf->visframe == r_framecount)
883                         return;
884         }
885         */
886         surf->visframe = r_framecount;
887
888         c_faces++;
889
890         currententity = ent;
891         modelalpha = ent->render.alpha;
892
893         softwaretransformforbrushentity (ent);
894
895         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
896         {
897                 // sky and liquid don't need sorting (skypoly/transpoly)
898                 if (surf->flags & SURF_DRAWSKY)
899                         RSurf_DrawSky(surf, true);
900                 else
901                         RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), true, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
902         }
903         else
904         {
905                 t = R_TextureAnimation(surf->texinfo->texture);
906                 if (surf->texinfo->texture->transparent || vertexworld || ent->render.alpha != 1 || ent->render.model->firstmodelsurface == 0 || (ent->render.effects & EF_FULLBRIGHT) || ent->render.colormod[0] != 1 || ent->render.colormod[2] != 1 || ent->render.colormod[2] != 1)
907                         RSurf_DrawWallVertex(surf, t, true, true);
908                 else
909                         RSurf_DrawWall(surf, t, true);
910         }
911 }
912
913 /*
914 =================
915 R_DrawBrushModel
916 =================
917 */
918 void R_DrawBrushModel (entity_t *e)
919 {
920         int                     i, j, vertexlit;
921         vec3_t          mins, maxs;
922         msurface_t      *s;
923         model_t         *clmodel;
924         int                     rotated;
925         vec3_t          org;
926         glpoly_t        *p;
927
928         currententity = e;
929
930         clmodel = e->render.model;
931
932         if (e->render.angles[0] || e->render.angles[1] || e->render.angles[2])
933         {
934                 rotated = true;
935                 for (i=0 ; i<3 ; i++)
936                 {
937                         mins[i] = e->render.origin[i] - clmodel->radius;
938                         maxs[i] = e->render.origin[i] + clmodel->radius;
939                 }
940         }
941         else
942         {
943                 rotated = false;
944                 VectorAdd (e->render.origin, clmodel->mins, mins);
945                 VectorAdd (e->render.origin, clmodel->maxs, maxs);
946         }
947
948         if (R_CullBox (mins, maxs))
949                 return;
950
951         c_bmodels++;
952
953         VectorSubtract (r_origin, e->render.origin, modelorg);
954         if (rotated)
955         {
956                 vec3_t  temp;
957                 vec3_t  forward, right, up;
958
959                 VectorCopy (modelorg, temp);
960                 AngleVectors (e->render.angles, forward, right, up);
961                 modelorg[0] = DotProduct (temp, forward);
962                 modelorg[1] = -DotProduct (temp, right);
963                 modelorg[2] = DotProduct (temp, up);
964         }
965
966         softwaretransformforbrushentity (e);
967
968         for (i = 0, s = &clmodel->surfaces[clmodel->firstmodelsurface];i < clmodel->nummodelsurfaces;i++, s++)
969         {
970                 s->visframe = -1;
971                 if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
972                         s->visframe = r_framecount;
973         }
974
975 // calculate dynamic lighting for bmodel if it's not an instanced model
976         for (i = 0;i < MAX_DLIGHTS;i++)
977         {
978                 if (!cl_dlights[i].radius)
979                         continue;
980
981                 VectorSubtract(cl_dlights[i].origin, currententity->render.origin, org);
982                 R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel);
983         }
984         vertexlit = modelalpha != 1 || clmodel->firstmodelsurface == 0 || (currententity->render.effects & EF_FULLBRIGHT) || currententity->render.colormod[0] != 1 || currententity->render.colormod[2] != 1 || currententity->render.colormod[2] != 1;
985
986         // draw texture
987         for (i = 0, s = &clmodel->surfaces[clmodel->firstmodelsurface];i < clmodel->nummodelsurfaces;i++, s++)
988         {
989                 if (s->visframe == r_framecount)
990                 {
991 //                      R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent);
992                         if (r_ser.value)
993                         {
994                                 for (p = s->polys;p;p = p->next)
995                                 {
996                                         for (j = 0;j < p->numverts;j++)
997                                                 softwaretransform(&p->verts[j][0], bmverts + j * 3);
998                                         R_Clip_AddPolygon(bmverts, p->numverts, 3 * sizeof(float), (s->flags & SURF_CLIPSOLID) != 0 && modelalpha == 1, RBrushModelSurf_Callback, s, e, NULL);
999                                 }
1000                         }
1001                         else
1002                         {
1003                                 if (s->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1004                                 {
1005                                         // sky and liquid don't need sorting (skypoly/transpoly)
1006                                         if (s->flags & SURF_DRAWSKY)
1007                                                 RSurf_DrawSky(s, true);
1008                                         else
1009                                                 RSurf_DrawWater(s, R_TextureAnimation(s->texinfo->texture), true, s->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1010                                 }
1011                                 else
1012                                 {
1013                                         texture_t *t = R_TextureAnimation(s->texinfo->texture);
1014                                         if (vertexlit || s->texinfo->texture->transparent)
1015                                                 RSurf_DrawWallVertex(s, t, true, true);
1016                                         else
1017                                                 RSurf_DrawWall(s, t, true);
1018                                 }
1019                         }
1020                 }
1021         }
1022         UploadLightmaps();
1023 }
1024
1025 /*
1026 =============================================================
1027
1028         WORLD MODEL
1029
1030 =============================================================
1031 */
1032
1033 /*
1034 static byte *worldvis;
1035
1036 void R_MarkLeaves (void)
1037 {
1038         static float noviscache;
1039         if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
1040                 return;
1041
1042         r_oldviewleaf = r_viewleaf;
1043         noviscache = r_novis.value;
1044
1045         worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1046 }
1047 */
1048
1049 void RSurf_Callback(void *data, void *junk)
1050 {
1051         ((msurface_t *)data)->visframe = r_framecount;
1052 }
1053
1054 /*
1055 void RSurf_Callback(void *data, void *junk)
1056 {
1057         msurface_t *surf = data;
1058         texture_t *t;
1059
1060 //      if (surf->visframe == r_framecount)
1061 //              return;
1062
1063         surf->visframe = r_framecount;
1064
1065         c_faces++;
1066
1067         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1068         {
1069                 // sky and liquid don't need sorting (skypoly/transpoly)
1070                 if (surf->flags & SURF_DRAWSKY)
1071                         RSurf_DrawSky(surf, false);
1072                 else
1073                         RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1074         }
1075         else
1076         {
1077                 t = R_TextureAnimation(surf->texinfo->texture);
1078                 if (vertexworld)
1079                         RSurf_DrawWallVertex(surf, t, false, false);
1080                 else
1081                         RSurf_DrawWall(surf, t, false);
1082         }
1083 }
1084 */
1085
1086 /*
1087 mleaf_t *r_oldviewleaf;
1088 int r_markvisframecount = 0;
1089
1090 void R_MarkLeaves (void)
1091 {
1092         static float noviscache;
1093         int i, l, k, c;
1094         mleaf_t *leaf;
1095         msurface_t *surf, **mark, **endmark;
1096         model_t *model = cl.worldmodel;
1097 //      mportal_t *portal;
1098         glpoly_t *p;
1099         byte    *in;
1100         int             row;
1101
1102         // ignore testvis if the map just changed
1103         if (r_testvis.value && model->nodes->markvisframe == r_markvisframecount)
1104                 return;
1105
1106         if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
1107                 return;
1108
1109         r_oldviewleaf = r_viewleaf;
1110         noviscache = r_novis.value;
1111
1112         if ((in = r_viewleaf->compressed_vis))
1113         {
1114                 row = (model->numleafs+7)>>3;
1115
1116                 if (!r_testvis.value)
1117                         r_markvisframecount++;
1118
1119                 // LordHavoc: mark the root node as visible, it will terminate all other ascensions
1120                 model->nodes->markvisframe = r_markvisframecount;
1121
1122                 k = 0;
1123                 while (k < row)
1124                 {
1125                         c = *in++;
1126                         if (c)
1127                         {
1128                                 l = model->numleafs - (k << 3);
1129                                 if (l > 8)
1130                                         l = 8;
1131                                 for (i=0 ; i<l ; i++)
1132                                 {
1133                                         if (c & (1<<i))
1134                                         {
1135                                                 leaf = &model->leafs[(k << 3)+i+1];
1136                                                 node = (mnode_t *)leaf;
1137                                                 do
1138                                                 {
1139                                                         node->markvisframe = r_markvisframecount;
1140                                                         node = node->parent;
1141                                                 }
1142                                                 while (node->markvisframecount != r_markvisframecount);
1143                                         }
1144                                 }
1145                                 k++;
1146                         }
1147                         else
1148                                 k += *in++;
1149                 }
1150         }
1151         else
1152         {
1153                 // LordHavoc: no vis data, mark everything as visible
1154                 model->nodes->markvisframe = r_markvisframecount;
1155
1156                 for (i = 1;i < model->numleafs;i++)
1157                 {
1158                         node = (mnode_t *)&model->leafs[i];
1159                         do
1160                         {
1161                                 node->markvisframe = r_markvisframecount;
1162                                 node = node->parent;
1163                         }
1164                         while (node->markvisframecount != r_markvisframecount);
1165                 }
1166         }
1167 }
1168 */
1169
1170 void R_SolidWorldNode (void)
1171 {
1172         if ((int) r_solidworldnode.value == 3)
1173         {
1174                 int portalstack;
1175                 mportal_t *p, *pstack[8192];
1176                 msurface_t *surf, **mark, **endmark;
1177                 mleaf_t *leaf;
1178                 glpoly_t *poly;
1179                 tinyplane_t plane;
1180
1181                 leaf = r_viewleaf;
1182                 leaf->worldnodeframe = r_framecount;
1183                 portalstack = 0;
1184         loc0:
1185                 c_leafs++;
1186
1187                 leaf->visframe = r_framecount;
1188
1189                 if (leaf->nummarksurfaces)
1190                 {
1191                         mark = leaf->firstmarksurface;
1192                         endmark = mark + leaf->nummarksurfaces;
1193                         if (r_ser.value)
1194                         {
1195                                 do
1196                                 {
1197                                         surf = *mark++;
1198                                         // make sure surfaces are only processed once
1199                                         if (surf->worldnodeframe == r_framecount)
1200                                                 continue;
1201                                         surf->worldnodeframe = r_framecount;
1202                                         if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1203                                         {
1204                                                 if (surf->flags & SURF_PLANEBACK)
1205                                                 {
1206                                                         VectorNegate(surf->plane->normal, plane.normal);
1207                                                         plane.dist = -surf->plane->dist;
1208                                                         for (poly = surf->polys;poly;poly = poly->next)
1209                                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1210                                                 }
1211                                         }
1212                                         else
1213                                         {
1214                                                 if (!(surf->flags & SURF_PLANEBACK))
1215                                                         for (poly = surf->polys;poly;poly = poly->next)
1216                                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1217                                         }
1218                                 }
1219                                 while (mark < endmark);
1220                         }
1221                         else
1222                         {
1223                                 do
1224                                 {
1225                                         surf = *mark++;
1226                                         // make sure surfaces are only processed once
1227                                         if (surf->worldnodeframe == r_framecount)
1228                                                 continue;
1229                                         surf->worldnodeframe = r_framecount;
1230                                         if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1231                                         {
1232                                                 if (surf->flags & SURF_PLANEBACK)
1233                                                         surf->visframe = r_framecount;
1234                                         }
1235                                         else
1236                                         {
1237                                                 if (!(surf->flags & SURF_PLANEBACK))
1238                                                         surf->visframe = r_framecount;
1239                                         }
1240                                 }
1241                                 while (mark < endmark);
1242                         }
1243                 }
1244
1245                 // follow portals into other leafs
1246                 p = leaf->portals;
1247                 for (;p;p = p->next)
1248                 {
1249                         if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1250                         {
1251                                 leaf = p->past;
1252                                 if (leaf->worldnodeframe != r_framecount)
1253                                 {
1254                                         leaf->worldnodeframe = r_framecount;
1255                                         if (leaf->contents != CONTENTS_SOLID)
1256                                         {
1257                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1258                                                 {
1259                                                         pstack[portalstack++] = p;
1260                                                         goto loc0;
1261
1262         loc1:
1263                                                         p = pstack[--portalstack];
1264                                                 }
1265                                         }
1266                                 }
1267                         }
1268                 }
1269
1270                 if (portalstack)
1271                         goto loc1;
1272         }
1273         else if ((int) r_solidworldnode.value == 2)
1274         {
1275                 mnode_t *nodestack[8192], *node = cl.worldmodel->nodes;
1276                 int nodestackpos = 0;
1277                 glpoly_t *poly;
1278
1279 loc2:
1280                 if (R_NotCulledBox(node->mins, node->maxs))
1281                 {
1282                         if (r_ser.value)
1283                         {
1284                                 if (node->numsurfaces)
1285                                 {
1286                                         msurface_t *surf = cl.worldmodel->surfaces + node->firstsurface, *surfend = surf + node->numsurfaces;
1287                                         tinyplane_t plane;
1288                                         if (PlaneDiff (r_origin, node->plane) < 0)
1289                                         {
1290                                                 for (;surf < surfend;surf++)
1291                                                 {
1292                                                         if (surf->flags & SURF_PLANEBACK)
1293                                                         {
1294                                                                 VectorNegate(surf->plane->normal, plane.normal);
1295                                                                 plane.dist = -surf->plane->dist;
1296                                                                 for (poly = surf->polys;poly;poly = poly->next)
1297                                                                         R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, &plane);
1298                                                         }
1299                                                 }
1300                                         }
1301                                         else
1302                                         {
1303                                                 for (;surf < surfend;surf++)
1304                                                 {
1305                                                         if (!(surf->flags & SURF_PLANEBACK))
1306                                                                 for (poly = surf->polys;poly;poly = poly->next)
1307                                                                         R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1308                                                 }
1309                                         }
1310                                 }
1311                         }
1312                         else
1313                         {
1314                                 if (node->numsurfaces)
1315                                 {
1316                                         msurface_t *surf = cl.worldmodel->surfaces + node->firstsurface, *surfend = surf + node->numsurfaces;
1317                                         if (PlaneDiff (r_origin, node->plane) < 0)
1318                                         {
1319                                                 for (;surf < surfend;surf++)
1320                                                 {
1321                                                         if (surf->flags & SURF_PLANEBACK)
1322                                                                 surf->visframe = r_framecount;
1323                                                 }
1324                                         }
1325                                         else
1326                                         {
1327                                                 for (;surf < surfend;surf++)
1328                                                 {
1329                                                         if (!(surf->flags & SURF_PLANEBACK))
1330                                                                 surf->visframe = r_framecount;
1331                                                 }
1332                                         }
1333                                 }
1334                         }
1335
1336                         // recurse down the children
1337                         if (node->children[0]->contents >= 0)
1338                         {
1339                                 if (node->children[1]->contents >= 0)
1340                                 {
1341                                         if (nodestackpos < 8192)
1342                                                 nodestack[nodestackpos++] = node->children[1];
1343                                         node = node->children[0];
1344                                         goto loc2;
1345                                 }
1346                                 else
1347                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1348                                 node = node->children[0];
1349                                 goto loc2;
1350                         }
1351                         else
1352                         {
1353                                 ((mleaf_t *)node->children[0])->visframe = r_framecount;
1354                                 if (node->children[1]->contents >= 0)
1355                                 {
1356                                         node = node->children[1];
1357                                         goto loc2;
1358                                 }
1359                                 else if (nodestackpos > 0)
1360                                 {
1361                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1362                                         node = nodestack[--nodestackpos];
1363                                         goto loc2;
1364                                 }
1365                         }
1366                 }
1367                 else if (nodestackpos > 0)
1368                 {
1369                         node = nodestack[--nodestackpos];
1370                         goto loc2;
1371                 }
1372         }
1373         else if ((int) r_solidworldnode.value == 1 && r_ser.value)
1374         {
1375                 glpoly_t *poly;
1376                 msurface_t *surf, *endsurf;
1377                 tinyplane_t plane;
1378
1379                 surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
1380                 endsurf = surf + cl.worldmodel->nummodelsurfaces;
1381                 for (;surf < endsurf;surf++)
1382                 {
1383                         if (PlaneDiff(r_origin, surf->plane) < 0)
1384                         {
1385                                 if (surf->flags & SURF_PLANEBACK)
1386                                 {
1387                                         VectorNegate(surf->plane->normal, plane.normal);
1388                                         plane.dist = -surf->plane->dist;
1389                                         for (poly = surf->polys;poly;poly = poly->next)
1390                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1391                                 }
1392                         }
1393                         else
1394                         {
1395                                 if (!(surf->flags & SURF_PLANEBACK))
1396                                         for (poly = surf->polys;poly;poly = poly->next)
1397                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)&surf->plane);
1398                         }
1399                 }
1400         }
1401         else
1402         {
1403                 int l;
1404                 mleaf_t *leaf;
1405                 msurface_t *surf, **mark, **endmark;
1406                 glpoly_t *poly;
1407                 tinyplane_t plane;
1408
1409                 for (l = 0, leaf = cl.worldmodel->leafs;l < cl.worldmodel->numleafs;l++, leaf++)
1410                 {
1411                         if (R_CullBox(leaf->mins, leaf->maxs))
1412                                 continue;
1413                         leaf->visframe = r_framecount;
1414                         c_leafs++;
1415                         if (leaf->nummarksurfaces)
1416                         {
1417 //                              if (R_CullBox(leaf->mins, leaf->maxs))
1418 //                                      continue;
1419
1420                                 if (leaf->nummarksurfaces)
1421                                 {
1422                                         mark = leaf->firstmarksurface;
1423                                         endmark = mark + leaf->nummarksurfaces;
1424                                         if (r_ser.value)
1425                                         {
1426                                                 do
1427                                                 {
1428                                                         surf = *mark++;
1429                                                         // make sure surfaces are only processed once
1430                                                         if (surf->worldnodeframe == r_framecount)
1431                                                                 continue;
1432                                                         surf->worldnodeframe = r_framecount;
1433                                                         if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1434                                                         {
1435                                                                 if (surf->flags & SURF_PLANEBACK)
1436                                                                 {
1437                                                                         VectorNegate(surf->plane->normal, plane.normal);
1438                                                                         plane.dist = -surf->plane->dist;
1439                                                                         for (poly = surf->polys;poly;poly = poly->next)
1440                                                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1441                                                                 }
1442                                                         }
1443                                                         else
1444                                                         {
1445                                                                 if (!(surf->flags & SURF_PLANEBACK))
1446                                                                         for (poly = surf->polys;poly;poly = poly->next)
1447                                                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1448                                                         }
1449                                                 }
1450                                                 while (mark < endmark);
1451                                         }
1452                                         else
1453                                         {
1454                                                 do
1455                                                 {
1456                                                         surf = *mark++;
1457                                                         // make sure surfaces are only processed once
1458                                                         if (surf->worldnodeframe == r_framecount)
1459                                                                 continue;
1460                                                         surf->worldnodeframe = r_framecount;
1461                                                         if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1462                                                         {
1463                                                                 if (surf->flags & SURF_PLANEBACK)
1464                                                                         surf->visframe = r_framecount;
1465                                                         }
1466                                                         else
1467                                                         {
1468                                                                 if (!(surf->flags & SURF_PLANEBACK))
1469                                                                         surf->visframe = r_framecount;
1470                                                         }
1471                                                 }
1472                                                 while (mark < endmark);
1473                                         }
1474                                 }
1475                         }
1476                 }
1477         }
1478 }
1479
1480 /*
1481 void RSurf_Callback(void *data, void *junk)
1482 {
1483         ((msurface_t *)data)->visframe = r_framecount;
1484 }
1485
1486 int R_FrustumTestPolygon(float *points, int numpoints, int stride);
1487
1488 void RSurf_DoVisible(msurface_t *surf)
1489 {
1490         glpoly_t *p;
1491         for (p = surf->polys;p;p = p->next)
1492                 if (R_FrustumTestPolygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float)) >= 3)
1493 //              R_Clip_Polygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float), true, RSurf_Callback, surf, 1);
1494 //              if (R_Clip_Polygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID))
1495                         surf->visframe = r_framecount;
1496 }
1497 */
1498
1499 //mleaf_t *llistbuffer[32768], *l, **llist;
1500
1501 /*
1502 void RSurfLeaf_Callback(void *data)
1503 {
1504         int portalstackpos = 0;
1505         mleaf_t *leaf;
1506         mportal_t *p, *portalstack[32768];
1507         msurface_t *surf, **mark, **endmark;
1508         do
1509         {
1510
1511                 leaf = data;
1512                 if (leaf->visframe == r_framecount)
1513                         return;
1514                 leaf->visframe = r_framecount;
1515
1516                 c_leafs++;
1517
1518                 if (leaf->nummarksurfaces)
1519                 {
1520                         mark = leaf->firstmarksurface;
1521                         endmark = mark + leaf->nummarksurfaces;
1522                         do
1523                         {
1524                                 surf = *mark++;
1525                                 // make sure surfaces are only processed once
1526                                 if (surf->worldnodeframe == r_framecount)
1527                                         continue;
1528                                 surf->worldnodeframe = r_framecount;
1529                                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1530                                 {
1531                                         if (surf->flags & SURF_PLANEBACK)
1532                                                 RSurf_DoVisible(surf);
1533                                 }
1534                                 else
1535                                 {
1536                                         if (!(surf->flags & SURF_PLANEBACK))
1537                                                 RSurf_DoVisible(surf);
1538                                 }
1539                         }
1540                         while (mark < endmark);
1541                 }
1542
1543                 // follow portals into other leafs
1544                 for (p = leaf->portals;p;p = p->next)
1545                 {
1546                         if (p->past->visframe != r_framecount && DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1547                         {
1548         //                      R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3, RSurfLeaf_Callback, p->past, 1);
1549                                 if (R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3))
1550                                         portalstack[portalstackpos++] = p;
1551                         }
1552                 }
1553         }
1554         while(portalstackpos);
1555         RSurfLeaf_Callback(p->past);
1556         // upon returning, R_ProcessSpans will notice that the spans have changed and restart the line, this is ok because we're not adding any polygons that aren't already behind the portal
1557 }
1558 */
1559
1560 /*
1561 // experimental and inferior to the other in recursion depth allowances
1562 void R_PortalWorldNode (void)
1563 {
1564 //      int i, j;
1565         mportal_t *p;
1566         msurface_t *surf, **mark, **endmark;
1567         mleaf_t *leaf, *llistbuffer[32768], **l, **llist;
1568
1569         leaf = r_viewleaf;
1570         leaf->visframe = r_framecount;
1571         l = llist = &llistbuffer[0];
1572         *llist++ = r_viewleaf;
1573         while (l < llist)
1574         {
1575                 leaf = *l++;
1576
1577                 c_leafs++;
1578
1579                 if (leaf->nummarksurfaces)
1580                 {
1581                         mark = leaf->firstmarksurface;
1582                         endmark = mark + leaf->nummarksurfaces;
1583                         do
1584                         {
1585                                 surf = *mark++;
1586                                 // make sure surfaces are only processed once
1587                                 if (surf->worldnodeframe == r_framecount)
1588                                         continue;
1589                                 surf->worldnodeframe = r_framecount;
1590                                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1591                                 {
1592                                         if (surf->flags & SURF_PLANEBACK)
1593                                                 RSurf_DoVisible(surf);
1594                                 }
1595                                 else
1596                                 {
1597                                         if (!(surf->flags & SURF_PLANEBACK))
1598                                                 RSurf_DoVisible(surf);
1599                                 }
1600                         }
1601                         while (mark < endmark);
1602                 }
1603
1604                 // follow portals into other leafs
1605                 for (p = leaf->portals;p;p = p->next)
1606                 {
1607                         if (p->past->visframe != r_framecount)
1608                         {
1609                                 if (R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3))
1610                                 {
1611                                         p->past->visframe = r_framecount;
1612                                         *llist++ = p->past;
1613                                 }
1614                         }
1615                 }
1616
1617 //              for (p = leaf->portals;p;p = p->next)
1618 //              {
1619 //                      leaf = p->past;
1620 //                      if (leaf->worldnodeframe != r_framecount)
1621 //                      {
1622 //                              leaf->worldnodeframe = r_framecount;
1623 //                              i = (leaf - cl.worldmodel->leafs) - 1;
1624 //                              if ((worldvis[i>>3] & (1<<(i&7))) && R_NotCulledBox(leaf->mins, leaf->maxs))
1625 //                                      *llist++ = leaf;
1626 //                      }
1627 //              }
1628         }
1629
1630 //      i = 0;
1631 //      j = 0;
1632 //      p = r_viewleaf->portals;
1633 //      for (;p;p = p->next)
1634 //      {
1635 //              j++;
1636 //              if (p->past->worldnodeframe != r_framecount)
1637 //                      i++;
1638 //      }
1639 //      if (i)
1640 //              Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, j);
1641 }
1642 */
1643
1644
1645 int r_portalframecount = 0;
1646
1647 /*
1648 void R_Portal_Callback(void *data, void *data2)
1649 {
1650         mleaf_t *leaf = data;
1651         if (!r_testvis.value)
1652                 ((mportal_t *)data2)->visframe = r_portalframecount;
1653         if (leaf->visframe != r_framecount)
1654         {
1655                 c_leafs++;
1656                 leaf->visframe = r_framecount;
1657         }
1658 }
1659 */
1660
1661 void R_PVSWorldNode()
1662 {
1663         if (r_pvsworldnode.value == 1)
1664         {
1665                 int portalstack, i;
1666                 mportal_t *p, *pstack[8192];
1667                 msurface_t *surf, **mark, **endmark;
1668                 mleaf_t *leaf;
1669                 tinyplane_t plane;
1670                 glpoly_t *poly;
1671                 byte *worldvis;
1672
1673                 worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1674
1675                 leaf = r_viewleaf;
1676                 leaf->worldnodeframe = r_framecount;
1677                 portalstack = 0;
1678         loc0:
1679                 c_leafs++;
1680
1681                 leaf->visframe = r_framecount;
1682
1683                 if (leaf->nummarksurfaces)
1684                 {
1685                         mark = leaf->firstmarksurface;
1686                         endmark = mark + leaf->nummarksurfaces;
1687                         if (r_ser.value)
1688                         {
1689                                 do
1690                                 {
1691                                         surf = *mark++;
1692                                         // make sure surfaces are only processed once
1693                                         if (surf->worldnodeframe == r_framecount)
1694                                                 continue;
1695                                         surf->worldnodeframe = r_framecount;
1696                                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1697                                         {
1698                                                 if (surf->flags & SURF_PLANEBACK)
1699                                                 {
1700                                                         VectorNegate(surf->plane->normal, plane.normal);
1701                                                         plane.dist = -surf->plane->dist;
1702                                                         for (poly = surf->polys;poly;poly = poly->next)
1703                                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1704                                                 }
1705                                         }
1706                                         else
1707                                         {
1708                                                 if (!(surf->flags & SURF_PLANEBACK))
1709                                                         for (poly = surf->polys;poly;poly = poly->next)
1710                                                                 R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1711                                         }
1712                                 }
1713                                 while (mark < endmark);
1714                         }
1715                         else
1716                         {
1717                                 do
1718                                 {
1719                                         surf = *mark++;
1720                                         // make sure surfaces are only processed once
1721                                         if (surf->worldnodeframe == r_framecount)
1722                                                 continue;
1723                                         surf->worldnodeframe = r_framecount;
1724                                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1725                                         {
1726                                                 if (surf->flags & SURF_PLANEBACK)
1727                                                         surf->visframe = r_framecount;
1728                                         }
1729                                         else
1730                                         {
1731                                                 if (!(surf->flags & SURF_PLANEBACK))
1732                                                         surf->visframe = r_framecount;
1733                                         }
1734                                 }
1735                                 while (mark < endmark);
1736                         }
1737                 }
1738
1739                 // follow portals into other leafs
1740                 p = leaf->portals;
1741                 for (;p;p = p->next)
1742                 {
1743                         if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1744                         {
1745                                 leaf = p->past;
1746                                 if (leaf->worldnodeframe != r_framecount)
1747                                 {
1748                                         leaf->worldnodeframe = r_framecount;
1749                                         if (leaf->contents != CONTENTS_SOLID)
1750                                         {
1751                                                 i = (leaf - cl.worldmodel->leafs) - 1;
1752                                                 if (worldvis[i>>3] & (1<<(i&7)))
1753                                                 {
1754                                                         if (R_NotCulledBox(leaf->mins, leaf->maxs))
1755                                                         {
1756                                                                 pstack[portalstack++] = p;
1757                                                                 goto loc0;
1758
1759         loc1:
1760                                                                 p = pstack[--portalstack];
1761                                                         }
1762                                                 }
1763                                         }
1764                                 }
1765                         }
1766                 }
1767
1768                 if (portalstack)
1769                         goto loc1;
1770         }
1771         else
1772         {
1773                 int i/*, l*/, k, c, row, numbits, bit, leafnum, numleafs;
1774                 mleaf_t *leaf;
1775                 msurface_t *surf, **mark, **endmark;
1776                 model_t *model = cl.worldmodel;
1777                 byte *in;
1778         //      mportal_t *portal;
1779                 glpoly_t *poly;
1780                 tinyplane_t plane;
1781
1782         //      c_leafs++;
1783         //      r_viewleaf->visframe = r_framecount;
1784                 if (!r_testvis.value)
1785                         r_portalframecount++;
1786
1787                 numleafs = model->numleafs;
1788                 numbits = numleafs;
1789                 k = 0;
1790                 in = r_viewleaf->compressed_vis;
1791                 row = (numbits + 7) >> 3;
1792                 while (k < row)
1793                 {
1794                         c = *in++;
1795                         if (c)
1796                         {
1797                                 for (i = 0, bit = 1;c;i++, bit <<= 1)
1798                                 {
1799                                         if (c & bit)
1800                                         {
1801                                                 leafnum = (k << 3)+i+1;
1802                                                 if (leafnum > numleafs)
1803                                                         return;
1804                                                 c -= bit;
1805                                                 leaf = &model->leafs[leafnum];
1806                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1807                                                 {
1808                                                         //for (portal = leaf->portals;portal;portal = portal->next)
1809                                                         //      if (DotProduct(r_origin, portal->plane.normal) > portal->plane.dist)
1810                                                         //              R_Clip_AddPolygon((float *)portal->points, portal->numpoints, sizeof(mvertex_t), false, R_Portal_Callback, leaf, portal, portal->plane);
1811                                                         //leaf->visframe = r_framecount;
1812                                                         c_leafs++;
1813                                                         if (leaf->nummarksurfaces)
1814                                                         {
1815                                                                 mark = leaf->firstmarksurface;
1816                                                                 endmark = mark + leaf->nummarksurfaces;
1817                                                                 if (r_ser.value)
1818                                                                 {
1819                                                                         do
1820                                                                         {
1821                                                                                 surf = *mark++;
1822                                                                                 // make sure surfaces are only processed once
1823                                                                                 if (surf->worldnodeframe == r_framecount)
1824                                                                                         continue;
1825                                                                                 surf->worldnodeframe = r_framecount;
1826                                                                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1827                                                                                 {
1828                                                                                         if (surf->flags & SURF_PLANEBACK)
1829                                                                                         {
1830                                                                                                 VectorNegate(surf->plane->normal, plane.normal);
1831                                                                                                 plane.dist = -surf->plane->dist;
1832                                                                                                 for (poly = surf->polys;poly;poly = poly->next)
1833                                                                                                         R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1834                                                                                         }
1835                                                                                 }
1836                                                                                 else
1837                                                                                 {
1838                                                                                         if (!(surf->flags & SURF_PLANEBACK))
1839                                                                                                 for (poly = surf->polys;poly;poly = poly->next)
1840                                                                                                         R_Clip_AddPolygon((float *)poly->verts, poly->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1841                                                                                 }
1842                                                                         }
1843                                                                         while (mark < endmark);
1844                                                                 }
1845                                                                 else
1846                                                                 {
1847                                                                         do
1848                                                                         {
1849                                                                                 surf = *mark++;
1850                                                                                 // make sure surfaces are only processed once
1851                                                                                 if (surf->worldnodeframe == r_framecount)
1852                                                                                         continue;
1853                                                                                 surf->worldnodeframe = r_framecount;
1854                                                                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1855                                                                                 {
1856                                                                                         if (surf->flags & SURF_PLANEBACK)
1857                                                                                                 surf->visframe = r_framecount;
1858                                                                                 }
1859                                                                                 else
1860                                                                                 {
1861                                                                                         if (!(surf->flags & SURF_PLANEBACK))
1862                                                                                                 surf->visframe = r_framecount;
1863                                                                                 }
1864                                                                         }
1865                                                                         while (mark < endmark);
1866                                                                 }
1867                                                         }
1868                                                 }
1869                                         }
1870                                 }
1871                                 k++;
1872                         }
1873                         else
1874                                 k += *in++;
1875                 }
1876         }
1877 }
1878
1879 entity_t clworldent;
1880
1881 void R_DrawSurfaces (void)
1882 {
1883         msurface_t      *surf, *endsurf;
1884         texture_t       *t, *currentt;
1885         int vertex = gl_vertex.value;
1886
1887         currententity = &clworldent;
1888         modelalpha = 1;
1889         softwaretransformidentity();
1890         surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
1891         endsurf = surf + cl.worldmodel->nummodelsurfaces;
1892         t = currentt = NULL;
1893         for (;surf < endsurf;surf++)
1894         {
1895                 if (surf->visframe == r_framecount)
1896                 {
1897                         c_faces++;
1898                         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1899                         {
1900                                 if (surf->flags & SURF_DRAWSKY)
1901                                         RSurf_DrawSky(surf, false);
1902                                 else
1903                                 {
1904                                         if (currentt != surf->texinfo->texture)
1905                                         {
1906                                                 currentt = surf->texinfo->texture;
1907                                                 t = R_TextureAnimation(surf->texinfo->texture);
1908                                         }
1909                                         RSurf_DrawWater(surf, t, false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1910                                 }
1911                         }
1912                         else
1913                         {
1914                                 if (currentt != surf->texinfo->texture)
1915                                 {
1916                                         currentt = surf->texinfo->texture;
1917                                         t = R_TextureAnimation(surf->texinfo->texture);
1918                                 }
1919                                 if (vertex)
1920                                         RSurf_DrawWallVertex(surf, t, false, false);
1921                                 else
1922                                         RSurf_DrawWall(surf, t, false);
1923                         }
1924                 }
1925         }
1926 }
1927
1928 void R_DrawPortals(void)
1929 {
1930         int drawportals, i, r, g, b;
1931 //      mleaf_t *leaf, *endleaf;
1932         mportal_t *portal, *endportal;
1933         mvertex_t *point/*, *endpoint*/;
1934         drawportals = (int)r_drawportals.value;
1935         if (drawportals < 1)
1936                 return;
1937         /*
1938         leaf = cl.worldmodel->leafs;
1939         endleaf = leaf + cl.worldmodel->numleafs;
1940         for (;leaf < endleaf;leaf++)
1941         {
1942                 if (leaf->visframe == r_framecount && leaf->portals)
1943                 {
1944                         i = leaf - cl.worldmodel->leafs;
1945                         r = (i & 0x0007) << 5;
1946                         g = (i & 0x0038) << 2;
1947                         b = (i & 0x01C0) >> 1;
1948                         portal = leaf->portals;
1949                         while (portal)
1950                         {
1951                                 transpolybegin(0, 0, 0, TPOLYTYPE_ALPHA);
1952                                 point = portal->points + portal->numpoints - 1;
1953                                 endpoint = portal->points;
1954                                 for (;point >= endpoint;point--)
1955                                         transpolyvertub(point->position[0], point->position[1], point->position[2], 0, 0, r, g, b, 32);
1956                                 transpolyend();
1957                                 portal = portal->next;
1958                         }
1959                 }
1960         }
1961         */
1962         portal = cl.worldmodel->portals;
1963         endportal = portal + cl.worldmodel->numportals;
1964         for (;portal < endportal;portal++)
1965         {
1966                 if (portal->visframe == r_portalframecount)
1967                 {
1968                         i = portal - cl.worldmodel->portals;
1969                         r = (i & 0x0007) << 5;
1970                         g = (i & 0x0038) << 2;
1971                         b = (i & 0x01C0) >> 1;
1972                         transpolybegin(0, 0, 0, TPOLYTYPE_ALPHA);
1973                         point = portal->points;
1974                         if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1975                         {
1976                                 for (i = portal->numpoints - 1;i >= 0;i--)
1977                                         transpolyvertub(point[i].position[0], point[i].position[1], point[i].position[2], 0, 0, r, g, b, 32);
1978                         }
1979                         else
1980                         {
1981                                 for (i = 0;i < portal->numpoints;i++)
1982                                         transpolyvertub(point[i].position[0], point[i].position[1], point[i].position[2], 0, 0, r, g, b, 32);
1983                         }
1984                         transpolyend();
1985                 }
1986         }
1987 }
1988
1989 /*
1990 =============
1991 R_DrawWorld
1992 =============
1993 */
1994 void R_DrawWorld (void)
1995 {
1996         wateralpha = bound(0, r_wateralpha.value*255.0f, 255);
1997         vertexworld = gl_vertex.value;
1998
1999         memset (&clworldent, 0, sizeof(clworldent));
2000         clworldent.render.model = cl.worldmodel;
2001         clworldent.render.colormod[0] = clworldent.render.colormod[1] = clworldent.render.colormod[2] = 1;
2002         modelalpha = clworldent.render.alpha = 1;
2003         clworldent.render.scale = 1;
2004
2005         VectorCopy (r_origin, modelorg);
2006
2007         currententity = &clworldent;
2008
2009         softwaretransformidentity(); // LordHavoc: clear transform
2010
2011         if (cl.worldmodel)
2012         {
2013                 if (r_novis.value || r_viewleaf->compressed_vis == NULL)
2014                         R_SolidWorldNode ();
2015                 else
2016                 {
2017 //                      R_MarkLeaves ();
2018                         R_PVSWorldNode ();
2019                 }
2020         }
2021 }
2022
2023 /*
2024 =============================================================================
2025
2026   LIGHTMAP ALLOCATION
2027
2028 =============================================================================
2029 */
2030
2031 // returns a texture number and the position inside it
2032 int AllocBlock (int w, int h, short *x, short *y)
2033 {
2034         int             i, j;
2035         int             best, best2;
2036         int             texnum;
2037
2038         for (texnum = 0;texnum < MAX_LIGHTMAPS;texnum++)
2039         {
2040                 best = BLOCK_HEIGHT;
2041
2042                 for (i = 0;i < BLOCK_WIDTH - w;i += lightmapalign) // LordHavoc: NVIDIA has broken subimage, so align the lightmaps
2043                 {
2044                         best2 = 0;
2045
2046                         for (j=0 ; j<w ; j++)
2047                         {
2048                                 if (allocated[texnum][i+j] >= best)
2049                                         break;
2050                                 if (allocated[texnum][i+j] > best2)
2051                                         best2 = allocated[texnum][i+j];
2052                         }
2053                         if (j == w)
2054                         {       // this is a valid spot
2055                                 *x = i;
2056                                 *y = best = best2;
2057                         }
2058                 }
2059
2060                 if (best + h > BLOCK_HEIGHT)
2061                         continue;
2062
2063                 if (nosubimagefragments || nosubimage)
2064                 {
2065                         if (!lightmaps[texnum])
2066                         {
2067                                 lightmaps[texnum] = qmalloc(BLOCK_WIDTH*BLOCK_HEIGHT*4);
2068                                 memset(lightmaps[texnum], 0, BLOCK_WIDTH*BLOCK_HEIGHT*4);
2069                         }
2070                 }
2071                 // LordHavoc: clear texture to blank image, fragments are uploaded using subimage
2072                 else if (!allocated[texnum][0])
2073                 {
2074                         byte blank[BLOCK_WIDTH*BLOCK_HEIGHT*4];
2075                         memset(blank, 0, sizeof(blank));
2076                         if(r_upload.value)
2077                         {
2078                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + texnum);
2079                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2080                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2081                                 if (lightmaprgba)
2082                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank);
2083                                 else
2084                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, blank);
2085                         }
2086                 }
2087
2088                 for (i = 0;i < w;i++)
2089                         allocated[texnum][*x + i] = best + h;
2090
2091                 return texnum;
2092         }
2093
2094         Host_Error ("AllocBlock: full, unable to find room for %i by %i lightmap", w, h);
2095         return 0;
2096 }
2097
2098
2099 //int   nColinElim;
2100
2101 /*
2102 ================
2103 BuildSurfaceDisplayList
2104 ================
2105 */
2106 void BuildSurfaceDisplayList (model_t *model, mvertex_t *vertices, msurface_t *fa)
2107 {
2108         int                     i, j, lindex, lnumverts;
2109         medge_t         *pedges;
2110         float           *vec;
2111         float           s, t;
2112         glpoly_t        *poly;
2113
2114 // reconstruct the polygon
2115         pedges = model->edges;
2116         lnumverts = fa->numedges;
2117
2118         //
2119         // draw texture
2120         //
2121         poly = Hunk_AllocName (sizeof(glpolysizeof_t) + lnumverts * sizeof(float[VERTEXSIZE]), "surfaces");
2122         poly->next = fa->polys;
2123         fa->polys = poly;
2124 //      poly->flags = fa->flags;
2125         poly->numverts = lnumverts;
2126
2127         for (i=0 ; i<lnumverts ; i++)
2128         {
2129                 lindex = model->surfedges[fa->firstedge + i];
2130
2131                 if (lindex > 0)
2132                         vec = vertices[pedges[lindex].v[0]].position;
2133                 else
2134                         vec = vertices[pedges[-lindex].v[1]].position;
2135
2136                 s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
2137                 t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
2138
2139                 VectorCopy (vec, poly->verts[i]);
2140                 poly->verts[i][3] = s / fa->texinfo->texture->width;
2141                 poly->verts[i][4] = t / fa->texinfo->texture->height;
2142
2143                 //
2144                 // lightmap texture coordinates
2145                 //
2146                 s -= fa->texturemins[0];
2147                 t -= fa->texturemins[1];
2148                 s += 8;
2149                 t += 8;
2150                 // LordHavoc: calc lightmap data offset
2151                 j = (bound(0l, (int)t>>4, fa->extents[1]>>4) * ((fa->extents[0]>>4)+1) + bound(0l, (int)s>>4, fa->extents[0]>>4)) * 3;
2152                 poly->verts[i][7] = j;
2153                 s += fa->light_s*16;
2154                 s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
2155
2156                 t += fa->light_t*16;
2157                 t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
2158
2159                 poly->verts[i][5] = s;
2160                 poly->verts[i][6] = t;
2161         }
2162
2163         //
2164         // remove co-linear points - Ed
2165         //
2166         /*
2167         if (!gl_keeptjunctions.value)
2168         {
2169                 for (i = 0 ; i < lnumverts ; ++i)
2170                 {
2171                         vec3_t v1, v2;
2172                         float *prev, *this, *next;
2173
2174                         prev = poly->verts[(i + lnumverts - 1) % lnumverts];
2175                         this = poly->verts[i];
2176                         next = poly->verts[(i + 1) % lnumverts];
2177
2178                         VectorSubtract( this, prev, v1 );
2179                         VectorNormalize( v1 );
2180                         VectorSubtract( next, prev, v2 );
2181                         VectorNormalize( v2 );
2182
2183                         // skip co-linear points
2184                         #define COLINEAR_EPSILON 0.001
2185                         if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
2186                                 (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) &&
2187                                 (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
2188                         {
2189                                 int j;
2190                                 for (j = i + 1; j < lnumverts; ++j)
2191                                 {
2192                                         int k;
2193                                         for (k = 0; k < VERTEXSIZE; ++k)
2194                                                 poly->verts[j - 1][k] = poly->verts[j][k];
2195                                 }
2196                                 --lnumverts;
2197                                 ++nColinElim;
2198                                 // retry next vertex next time, which is now current vertex
2199                                 --i;
2200                         }
2201                 }
2202                 poly->numverts = lnumverts;
2203         }
2204         */
2205 }
2206
2207 /*
2208 ========================
2209 GL_CreateSurfaceLightmap
2210 ========================
2211 */
2212 void GL_CreateSurfaceLightmap (msurface_t *surf)
2213 {
2214         int             smax, tmax;
2215
2216         if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
2217                 return;
2218
2219         smax = (surf->extents[0]>>4)+1;
2220         tmax = (surf->extents[1]>>4)+1;
2221
2222         surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
2223         if (nosubimage || nosubimagefragments)
2224                 return;
2225         glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum);
2226         smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask;
2227         if (lightmaprgba)
2228         {
2229                 R_BuildLightMap (surf, templight, smax * 4);
2230                 if(r_upload.value)
2231                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
2232         }
2233         else
2234         {
2235                 R_BuildLightMap (surf, templight, smax * 3);
2236                 if(r_upload.value)
2237                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
2238         }
2239 }
2240
2241
2242 /*
2243 ==================
2244 GL_BuildLightmaps
2245
2246 Builds the lightmap texture
2247 with all the surfaces from all brush models
2248 ==================
2249 */
2250 void GL_BuildLightmaps (void)
2251 {
2252         int             i, j;
2253         model_t *m;
2254
2255         memset (allocated, 0, sizeof(allocated));
2256
2257         r_framecount = 1;               // no dlightcache
2258
2259         if (gl_nosubimagefragments.value)
2260                 nosubimagefragments = 1;
2261         else
2262                 nosubimagefragments = 0;
2263
2264         if (gl_nosubimage.value)
2265                 nosubimage = 1;
2266         else
2267                 nosubimage = 0;
2268
2269         if (gl_lightmaprgba.value)
2270         {
2271                 lightmaprgba = true;
2272                 lightmapbytes = 4;
2273         }
2274         else
2275         {
2276                 lightmaprgba = false;
2277                 lightmapbytes = 3;
2278         }
2279
2280         // LordHavoc: NVIDIA seems to have a broken glTexSubImage2D,
2281         //            it needs to be aligned on 4 pixel boundaries...
2282         //            so I implemented an adjustable lightmap alignment
2283         if (gl_lightmapalign.value < 1)
2284                 gl_lightmapalign.value = 1;
2285         if (gl_lightmapalign.value > 16)
2286                 gl_lightmapalign.value = 16;
2287         lightmapalign = 1;
2288         while (lightmapalign < gl_lightmapalign.value)
2289                 lightmapalign <<= 1;
2290         gl_lightmapalign.value = lightmapalign;
2291         lightmapalignmask = ~(lightmapalign - 1);
2292         if (nosubimagefragments || nosubimage)
2293         {
2294                 lightmapalign = 1;
2295                 lightmapalignmask = ~0;
2296         }
2297
2298         if (!lightmap_textures)
2299                 lightmap_textures = R_GetTextureSlots(MAX_LIGHTMAPS);
2300
2301         for (j=1 ; j<MAX_MODELS ; j++)
2302         {
2303                 m = cl.model_precache[j];
2304                 if (!m)
2305                         break;
2306                 if (m->name[0] == '*')
2307                         continue;
2308                 for (i=0 ; i<m->numsurfaces ; i++)
2309                 {
2310                         if ( m->surfaces[i].flags & SURF_DRAWTURB )
2311                                 continue;
2312                         if ( m->surfaces[i].flags & SURF_DRAWSKY )
2313                                 continue;
2314                         GL_CreateSurfaceLightmap (m->surfaces + i);
2315                         BuildSurfaceDisplayList (m, m->vertexes, m->surfaces + i);
2316                 }
2317         }
2318
2319         if (nosubimage || nosubimagefragments)
2320         {
2321                 if(r_upload.value)
2322                         if (gl_mtexable)
2323                                 qglSelectTexture(gl_mtex_enum+1);
2324                 for (i = 0;i < MAX_LIGHTMAPS;i++)
2325                 {
2326                         if (!allocated[i][0])
2327                                 break;
2328                         lightmapupdate[i][0] = BLOCK_HEIGHT;
2329                         lightmapupdate[i][1] = 0;
2330                         if(r_upload.value)
2331                         {
2332                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
2333                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2334                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2335                                 if (lightmaprgba)
2336                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
2337                                 else
2338                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
2339                         }
2340                 }
2341                 if(r_upload.value)
2342                         if (gl_mtexable)
2343                                 qglSelectTexture(gl_mtex_enum+0);
2344         }
2345 }
2346