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