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