]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rsurf.c
gzip support from quakeforge (QFile and friends). also includes a couple of
[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 // LordHavoc: skinny but tall lightmaps for quicker subimage uploads
27 #define BLOCK_WIDTH             256
28 #define BLOCK_HEIGHT    256
29 // LordHavoc: increased lightmap limit from 64 to 1024
30 #define MAX_LIGHTMAPS   1024
31 #define LIGHTMAPSIZE    (BLOCK_WIDTH*BLOCK_HEIGHT*4)
32
33 int                     active_lightmaps;
34
35 short allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
36
37 byte *lightmaps[MAX_LIGHTMAPS];
38 short lightmapupdate[MAX_LIGHTMAPS][2];
39
40 signed int blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; // LordHavoc: *3 for colored lighting
41
42 int lightmapalign, lightmapalignmask; // LordHavoc: NVIDIA's broken subimage fix, see BuildLightmaps for notes
43 cvar_t gl_lightmapalign = {"gl_lightmapalign", "4"};
44 cvar_t gl_lightmaprgba = {"gl_lightmaprgba", "1"};
45 cvar_t gl_nosubimagefragments = {"gl_nosubimagefragments", "0"};
46 cvar_t gl_nosubimage = {"gl_nosubimage", "0"};
47 cvar_t r_ambient = {"r_ambient", "0"};
48 cvar_t gl_vertex = {"gl_vertex", "0"};
49 cvar_t r_dlightmap = {"r_dlightmap", "1"};
50 cvar_t r_drawportals = {"r_drawportals", "0"};
51
52 qboolean lightmaprgba, nosubimagefragments, nosubimage;
53 int lightmapbytes;
54
55 int wateralpha;
56
57 void gl_surf_start(void)
58 {
59 }
60
61 void gl_surf_shutdown(void)
62 {
63 }
64
65 void gl_surf_newmap(void)
66 {
67 }
68
69 void GL_Surf_Init(void)
70 {
71         int i;
72         for (i = 0;i < MAX_LIGHTMAPS;i++)
73                 lightmaps[i] = NULL;
74         Cvar_RegisterVariable(&gl_lightmapalign);
75         Cvar_RegisterVariable(&gl_lightmaprgba);
76         Cvar_RegisterVariable(&gl_nosubimagefragments);
77         Cvar_RegisterVariable(&gl_nosubimage);
78         Cvar_RegisterVariable(&r_ambient);
79         Cvar_RegisterVariable(&gl_vertex);
80         Cvar_RegisterVariable(&r_dlightmap);
81         Cvar_RegisterVariable(&r_drawportals);
82
83         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
84 }
85
86 int         dlightdivtable[32768];
87
88 /*
89         R_AddDynamicLights
90 */
91 int R_AddDynamicLights (msurface_t *surf)
92 {
93         int         sdtable[18], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, red, green, blue, lit, dist2, impacts, impactt;
94         unsigned int *bl;
95         float       dist;
96         vec3_t      impact, local;
97
98         // LordHavoc: use 64bit integer...  shame it's not very standardized...
99 #if _MSC_VER || __BORLANDC__
100         __int64     k;
101 #else
102         long long   k;
103 #endif
104
105         lit = false;
106
107         if (!dlightdivtable[1])
108         {
109                 dlightdivtable[0] = 4194304;
110                 for (s = 1; s < 32768; s++)
111                         dlightdivtable[s] = 4194304 / (s << 7);
112         }
113
114         smax = (surf->extents[0] >> 4) + 1;
115         tmax = (surf->extents[1] >> 4) + 1;
116
117         for (lnum = 0; lnum < MAX_DLIGHTS; lnum++)
118         {
119                 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
120                         continue;                                       // not lit by this light
121
122                 VectorSubtract (cl_dlights[lnum].origin, currententity->render.origin, local);
123                 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
124
125                 // for comparisons to minimum acceptable light
126                 maxdist = (int) ((cl_dlights[lnum].radius * cl_dlights[lnum].radius));
127
128                 // clamp radius to avoid exceeding 32768 entry division table
129                 if (maxdist > 4194304)
130                         maxdist = 4194304;
131
132                 dist2 = dist * dist;
133                 if (dist2 >= maxdist)
134                         continue;
135
136                 impact[0] = cl_dlights[lnum].origin[0] - surf->plane->normal[0] * dist;
137                 impact[1] = cl_dlights[lnum].origin[1] - surf->plane->normal[1] * dist;
138                 impact[2] = cl_dlights[lnum].origin[2] - surf->plane->normal[2] * dist;
139
140                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
141                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
142
143                 s = bound(0, impacts, smax * 16) - impacts;
144                 t = bound(0, impactt, tmax * 16) - impactt;
145                 i = s * s + t * t + dist2;
146                 if (i > maxdist)
147                         continue;
148
149                 // reduce calculations
150                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
151                         sdtable[s] = i * i + dist2 + LIGHTOFFSET;
152
153                 maxdist3 = maxdist - (int) (dist * dist);
154
155                 // convert to 8.8 blocklights format and scale up by radius
156                 red = cl_dlights[lnum].color[0] * maxdist;
157                 green = cl_dlights[lnum].color[1] * maxdist;
158                 blue = cl_dlights[lnum].color[2] * maxdist;
159                 bl = blocklights;
160
161                 i = impactt;
162                 for (t = 0; t < tmax; t++, i -= 16)
163                 {
164                         td = i * i;
165                         // make sure some part of it is visible on this line
166                         if (td < maxdist3)
167                         {
168                                 maxdist2 = maxdist - td;
169                                 for (s = 0; s < smax; s++)
170                                 {
171                                         if (sdtable[s] < maxdist2)
172                                         {
173                                                 k = dlightdivtable[(sdtable[s] + td) >> 7];
174                                                 bl[0] += (red   * k) >> 9;
175                                                 bl[1] += (green * k) >> 9;
176                                                 bl[2] += (blue  * k) >> 9;
177                                                 lit = true;
178                                         }
179                                         bl += 3;
180                                 }
181                         }
182                         else // skip line
183                                 bl += smax * 3;
184                 }
185         }
186         return lit;
187 }
188
189
190 void R_ConvertLightmap (int *in, byte *out, int width, int height, int stride)
191 {
192         int i, j;
193         stride -= (width*lightmapbytes);
194         if (lighthalf)
195         {
196                 // LordHavoc: I shift down by 8 unlike GLQuake's 7,
197                 // the image is brightened as a processing pass
198                 if (lightmaprgba)
199                 {
200                         for (i = 0;i < height;i++, out += stride)
201                         {
202                                 for (j = 0;j < width;j++, in += 3, out += 4)
203                                 {
204                                         out[0] = min(in[0] >> 8, 255);
205                                         out[1] = min(in[1] >> 8, 255);
206                                         out[2] = min(in[2] >> 8, 255);
207                                         out[3] = 255;
208                                 }
209                         }
210                 }
211                 else
212                 {
213                         for (i = 0;i < height;i++, out += stride)
214                         {
215                                 for (j = 0;j < width;j++, in += 3, out += 3)
216                                 {
217                                         out[0] = min(in[0] >> 8, 255);
218                                         out[1] = min(in[1] >> 8, 255);
219                                         out[2] = min(in[2] >> 8, 255);
220                                 }
221                         }
222                 }
223         }
224         else
225         {
226                 if (lightmaprgba)
227                 {
228                         for (i = 0;i < height;i++, out += stride)
229                         {
230                                 for (j = 0;j < width;j++, in += 3, out += 4)
231                                 {
232                                         out[0] = min(in[0] >> 7, 255);
233                                         out[1] = min(in[1] >> 7, 255);
234                                         out[2] = min(in[2] >> 7, 255);
235                                         out[3] = 255;
236                                 }
237                         }
238                 }
239                 else
240                 {
241                         for (i = 0;i < height;i++, out += stride)
242                         {
243                                 for (j = 0;j < width;j++, in += 3, out += 3)
244                                 {
245                                         out[0] = min(in[0] >> 7, 255);
246                                         out[1] = min(in[1] >> 7, 255);
247                                         out[2] = min(in[2] >> 7, 255);
248                                 }
249                         }
250                 }
251         }
252 }
253
254 /*
255 ===============
256 R_BuildLightMap
257
258 Combine and scale multiple lightmaps into the 8.8 format in blocklights
259 ===============
260 */
261 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
262 {
263         int                     smax, tmax;
264         int                     i, j, size, size3;
265         byte            *lightmap;
266         int                     scale;
267         int                     maps;
268         int                     *bl;
269
270         surf->cached_dlight = 0;
271         surf->cached_lighthalf = lighthalf;
272         surf->cached_ambient = r_ambient.value;
273
274         smax = (surf->extents[0]>>4)+1;
275         tmax = (surf->extents[1]>>4)+1;
276         size = smax*tmax;
277         size3 = size*3;
278         lightmap = surf->samples;
279
280 // set to full bright if no light data
281         if ((currententity && (currententity->render.effects & EF_FULLBRIGHT)) || !cl.worldmodel->lightdata)
282         {
283                 bl = blocklights;
284                 for (i=0 ; i<size ; i++)
285                 {
286                         *bl++ = 255*256;
287                         *bl++ = 255*256;
288                         *bl++ = 255*256;
289                 }
290         }
291         else
292         {
293 // clear to no light
294                 j = r_ambient.value * 512.0f; // would be 256.0f logically, but using 512.0f to match winquake style
295                 if (j)
296                 {
297                         bl = blocklights;
298                         for (i = 0;i < size3;i++)
299                                 *bl++ = j;
300                 }
301                 else
302                         memset(&blocklights[0], 0, size*3*sizeof(int));
303
304 // add all the lightmaps
305                 if (lightmap)
306                 {
307                         for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
308                         {
309                                 scale = d_lightstylevalue[surf->styles[maps]];
310                                 surf->cached_light[maps] = scale;       // 8.8 fraction
311                                 bl = blocklights;
312                                 for (i = 0;i < size3;i++)
313                                         *bl++ += *lightmap++ * scale;
314                         }
315                 }
316                 if (r_dlightmap.value && surf->dlightframe == r_framecount)
317                         if ((surf->cached_dlight = R_AddDynamicLights(surf)))
318                                 c_light_polys++;
319         }
320         R_ConvertLightmap(blocklights, dest, smax, tmax, stride);
321 }
322
323 byte templight[BLOCK_WIDTH*BLOCK_HEIGHT*4];
324
325 void R_UpdateLightmap(msurface_t *s, int lnum)
326 {
327         int smax, tmax;
328         // upload the new lightmap texture fragment
329         if(r_upload.value)
330                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + lnum);
331         if (nosubimage || nosubimagefragments)
332         {
333                 if (lightmapupdate[lnum][0] > s->light_t)
334                         lightmapupdate[lnum][0] = s->light_t;
335                 if (lightmapupdate[lnum][1] < (s->light_t + ((s->extents[1]>>4)+1)))
336                         lightmapupdate[lnum][1] = (s->light_t + ((s->extents[1]>>4)+1));
337                 if (lightmaprgba)
338                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 4, BLOCK_WIDTH * 4);
339                 else
340                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 3, BLOCK_WIDTH * 3);
341         }
342         else
343         {
344                 smax = ((s->extents[0]>>4)+lightmapalign) & lightmapalignmask;
345                 tmax = (s->extents[1]>>4)+1;
346                 if (lightmaprgba)
347                 {
348                         R_BuildLightMap (s, templight, smax * 4);
349                         if(r_upload.value)
350                                 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
351                 }
352                 else
353                 {
354                         R_BuildLightMap (s, templight, smax * 3);
355                         if(r_upload.value)
356                                 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
357                 }
358         }
359 }
360
361
362 /*
363 ===============
364 R_TextureAnimation
365
366 Returns the proper texture for a given time and base texture
367 ===============
368 */
369 texture_t *R_TextureAnimation (texture_t *base)
370 {
371 //      texture_t *original;
372 //      int             relative;
373 //      int             count;
374
375         if (currententity->render.frame)
376         {
377                 if (base->alternate_anims)
378                         base = base->alternate_anims;
379         }
380         
381         if (!base->anim_total)
382                 return base;
383
384         return base->anim_frames[(int)(cl.time*5) % base->anim_total];
385
386         /*
387         original = base;
388
389         relative = (int)(cl.time*5) % base->anim_total;
390
391         count = 0;      
392         while (base->anim_min > relative || base->anim_max <= relative)
393         {
394                 base = base->anim_next;
395                 if (!base)
396                 {
397                         Con_Printf("R_TextureAnimation: broken cycle");
398                         return original;
399                 }
400                 if (++count > 100)
401                 {
402                         Con_Printf("R_TextureAnimation: infinite cycle");
403                         return original;
404                 }
405         }
406
407         return base;
408         */
409 }
410
411
412 /*
413 =============================================================
414
415         BRUSH MODELS
416
417 =============================================================
418 */
419
420
421 float   turbsin[256] =
422 {
423         #include "gl_warp_sin.h"
424 };
425 #define TURBSCALE (256.0 / (2 * M_PI))
426
427
428 void UploadLightmaps(void)
429 {
430         int i;
431         if (nosubimage || nosubimagefragments)
432         {
433                 for (i = 0;i < MAX_LIGHTMAPS;i++)
434                 {
435                         if (lightmapupdate[i][0] < lightmapupdate[i][1])
436                         {
437                                 if(r_upload.value)
438                                 {
439                                         glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
440                                         if (nosubimage)
441                                         {
442                                                 if (lightmaprgba)
443                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
444                                                 else
445                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
446                                         }
447                                         else
448                                         {
449                                                 if (lightmaprgba)
450                                                         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]));
451                                                 else
452                                                         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]));
453                                         }
454                                 }
455                         }
456                         lightmapupdate[i][0] = BLOCK_HEIGHT;
457                         lightmapupdate[i][1] = 0;
458                 }
459         }
460 }
461
462 float   wvert[1024*6]; // used by the following functions
463
464 void RSurf_DrawSky(msurface_t *s, int transform)
465 {
466         glpoly_t *p;
467         int i;
468         float *v;
469
470         // LordHavoc: HalfLife maps have freaky skypolys...
471         if (hlbsp)
472                 return;
473
474         for (p=s->polys ; p ; p=p->next)
475         {
476                 if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS)
477                 {
478                         skypoly[currentskypoly].firstvert = currentskyvert;
479                         skypoly[currentskypoly++].verts = p->numverts;
480                         if (transform)
481                         {
482                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
483                                 {
484                                         softwaretransform(v, skyvert[currentskyvert].v);
485                                         currentskyvert++;
486                                 }
487                         }
488                         else
489                         {
490                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
491                                 {
492                                         VectorCopy(v, skyvert[currentskyvert].v);
493                                         currentskyvert++;
494                                 }
495                         }
496                 }
497         }
498 }
499
500 int RSurf_Light(int *dlightbits, glpoly_t *polys)
501 {
502         float           cr, cg, cb, radius, radius2, f, *v, *wv;
503         int                     i, a, b, lit = false;
504         unsigned int c, d;
505         dlight_t        *light;
506         vec_t           *lightorigin;
507         glpoly_t        *p;
508         for (a = 0;a < 8;a++)
509         {
510                 if ((c = dlightbits[a]))
511                 {
512                         for (b = 0, d = 1;c;b++, d <<= 1)
513                         {
514                                 if (c & d)
515                                 {
516                                         c -= d;
517                                         light = &cl_dlights[a * 32 + b];
518                                         lightorigin = light->origin;
519                                         cr = light->color[0];
520                                         cg = light->color[1];
521                                         cb = light->color[2];
522                                         radius = light->radius*light->radius;
523                                         radius2 = radius * 256.0f;
524                                         wv = wvert;
525                                         for (p = polys;p;p = p->next)
526                                         {
527                                                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
528                                                 {
529                                                         f = VectorDistance2(wv, lightorigin);
530                                                         if (f < radius)
531                                                         {
532                                                                 f = radius2 / (f + LIGHTOFFSET);
533                                                                 wv[3] += cr * f;
534                                                                 wv[4] += cg * f;
535                                                                 wv[5] += cb * f;
536                                                                 lit = true;
537                                                         }
538                                                         wv += 6;
539                                                 }
540                                         }
541                                 }
542                         }
543                 }
544         }
545         return lit;
546 }
547
548 void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
549 {
550         int             i;
551         float   os = turbsin[(int)(cl.time * TURBSCALE) & 255], ot = turbsin[(int)(cl.time * TURBSCALE + 96.0) & 255];
552         glpoly_t *p;
553         float   *v;
554         // FIXME: make fog texture if water texture is transparent?
555
556         if (s->dlightframe != r_framecount)
557         {
558                 vec3_t temp;
559                 // LordHavoc: fast path for no vertex lighting cases
560                 if (transform)
561                 {
562                         if (r_waterripple.value)
563                         {
564                                 for (p=s->polys ; p ; p=p->next)
565                                 {
566                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
567                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
568                                         {
569                                                 softwaretransform(v, temp);
570                                                 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);
571                                         }
572                                         transpolyend();
573                                 }
574                         }
575                         else
576                         {
577                                 for (p=s->polys ; p ; p=p->next)
578                                 {
579                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
580                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
581                                         {
582                                                 softwaretransform(v, temp);
583                                                 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);
584                                         }
585                                         transpolyend();
586                                 }
587                         }
588                 }
589                 else
590                 {
591                         if (r_waterripple.value)
592                         {
593                                 for (p=s->polys ; p ; p=p->next)
594                                 {
595                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
596                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
597                                                 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);
598                                         transpolyend();
599                                 }
600                         }
601                         else
602                         {
603                                 for (p=s->polys ; p ; p=p->next)
604                                 {
605                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
606                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
607                                                 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);
608                                         transpolyend();
609                                 }
610                         }
611                 }
612         }
613         else
614         {
615                 float *wv;
616                 wv = wvert;
617                 for (p = s->polys;p;p = p->next)
618                 {
619                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
620                         {
621                                 if (transform)
622                                         softwaretransform(v, wv);
623                                 else
624                                         VectorCopy(v, wv);
625                                 if (r_waterripple.value)
626                                         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);
627                                 wv[3] = wv[4] = wv[5] = 128.0f;
628                                 wv += 6;
629                         }
630                 }
631                 if (s->dlightframe == r_framecount)
632                         RSurf_Light(s->dlightbits, s->polys);
633                 wv = wvert;
634                 for (p=s->polys ; p ; p=p->next)
635                 {
636                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
637                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
638                                 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);
639                         transpolyend();
640                 }
641         }
642 }
643
644 void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform)
645 {
646         int             i, lit = false, polys = 0, verts = 0;
647         float   *v;
648         glpoly_t *p;
649         wallpoly_t *wp;
650         wallvert_t *out;
651         wallvertcolor_t *outcolor;
652         // check for lightmap modification
653         if (s->cached_dlight
654          || (r_dynamic.value && r_dlightmap.value && s->dlightframe == r_framecount)
655          || r_ambient.value != s->cached_ambient
656          || lighthalf != s->cached_lighthalf
657          || (r_dynamic.value
658          && ((s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0])
659          || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1])
660          || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2])
661          || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))))
662                 R_UpdateLightmap(s, s->lightmaptexturenum);
663         if (r_dlightmap.value || s->dlightframe != r_framecount)
664         {
665                 // LordHavoc: fast path version for no vertex lighting cases
666                 wp = &wallpoly[currentwallpoly];
667                 out = &wallvert[currentwallvert];
668                 for (p = s->polys;p;p = p->next)
669                 {
670                         if ((currentwallpoly >= MAX_WALLPOLYS) || (currentwallvert+p->numverts > MAX_WALLVERTS))
671                                 return;
672                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
673                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
674                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
675                         wp->firstvert = currentwallvert;
676                         wp->numverts = p->numverts;
677                         wp->lit = lit;
678                         wp++;
679                         currentwallpoly++;
680                         currentwallvert += p->numverts;
681                         v = p->verts[0];
682                         if (transform)
683                         {
684                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
685                                 {
686                                         softwaretransform(v, out->vert);
687                                         out->vert[3] = v[3];
688                                         out->vert[4] = v[4];
689                                         out->vert[5] = v[5];
690                                         out->vert[6] = v[6];
691                                 }
692                         }
693                         else
694                         {
695                                 /*
696                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
697                                 {
698                                         VectorCopy(v, out->vert);
699                                         out->vert[3] = v[3];
700                                         out->vert[4] = v[4];
701                                         out->vert[5] = v[5];
702                                         out->vert[6] = v[6];
703                                 }
704                                 */
705                                 memcpy(out, v, sizeof(vec_t) * VERTEXSIZE * p->numverts);
706                                 out += p->numverts;
707                         }
708                 }
709         }
710         else
711         {
712                 float *wv;
713                 wv = wvert;
714                 for (p = s->polys;p;p = p->next)
715                 {
716                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
717                         {
718                                 if (transform)
719                                         softwaretransform(v, wv);
720                                 else
721                                         VectorCopy(v, wv);
722                                 wv[3] = wv[4] = wv[5] = 0.0f;
723                                 wv += 6;
724                         }
725                         verts += p->numverts;
726                         polys++;
727                 }
728                 if ((currentwallpoly + polys > MAX_WALLPOLYS) || (currentwallvert+verts > MAX_WALLVERTS))
729                         return;
730                 if ((!r_dlightmap.value) && s->dlightframe == r_framecount)
731                         lit = RSurf_Light(s->dlightbits, s->polys);
732                 wv = wvert;
733                 wp = &wallpoly[currentwallpoly];
734                 out = &wallvert[currentwallvert];
735                 outcolor = &wallvertcolor[currentwallvert];
736                 currentwallpoly += polys;
737                 for (p = s->polys;p;p = p->next)
738                 {
739                         v = p->verts[0];
740                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
741                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
742                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
743                         wp->firstvert = currentwallvert;
744                         wp->numverts = p->numverts;
745                         wp->lit = lit;
746                         wp++;
747                         currentwallvert += p->numverts;
748                         for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++, outcolor++)
749                         {
750                                 if (lit)
751                                 {
752                                         if (lighthalf)
753                                         {
754                                                 outcolor->r = (byte) (bound(0, (int) wv[3] >> 1, 255));
755                                                 outcolor->g = (byte) (bound(0, (int) wv[4] >> 1, 255));
756                                                 outcolor->b = (byte) (bound(0, (int) wv[5] >> 1, 255));
757                                                 outcolor->a = 255;
758                                         }
759                                         else
760                                         {
761                                                 outcolor->r = (byte) (bound(0, (int) wv[3], 255));
762                                                 outcolor->g = (byte) (bound(0, (int) wv[4], 255));
763                                                 outcolor->b = (byte) (bound(0, (int) wv[5], 255));
764                                                 outcolor->a = 255;
765                                         }
766                                 }
767                                 out->vert[0] = wv[0];
768                                 out->vert[1] = wv[1];
769                                 out->vert[2] = wv[2];
770                                 out->vert[3] = v[3];
771                                 out->vert[4] = v[4];
772                                 out->vert[5] = v[5];
773                                 out->vert[6] = v[6];
774                         }
775                 }
776         }
777 }
778
779 // LordHavoc: transparent brush models
780 void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel)
781 {
782         int i, alpha, size3;
783         float *v, *wv, scale;
784         glpoly_t *p;
785         byte *lm;
786         alpha = (int) (modelalpha * 255.0f);
787         size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
788         wv = wvert;
789         for (p = s->polys;p;p = p->next)
790         {
791                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
792                 {
793                         if (transform)
794                                 softwaretransform(v, wv);
795                         else
796                                 VectorCopy(v, wv);
797                         wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f;
798                         if (s->styles[0] != 255)
799                         {
800                                 lm = (byte *)((long) s->samples + (int) v[7]);
801                                 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;
802                                 if (s->styles[1] != 255)
803                                 {
804                                         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;
805                                         if (s->styles[2] != 255)
806                                         {
807                                                 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;
808                                                 if (s->styles[3] != 255)
809                                                 {
810                                                         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;
811                                                 }
812                                         }
813                                 }
814                         }
815                         wv += 6;
816                 }
817         }
818         if (s->dlightframe == r_framecount)
819                 RSurf_Light(s->dlightbits, s->polys);
820         wv = wvert;
821         if (isbmodel && (currententity->render.colormod[0] != 1 || currententity->render.colormod[1] != 1 || currententity->render.colormod[2] != 1))
822         {
823                 for (p = s->polys;p;p = p->next)
824                 {
825                         v = p->verts[0];
826                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
827                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
828                                 transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->render.colormod[0], wv[4] * currententity->render.colormod[1], wv[5] * currententity->render.colormod[2], alpha);
829                         transpolyend();
830                 }
831         }
832         else
833         {
834                 for (p = s->polys;p;p = p->next)
835                 {
836                         v = p->verts[0];
837                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
838                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
839                                 transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha);
840                         transpolyend();
841                 }
842         }
843 }
844
845 void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model);
846
847 /*
848 =================
849 R_DrawBrushModel
850 =================
851 */
852 void R_DrawBrushModel (entity_t *e)
853 {
854         int                     i;
855         vec3_t          mins, maxs;
856         msurface_t      *s;
857         model_t         *clmodel;
858         int     rotated, vertexlit = false;
859         vec3_t          org;
860
861         currententity = e;
862
863         clmodel = e->render.model;
864
865         if (e->render.angles[0] || e->render.angles[1] || e->render.angles[2])
866         {
867                 rotated = true;
868                 for (i=0 ; i<3 ; i++)
869                 {
870                         mins[i] = e->render.origin[i] - clmodel->radius;
871                         maxs[i] = e->render.origin[i] + clmodel->radius;
872                 }
873         }
874         else
875         {
876                 rotated = false;
877                 VectorAdd (e->render.origin, clmodel->mins, mins);
878                 VectorAdd (e->render.origin, clmodel->maxs, maxs);
879         }
880
881         if (R_VisibleCullBox (mins, maxs))
882                 return;
883
884         c_bmodels++;
885
886         VectorSubtract (r_origin, e->render.origin, modelorg);
887         if (rotated)
888         {
889                 vec3_t  temp;
890                 vec3_t  forward, right, up;
891
892                 VectorCopy (modelorg, temp);
893                 AngleVectors (e->render.angles, forward, right, up);
894                 modelorg[0] = DotProduct (temp, forward);
895                 modelorg[1] = -DotProduct (temp, right);
896                 modelorg[2] = DotProduct (temp, up);
897         }
898
899         for (i = 0, s = &clmodel->surfaces[clmodel->firstmodelsurface];i < clmodel->nummodelsurfaces;i++, s++)
900         {
901                 if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
902                         s->visframe = r_framecount;
903                 else
904                         s->visframe = -1;
905         }
906
907 // calculate dynamic lighting for bmodel if it's not an
908 // instanced model
909         for (i = 0;i < MAX_DLIGHTS;i++)
910         {
911                 if (!cl_dlights[i].radius)
912                         continue;
913
914                 VectorSubtract(cl_dlights[i].origin, currententity->render.origin, org);
915                 R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel);
916         }
917         vertexlit = modelalpha != 1 || clmodel->firstmodelsurface == 0 || (currententity->render.effects & EF_FULLBRIGHT) || currententity->render.colormod[0] != 1 || currententity->render.colormod[2] != 1 || currententity->render.colormod[2] != 1;
918
919         e->render.angles[0] = -e->render.angles[0];     // stupid quake bug
920         softwaretransformforentity (e);
921         e->render.angles[0] = -e->render.angles[0];     // stupid quake bug
922
923         // draw texture
924         for (i = 0, s = &clmodel->surfaces[clmodel->firstmodelsurface];i < clmodel->nummodelsurfaces;i++, s++)
925         {
926                 if (s->visframe == r_framecount)
927                 {
928 //                      R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent);
929                         if (s->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
930                         {
931                                 // sky and liquid don't need sorting (skypoly/transpoly)
932                                 if (s->flags & SURF_DRAWSKY)
933                                         RSurf_DrawSky(s, true);
934                                 else
935                                         RSurf_DrawWater(s, R_TextureAnimation(s->texinfo->texture), true, s->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
936                         }
937                         else
938                         {
939                                 texture_t *t = R_TextureAnimation(s->texinfo->texture);
940                                 if (vertexlit || s->texinfo->texture->transparent)
941                                         RSurf_DrawWallVertex(s, t, true, true);
942                                 else
943                                         RSurf_DrawWall(s, t, true);
944                         }
945                 }
946         }
947         UploadLightmaps();
948 }
949
950 /*
951 =============================================================
952
953         WORLD MODEL
954
955 =============================================================
956 */
957
958 static byte *worldvis;
959
960 void R_MarkLeaves (void)
961 {
962         static float noviscache;
963         if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
964                 return;
965
966         r_oldviewleaf = r_viewleaf;
967         noviscache = r_novis.value;
968
969         worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
970 }
971
972 void R_SolidWorldNode (void)
973 {
974         int l;
975         mleaf_t *leaf;
976         msurface_t *surf, **mark, **endmark;
977
978         for (l = 0, leaf = cl.worldmodel->leafs;l < cl.worldmodel->numleafs;l++, leaf++)
979         {
980                 if (leaf->nummarksurfaces)
981                 {
982                         if (R_CullBox(leaf->mins, leaf->maxs))
983                                 continue;
984
985                         c_leafs++;
986
987                         leaf->visframe = r_framecount;
988
989                         if (leaf->nummarksurfaces)
990                         {
991                                 mark = leaf->firstmarksurface;
992                                 endmark = mark + leaf->nummarksurfaces;
993                                 do
994                                 {
995                                         surf = *mark++;
996                                         // make sure surfaces are only processed once
997                                         if (surf->worldnodeframe == r_framecount)
998                                                 continue;
999                                         surf->worldnodeframe = r_framecount;
1000                                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1001                                         {
1002                                                 if (surf->flags & SURF_PLANEBACK)
1003                                                         surf->visframe = r_framecount;
1004                                         }
1005                                         else
1006                                         {
1007                                                 if (!(surf->flags & SURF_PLANEBACK))
1008                                                         surf->visframe = r_framecount;
1009                                         }
1010                                 }
1011                                 while (mark < endmark);
1012                         }
1013                 }
1014         }
1015 }
1016
1017 /*
1018 // experimental and inferior to the other in recursion depth allowances
1019 void R_PortalWorldNode (void)
1020 {
1021         int i, j;
1022         mportal_t *p;
1023         msurface_t *surf, **mark, **endmark;
1024         mleaf_t *leaf, *llistbuffer[8192], **l, **llist;
1025
1026         leaf = r_viewleaf;
1027         leaf->worldnodeframe = r_framecount;
1028         l = llist = &llistbuffer[0];
1029         *llist++ = r_viewleaf;
1030         while (l < llist)
1031         {
1032                 leaf = *l++;
1033
1034                 c_leafs++;
1035
1036                 leaf->visframe = r_framecount;
1037
1038                 if (leaf->nummarksurfaces)
1039                 {
1040                         mark = leaf->firstmarksurface;
1041                         endmark = mark + leaf->nummarksurfaces;
1042                         do
1043                         {
1044                                 surf = *mark++;
1045                                 // make sure surfaces are only processed once
1046                                 if (surf->worldnodeframe == r_framecount)
1047                                         continue;
1048                                 surf->worldnodeframe = r_framecount;
1049                                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1050                                 {
1051                                         if (surf->flags & SURF_PLANEBACK)
1052                                                 surf->visframe = r_framecount;
1053                                 }
1054                                 else
1055                                 {
1056                                         if (!(surf->flags & SURF_PLANEBACK))
1057                                                 surf->visframe = r_framecount;
1058                                 }
1059                         }
1060                         while (mark < endmark);
1061                 }
1062
1063                 // follow portals into other leafs
1064                 p = leaf->portals;
1065                 for (;p;p = p->next)
1066                 {
1067                         leaf = p->past;
1068                         if (leaf->worldnodeframe != r_framecount)
1069                         {
1070                                 leaf->worldnodeframe = r_framecount;
1071                                 i = (leaf - cl.worldmodel->leafs) - 1;
1072                                 if ((worldvis[i>>3] & (1<<(i&7))) && R_NotCulledBox(leaf->mins, leaf->maxs))
1073                                         *llist++ = leaf;
1074                         }
1075                 }
1076         }
1077
1078         i = 0;
1079         j = 0;
1080         p = r_viewleaf->portals;
1081         for (;p;p = p->next)
1082         {
1083                 j++;
1084                 if (p->past->worldnodeframe != r_framecount)
1085                         i++;
1086         }
1087         if (i)
1088                 Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, j);
1089 }
1090 */
1091
1092 void R_PortalWorldNode (void)
1093 {
1094         int portalstack, i;
1095         mportal_t *p, *pstack[8192];
1096         msurface_t *surf, **mark, **endmark;
1097         mleaf_t *leaf;
1098
1099         leaf = r_viewleaf;
1100         leaf->worldnodeframe = r_framecount;
1101         portalstack = 0;
1102 loc0:
1103         c_leafs++;
1104
1105         leaf->visframe = r_framecount;
1106
1107         if (leaf->nummarksurfaces)
1108         {
1109                 mark = leaf->firstmarksurface;
1110                 endmark = mark + leaf->nummarksurfaces;
1111                 do
1112                 {
1113                         surf = *mark++;
1114                         // make sure surfaces are only processed once
1115                         if (surf->worldnodeframe == r_framecount)
1116                                 continue;
1117                         surf->worldnodeframe = r_framecount;
1118                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1119                         {
1120                                 if (surf->flags & SURF_PLANEBACK)
1121                                         surf->visframe = r_framecount;
1122                         }
1123                         else
1124                         {
1125                                 if (!(surf->flags & SURF_PLANEBACK))
1126                                         surf->visframe = r_framecount;
1127                         }
1128                 }
1129                 while (mark < endmark);
1130         }
1131
1132         // follow portals into other leafs
1133         p = leaf->portals;
1134         for (;p;p = p->next)
1135         {
1136                 leaf = p->past;
1137                 if (leaf->worldnodeframe != r_framecount)
1138                 {
1139                         leaf->worldnodeframe = r_framecount;
1140                         if (leaf->contents != CONTENTS_SOLID)
1141                         {
1142                                 i = (leaf - cl.worldmodel->leafs) - 1;
1143                                 if (worldvis[i>>3] & (1<<(i&7)))
1144                                 {
1145                                         if (R_NotCulledBox(leaf->mins, leaf->maxs))
1146                                         {
1147                                                 pstack[portalstack++] = p;
1148                                                 goto loc0;
1149
1150 loc1:
1151                                                 p = pstack[--portalstack];
1152                                         }
1153                                 }
1154                         }
1155                 }
1156         }
1157
1158         if (portalstack)
1159                 goto loc1;
1160
1161         i = 0;
1162         portalstack = 0;
1163         p = r_viewleaf->portals;
1164         for (;p;p = p->next)
1165         {
1166                 portalstack++;
1167                 if (p->past->worldnodeframe != r_framecount)
1168                         i++;
1169         }
1170         if (i)
1171                 Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, portalstack);
1172 }
1173
1174 void R_DrawSurfaces (void)
1175 {
1176         msurface_t      *surf, *endsurf;
1177         texture_t       *t;
1178         int vertex = gl_vertex.value;
1179
1180         surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
1181         endsurf = surf + cl.worldmodel->nummodelsurfaces;
1182         for (;surf < endsurf;surf++)
1183         {
1184                 if (surf->visframe == r_framecount)
1185                 {
1186                         c_faces++;
1187                         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1188                         {
1189                                 // sky and liquid don't need sorting (skypoly/transpoly)
1190                                 if (surf->flags & SURF_DRAWSKY)
1191                                         RSurf_DrawSky(surf, false);
1192                                 else
1193                                         RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1194                         }
1195                         else
1196                         {
1197                                 t = R_TextureAnimation(surf->texinfo->texture);
1198                                 if (vertex)
1199                                         RSurf_DrawWallVertex(surf, t, false, false);
1200                                 else
1201                                         RSurf_DrawWall(surf, t, false);
1202                         }
1203                 }
1204         }
1205 }
1206
1207 void R_DrawPortals(void)
1208 {
1209         int drawportals, i, r, g, b;
1210         mleaf_t *leaf, *endleaf;
1211         mportal_t *portal;
1212         mvertex_t *point, *endpoint;
1213         drawportals = (int)r_drawportals.value;
1214         if (drawportals < 1)
1215                 return;
1216         leaf = cl.worldmodel->leafs;
1217         endleaf = leaf + cl.worldmodel->numleafs;
1218         for (;leaf < endleaf;leaf++)
1219         {
1220                 if (leaf->visframe == r_framecount && leaf->portals)
1221                 {
1222                         i = leaf - cl.worldmodel->leafs;
1223                         r = (i & 0x0007) << 5;
1224                         g = (i & 0x0038) << 2;
1225                         b = (i & 0x01C0) >> 1;
1226                         portal = leaf->portals;
1227                         while (portal)
1228                         {
1229                                 transpolybegin(0, 0, 0, TPOLYTYPE_ALPHA);
1230                                 point = portal->points + portal->numpoints - 1;
1231                                 endpoint = portal->points;
1232                                 for (;point >= endpoint;point--)
1233                                         transpolyvertub(point->position[0], point->position[1], point->position[2], 0, 0, r, g, b, 32);
1234                                 transpolyend();
1235                                 portal = portal->next;
1236                         }
1237                 }
1238         }
1239 }
1240
1241 /*
1242 =============
1243 R_DrawWorld
1244 =============
1245 */
1246 void R_DrawWorld (void)
1247 {
1248         entity_t        ent;
1249
1250         wateralpha = bound(0, r_wateralpha.value*255.0f, 255);
1251
1252         memset (&ent, 0, sizeof(ent));
1253         ent.render.model = cl.worldmodel;
1254         ent.render.colormod[0] = ent.render.colormod[1] = ent.render.colormod[2] = 1;
1255         modelalpha = ent.render.alpha = 1;
1256         ent.render.scale = 1;
1257
1258         VectorCopy (r_origin, modelorg);
1259
1260         currententity = &ent;
1261
1262         softwaretransformidentity(); // LordHavoc: clear transform
1263
1264         if (cl.worldmodel)
1265         {
1266                 if (r_viewleaf->contents == CONTENTS_SOLID)
1267                         R_SolidWorldNode ();
1268                 else
1269                 {
1270                         R_MarkLeaves ();
1271                         R_PortalWorldNode ();
1272                 }
1273         }
1274
1275         R_PushDlights (); // now mark the lit surfaces
1276
1277         R_DrawSurfaces ();
1278
1279         R_DrawPortals ();
1280 }
1281
1282 /*
1283 =============================================================================
1284
1285   LIGHTMAP ALLOCATION
1286
1287 =============================================================================
1288 */
1289
1290 // returns a texture number and the position inside it
1291 int AllocBlock (int w, int h, short *x, short *y)
1292 {
1293         int             i, j;
1294         int             best, best2;
1295         int             texnum;
1296
1297         for (texnum = 0;texnum < MAX_LIGHTMAPS;texnum++)
1298         {
1299                 best = BLOCK_HEIGHT;
1300
1301                 for (i = 0;i < BLOCK_WIDTH - w;i += lightmapalign) // LordHavoc: NVIDIA has broken subimage, so align the lightmaps
1302                 {
1303                         best2 = 0;
1304
1305                         for (j=0 ; j<w ; j++)
1306                         {
1307                                 if (allocated[texnum][i+j] >= best)
1308                                         break;
1309                                 if (allocated[texnum][i+j] > best2)
1310                                         best2 = allocated[texnum][i+j];
1311                         }
1312                         if (j == w)
1313                         {       // this is a valid spot
1314                                 *x = i;
1315                                 *y = best = best2;
1316                         }
1317                 }
1318
1319                 if (best + h > BLOCK_HEIGHT)
1320                         continue;
1321
1322                 if (nosubimagefragments || nosubimage)
1323                 {
1324                         if (!lightmaps[texnum])
1325                         {
1326                                 lightmaps[texnum] = qmalloc(BLOCK_WIDTH*BLOCK_HEIGHT*4);
1327                                 memset(lightmaps[texnum], 0, BLOCK_WIDTH*BLOCK_HEIGHT*4);
1328                         }
1329                 }
1330                 // LordHavoc: clear texture to blank image, fragments are uploaded using subimage
1331                 else if (!allocated[texnum][0])
1332                 {
1333                         byte blank[BLOCK_WIDTH*BLOCK_HEIGHT*4];
1334                         memset(blank, 0, sizeof(blank));
1335                         if(r_upload.value)
1336                         {
1337                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + texnum);
1338                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1339                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1340                                 if (lightmaprgba)
1341                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank);
1342                                 else
1343                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, blank);
1344                         }
1345                 }
1346
1347                 for (i = 0;i < w;i++)
1348                         allocated[texnum][*x + i] = best + h;
1349
1350                 return texnum;
1351         }
1352
1353         Host_Error ("AllocBlock: full, unable to find room for %i by %i lightmap", w, h);
1354         return 0;
1355 }
1356
1357
1358 mvertex_t       *r_pcurrentvertbase;
1359 model_t         *currentmodel;
1360
1361 int     nColinElim;
1362
1363 /*
1364 ================
1365 BuildSurfaceDisplayList
1366 ================
1367 */
1368 void BuildSurfaceDisplayList (msurface_t *fa)
1369 {
1370         int                     i, j, lindex, lnumverts;
1371         medge_t         *pedges, *r_pedge;
1372         int                     vertpage;
1373         float           *vec;
1374         float           s, t;
1375         glpoly_t        *poly;
1376
1377 // reconstruct the polygon
1378         pedges = currentmodel->edges;
1379         lnumverts = fa->numedges;
1380         vertpage = 0;
1381
1382         //
1383         // draw texture
1384         //
1385         poly = Hunk_AllocName (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float), "surfaces");
1386         poly->next = fa->polys;
1387         poly->flags = fa->flags;
1388         fa->polys = poly;
1389         poly->numverts = lnumverts;
1390
1391         for (i=0 ; i<lnumverts ; i++)
1392         {
1393                 lindex = currentmodel->surfedges[fa->firstedge + i];
1394
1395                 if (lindex > 0)
1396                 {
1397                         r_pedge = &pedges[lindex];
1398                         vec = r_pcurrentvertbase[r_pedge->v[0]].position;
1399                 }
1400                 else
1401                 {
1402                         r_pedge = &pedges[-lindex];
1403                         vec = r_pcurrentvertbase[r_pedge->v[1]].position;
1404                 }
1405                 s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1406                 t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1407
1408                 VectorCopy (vec, poly->verts[i]);
1409                 poly->verts[i][3] = s / fa->texinfo->texture->width;
1410                 poly->verts[i][4] = t / fa->texinfo->texture->height;
1411
1412                 //
1413                 // lightmap texture coordinates
1414                 //
1415                 s -= fa->texturemins[0];
1416                 t -= fa->texturemins[1];
1417                 s += 8;
1418                 t += 8;
1419                 // LordHavoc: calc lightmap data offset
1420                 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;
1421                 poly->verts[i][7] = j;
1422                 s += fa->light_s*16;
1423                 s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
1424
1425                 t += fa->light_t*16;
1426                 t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
1427
1428                 poly->verts[i][5] = s;
1429                 poly->verts[i][6] = t;
1430         }
1431
1432         //
1433         // remove co-linear points - Ed
1434         //
1435         /*
1436         if (!gl_keeptjunctions.value)
1437         {
1438                 for (i = 0 ; i < lnumverts ; ++i)
1439                 {
1440                         vec3_t v1, v2;
1441                         float *prev, *this, *next;
1442
1443                         prev = poly->verts[(i + lnumverts - 1) % lnumverts];
1444                         this = poly->verts[i];
1445                         next = poly->verts[(i + 1) % lnumverts];
1446
1447                         VectorSubtract( this, prev, v1 );
1448                         VectorNormalize( v1 );
1449                         VectorSubtract( next, prev, v2 );
1450                         VectorNormalize( v2 );
1451
1452                         // skip co-linear points
1453                         #define COLINEAR_EPSILON 0.001
1454                         if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
1455                                 (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) && 
1456                                 (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
1457                         {
1458                                 int j;
1459                                 for (j = i + 1; j < lnumverts; ++j)
1460                                 {
1461                                         int k;
1462                                         for (k = 0; k < VERTEXSIZE; ++k)
1463                                                 poly->verts[j - 1][k] = poly->verts[j][k];
1464                                 }
1465                                 --lnumverts;
1466                                 ++nColinElim;
1467                                 // retry next vertex next time, which is now current vertex
1468                                 --i;
1469                         }
1470                 }
1471         }
1472         */
1473         poly->numverts = lnumverts;
1474 }
1475
1476 /*
1477 ========================
1478 GL_CreateSurfaceLightmap
1479 ========================
1480 */
1481 void GL_CreateSurfaceLightmap (msurface_t *surf)
1482 {
1483         int             smax, tmax;
1484
1485         if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
1486                 return;
1487
1488         smax = (surf->extents[0]>>4)+1;
1489         tmax = (surf->extents[1]>>4)+1;
1490
1491         surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
1492         if (nosubimage || nosubimagefragments)
1493                 return;
1494         glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum);
1495         smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask;
1496         if (lightmaprgba)
1497         {
1498                 R_BuildLightMap (surf, templight, smax * 4);
1499                 if(r_upload.value)
1500                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
1501         }
1502         else
1503         {
1504                 R_BuildLightMap (surf, templight, smax * 3);
1505                 if(r_upload.value)
1506                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
1507         }
1508 }
1509
1510
1511 /*
1512 ==================
1513 GL_BuildLightmaps
1514
1515 Builds the lightmap texture
1516 with all the surfaces from all brush models
1517 ==================
1518 */
1519 void GL_BuildLightmaps (void)
1520 {
1521         int             i, j;
1522         model_t *m;
1523
1524         memset (allocated, 0, sizeof(allocated));
1525
1526         r_framecount = 1;               // no dlightcache
1527
1528         if (gl_nosubimagefragments.value)
1529                 nosubimagefragments = 1;
1530         else
1531                 nosubimagefragments = 0;
1532
1533         if (gl_nosubimage.value)
1534                 nosubimage = 1;
1535         else
1536                 nosubimage = 0;
1537
1538         if (gl_lightmaprgba.value)
1539         {
1540                 lightmaprgba = true;
1541                 lightmapbytes = 4;
1542         }
1543         else
1544         {
1545                 lightmaprgba = false;
1546                 lightmapbytes = 3;
1547         }
1548
1549         // LordHavoc: NVIDIA seems to have a broken glTexSubImage2D,
1550         //            it needs to be aligned on 4 pixel boundaries...
1551         //            so I implemented an adjustable lightmap alignment
1552         if (gl_lightmapalign.value < 1)
1553                 gl_lightmapalign.value = 1;
1554         if (gl_lightmapalign.value > 16)
1555                 gl_lightmapalign.value = 16;
1556         lightmapalign = 1;
1557         while (lightmapalign < gl_lightmapalign.value)
1558                 lightmapalign <<= 1;
1559         gl_lightmapalign.value = lightmapalign;
1560         lightmapalignmask = ~(lightmapalign - 1);
1561         if (nosubimagefragments || nosubimage)
1562         {
1563                 lightmapalign = 1;
1564                 lightmapalignmask = ~0;
1565         }
1566
1567         if (!lightmap_textures)
1568                 lightmap_textures = R_GetTextureSlots(MAX_LIGHTMAPS);
1569
1570         for (j=1 ; j<MAX_MODELS ; j++)
1571         {
1572                 m = cl.model_precache[j];
1573                 if (!m)
1574                         break;
1575                 if (m->name[0] == '*')
1576                         continue;
1577                 r_pcurrentvertbase = m->vertexes;
1578                 currentmodel = m;
1579                 for (i=0 ; i<m->numsurfaces ; i++)
1580                 {
1581                         if ( m->surfaces[i].flags & SURF_DRAWTURB )
1582                                 continue;
1583                         if ( m->surfaces[i].flags & SURF_DRAWSKY )
1584                                 continue;
1585                         GL_CreateSurfaceLightmap (m->surfaces + i);
1586                         BuildSurfaceDisplayList (m->surfaces + i);
1587                 }
1588         }
1589
1590         if (nosubimage || nosubimagefragments)
1591         {
1592                 if(r_upload.value)
1593                         if (gl_mtexable)
1594                                 qglSelectTexture(gl_mtex_enum+1);
1595                 for (i = 0;i < MAX_LIGHTMAPS;i++)
1596                 {
1597                         if (!allocated[i][0])
1598                                 break;
1599                         lightmapupdate[i][0] = BLOCK_HEIGHT;
1600                         lightmapupdate[i][1] = 0;
1601                         if(r_upload.value)
1602                         {
1603                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
1604                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1605                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1606                                 if (lightmaprgba)
1607                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
1608                                 else
1609                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
1610                         }
1611                 }
1612                 if(r_upload.value)
1613                         if (gl_mtexable)
1614                                 qglSelectTexture(gl_mtex_enum+0);
1615         }
1616 }
1617