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