]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rsurf.c
e3756c7fa0894f2ef2c8c0f4bba699a9410f9156
[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()
58 {
59 }
60
61 void gl_surf_shutdown()
62 {
63 }
64
65 void gl_surf_newmap()
66 {
67 }
68
69 void GL_Surf_Init()
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 extern  int             solidskytexture;
422 extern  int             alphaskytexture;
423 extern  float   speedscale;             // for top sky and bottom sky
424
425 extern char skyname[];
426
427 float   turbsin[256] =
428 {
429         #include "gl_warp_sin.h"
430 };
431 #define TURBSCALE (256.0 / (2 * M_PI))
432
433
434 void UploadLightmaps()
435 {
436         int i;
437         if (nosubimage || nosubimagefragments)
438         {
439                 for (i = 0;i < MAX_LIGHTMAPS;i++)
440                 {
441                         if (lightmapupdate[i][0] < lightmapupdate[i][1])
442                         {
443                                 if(r_upload.value)
444                                 {
445                                         glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
446                                         if (nosubimage)
447                                         {
448                                                 if (lightmaprgba)
449                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
450                                                 else
451                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
452                                         }
453                                         else
454                                         {
455                                                 if (lightmaprgba)
456                                                         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]));
457                                                 else
458                                                         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]));
459                                         }
460                                 }
461                         }
462                         lightmapupdate[i][0] = BLOCK_HEIGHT;
463                         lightmapupdate[i][1] = 0;
464                 }
465         }
466 }
467
468 float   wvert[1024*6]; // used by the following functions
469
470 void RSurf_DrawSky(msurface_t *s, int transform)
471 {
472         glpoly_t *p;
473         int i;
474         float *v;
475
476         // LordHavoc: HalfLife maps have freaky skypolys...
477         if (hlbsp)
478                 return;
479
480         for (p=s->polys ; p ; p=p->next)
481         {
482                 if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS)
483                 {
484                         skypoly[currentskypoly].firstvert = currentskyvert;
485                         skypoly[currentskypoly++].verts = p->numverts;
486                         if (transform)
487                         {
488                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
489                                 {
490                                         softwaretransform(v, skyvert[currentskyvert].v);
491                                         currentskyvert++;
492                                 }
493                         }
494                         else
495                         {
496                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
497                                 {
498                                         VectorCopy(v, skyvert[currentskyvert].v);
499                                         currentskyvert++;
500                                 }
501                         }
502                 }
503         }
504 }
505
506 int RSurf_Light(int *dlightbits, glpoly_t *polys)
507 {
508         float           cr, cg, cb, radius, radius2, f, *v, *wv;
509         int                     i, a, b, lit = false;
510         unsigned int c, d;
511         dlight_t        *light;
512         vec_t           *lightorigin;
513         glpoly_t        *p;
514         for (a = 0;a < 8;a++)
515         {
516                 if ((c = dlightbits[a]))
517                 {
518                         for (b = 0, d = 1;c;b++, d <<= 1)
519                         {
520                                 if (c & d)
521                                 {
522                                         c -= d;
523                                         light = &cl_dlights[a * 32 + b];
524                                         lightorigin = light->origin;
525                                         cr = light->color[0];
526                                         cg = light->color[1];
527                                         cb = light->color[2];
528                                         radius = light->radius*light->radius;
529                                         radius2 = radius * 256.0f;
530                                         wv = wvert;
531                                         for (p = polys;p;p = p->next)
532                                         {
533                                                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
534                                                 {
535                                                         f = VectorDistance2(wv, lightorigin);
536                                                         if (f < radius)
537                                                         {
538                                                                 f = radius2 / (f + LIGHTOFFSET);
539                                                                 wv[3] += cr * f;
540                                                                 wv[4] += cg * f;
541                                                                 wv[5] += cb * f;
542                                                                 lit = true;
543                                                         }
544                                                         wv += 6;
545                                                 }
546                                         }
547                                 }
548                         }
549                 }
550         }
551         return lit;
552 }
553
554 void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
555 {
556         int             i;
557         float   os = turbsin[(int)(cl.time * TURBSCALE) & 255], ot = turbsin[(int)(cl.time * TURBSCALE + 96.0) & 255];
558         glpoly_t *p;
559         float   *v;
560         // FIXME: make fog texture if water texture is transparent?
561
562         if (s->dlightframe != r_framecount)
563         {
564                 vec3_t temp;
565                 // LordHavoc: fast path for no vertex lighting cases
566                 if (transform)
567                 {
568                         if (r_waterripple.value)
569                         {
570                                 for (p=s->polys ; p ; p=p->next)
571                                 {
572                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
573                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
574                                         {
575                                                 softwaretransform(v, temp);
576                                                 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);
577                                         }
578                                         transpolyend();
579                                 }
580                         }
581                         else
582                         {
583                                 for (p=s->polys ; p ; p=p->next)
584                                 {
585                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
586                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
587                                         {
588                                                 softwaretransform(v, temp);
589                                                 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);
590                                         }
591                                         transpolyend();
592                                 }
593                         }
594                 }
595                 else
596                 {
597                         if (r_waterripple.value)
598                         {
599                                 for (p=s->polys ; p ; p=p->next)
600                                 {
601                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
602                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
603                                                 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);
604                                         transpolyend();
605                                 }
606                         }
607                         else
608                         {
609                                 for (p=s->polys ; p ; p=p->next)
610                                 {
611                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
612                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
613                                                 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);
614                                         transpolyend();
615                                 }
616                         }
617                 }
618         }
619         else
620         {
621                 float *wv;
622                 wv = wvert;
623                 for (p = s->polys;p;p = p->next)
624                 {
625                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
626                         {
627                                 if (transform)
628                                         softwaretransform(v, wv);
629                                 else
630                                         VectorCopy(v, wv);
631                                 if (r_waterripple.value)
632                                         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);
633                                 wv[3] = wv[4] = wv[5] = 128.0f;
634                                 wv += 6;
635                         }
636                 }
637                 if (s->dlightframe == r_framecount)
638                         RSurf_Light(s->dlightbits, s->polys);
639                 wv = wvert;
640                 for (p=s->polys ; p ; p=p->next)
641                 {
642                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
643                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
644                                 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);
645                         transpolyend();
646                 }
647         }
648 }
649
650 void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform)
651 {
652         int             i, lit = false, polys = 0, verts = 0;
653         float   *v;
654         glpoly_t *p;
655         wallpoly_t *wp;
656         wallvert_t *out;
657         wallvertcolor_t *outcolor;
658         // check for lightmap modification
659         if (s->cached_dlight
660          || (r_dynamic.value && r_dlightmap.value && s->dlightframe == r_framecount)
661          || r_ambient.value != s->cached_ambient
662          || lighthalf != s->cached_lighthalf
663          || (r_dynamic.value
664          && ((s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0])
665          || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1])
666          || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2])
667          || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))))
668                 R_UpdateLightmap(s, s->lightmaptexturenum);
669         if (r_dlightmap.value || s->dlightframe != r_framecount)
670         {
671                 // LordHavoc: fast path version for no vertex lighting cases
672                 wp = &wallpoly[currentwallpoly];
673                 out = &wallvert[currentwallvert];
674                 for (p = s->polys;p;p = p->next)
675                 {
676                         if ((currentwallpoly >= MAX_WALLPOLYS) || (currentwallvert+p->numverts > MAX_WALLVERTS))
677                                 return;
678                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
679                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
680                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
681                         wp->firstvert = currentwallvert;
682                         wp->numverts = p->numverts;
683                         wp->lit = lit;
684                         wp++;
685                         currentwallpoly++;
686                         currentwallvert += p->numverts;
687                         v = p->verts[0];
688                         if (transform)
689                         {
690                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
691                                 {
692                                         softwaretransform(v, out->vert);
693                                         out->vert[3] = v[3];
694                                         out->vert[4] = v[4];
695                                         out->vert[5] = v[5];
696                                         out->vert[6] = v[6];
697                                 }
698                         }
699                         else
700                         {
701                                 /*
702                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
703                                 {
704                                         VectorCopy(v, out->vert);
705                                         out->vert[3] = v[3];
706                                         out->vert[4] = v[4];
707                                         out->vert[5] = v[5];
708                                         out->vert[6] = v[6];
709                                 }
710                                 */
711                                 memcpy(out, v, sizeof(vec_t) * VERTEXSIZE * p->numverts);
712                                 out += p->numverts;
713                         }
714                 }
715         }
716         else
717         {
718                 float *wv;
719                 wv = wvert;
720                 for (p = s->polys;p;p = p->next)
721                 {
722                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
723                         {
724                                 if (transform)
725                                         softwaretransform(v, wv);
726                                 else
727                                         VectorCopy(v, wv);
728                                 wv[3] = wv[4] = wv[5] = 0.0f;
729                                 wv += 6;
730                         }
731                         verts += p->numverts;
732                         polys++;
733                 }
734                 if ((currentwallpoly + polys > MAX_WALLPOLYS) || (currentwallvert+verts > MAX_WALLVERTS))
735                         return;
736                 if ((!r_dlightmap.value) && s->dlightframe == r_framecount)
737                         lit = RSurf_Light(s->dlightbits, s->polys);
738                 wv = wvert;
739                 wp = &wallpoly[currentwallpoly];
740                 out = &wallvert[currentwallvert];
741                 outcolor = &wallvertcolor[currentwallvert];
742                 currentwallpoly += polys;
743                 for (p = s->polys;p;p = p->next)
744                 {
745                         v = p->verts[0];
746                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
747                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
748                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
749                         wp->firstvert = currentwallvert;
750                         wp->numverts = p->numverts;
751                         wp->lit = lit;
752                         wp++;
753                         currentwallvert += p->numverts;
754                         for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++, outcolor++)
755                         {
756                                 if (lit)
757                                 {
758                                         if (lighthalf)
759                                         {
760                                                 outcolor->r = (byte) (bound(0, (int) wv[3] >> 1, 255));
761                                                 outcolor->g = (byte) (bound(0, (int) wv[4] >> 1, 255));
762                                                 outcolor->b = (byte) (bound(0, (int) wv[5] >> 1, 255));
763                                                 outcolor->a = 255;
764                                         }
765                                         else
766                                         {
767                                                 outcolor->r = (byte) (bound(0, (int) wv[3], 255));
768                                                 outcolor->g = (byte) (bound(0, (int) wv[4], 255));
769                                                 outcolor->b = (byte) (bound(0, (int) wv[5], 255));
770                                                 outcolor->a = 255;
771                                         }
772                                 }
773                                 out->vert[0] = wv[0];
774                                 out->vert[1] = wv[1];
775                                 out->vert[2] = wv[2];
776                                 out->vert[3] = v[3];
777                                 out->vert[4] = v[4];
778                                 out->vert[5] = v[5];
779                                 out->vert[6] = v[6];
780                         }
781                 }
782         }
783 }
784
785 // LordHavoc: transparent brush models
786 extern float modelalpha;
787
788 void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel)
789 {
790         int i, alpha, size3;
791         float *v, *wv, scale;
792         glpoly_t *p;
793         byte *lm;
794         alpha = (int) (modelalpha * 255.0f);
795         size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
796         wv = wvert;
797         for (p = s->polys;p;p = p->next)
798         {
799                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
800                 {
801                         if (transform)
802                                 softwaretransform(v, wv);
803                         else
804                                 VectorCopy(v, wv);
805                         wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f;
806                         if (s->styles[0] != 255)
807                         {
808                                 lm = (byte *)((long) s->samples + (int) v[7]);
809                                 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;
810                                 if (s->styles[1] != 255)
811                                 {
812                                         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;
813                                         if (s->styles[2] != 255)
814                                         {
815                                                 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;
816                                                 if (s->styles[3] != 255)
817                                                 {
818                                                         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;
819                                                 }
820                                         }
821                                 }
822                         }
823                         wv += 6;
824                 }
825         }
826         if (s->dlightframe == r_framecount)
827                 RSurf_Light(s->dlightbits, s->polys);
828         wv = wvert;
829         if (isbmodel && (currententity->render.colormod[0] != 1 || currententity->render.colormod[1] != 1 || currententity->render.colormod[2] != 1))
830         {
831                 for (p = s->polys;p;p = p->next)
832                 {
833                         v = p->verts[0];
834                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
835                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
836                                 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);
837                         transpolyend();
838                 }
839         }
840         else
841         {
842                 for (p = s->polys;p;p = p->next)
843                 {
844                         v = p->verts[0];
845                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
846                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
847                                 transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha);
848                         transpolyend();
849                 }
850         }
851 }
852
853 void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model);
854
855 /*
856 =================
857 R_DrawBrushModel
858 =================
859 */
860 void R_DrawBrushModel (entity_t *e)
861 {
862         int                     i;
863         vec3_t          mins, maxs;
864         msurface_t      *s;
865         model_t         *clmodel;
866         int     rotated, vertexlit = false;
867         vec3_t          org;
868
869         currententity = e;
870
871         clmodel = e->render.model;
872
873         if (e->render.angles[0] || e->render.angles[1] || e->render.angles[2])
874         {
875                 rotated = true;
876                 for (i=0 ; i<3 ; i++)
877                 {
878                         mins[i] = e->render.origin[i] - clmodel->radius;
879                         maxs[i] = e->render.origin[i] + clmodel->radius;
880                 }
881         }
882         else
883         {
884                 rotated = false;
885                 VectorAdd (e->render.origin, clmodel->mins, mins);
886                 VectorAdd (e->render.origin, clmodel->maxs, maxs);
887         }
888
889         if (R_VisibleCullBox (mins, maxs))
890                 return;
891
892         c_bmodels++;
893
894         VectorSubtract (r_refdef.vieworg, e->render.origin, modelorg);
895         if (rotated)
896         {
897                 vec3_t  temp;
898                 vec3_t  forward, right, up;
899
900                 VectorCopy (modelorg, temp);
901                 AngleVectors (e->render.angles, forward, right, up);
902                 modelorg[0] = DotProduct (temp, forward);
903                 modelorg[1] = -DotProduct (temp, right);
904                 modelorg[2] = DotProduct (temp, up);
905         }
906
907         s = &clmodel->surfaces[clmodel->firstmodelsurface];
908
909 // calculate dynamic lighting for bmodel if it's not an
910 // instanced model
911         for (i = 0;i < MAX_DLIGHTS;i++)
912         {
913                 if (!cl_dlights[i].radius)
914                         continue;
915
916                 VectorSubtract(cl_dlights[i].origin, currententity->render.origin, org);
917                 R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel);
918         }
919         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;
920
921         e->render.angles[0] = -e->render.angles[0];     // stupid quake bug
922         softwaretransformforentity (e);
923         e->render.angles[0] = -e->render.angles[0];     // stupid quake bug
924
925         // draw texture
926         for (i = 0;i < clmodel->nummodelsurfaces;i++, s++)
927         {
928                 if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
929                 {
930 //                      R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent);
931                         if (s->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
932                         {
933                                 // sky and liquid don't need sorting (skypoly/transpoly)
934                                 if (s->flags & SURF_DRAWSKY)
935                                         RSurf_DrawSky(s, true);
936                                 else
937                                         RSurf_DrawWater(s, R_TextureAnimation(s->texinfo->texture), true, s->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
938                         }
939                         else
940                         {
941                                 texture_t *t = R_TextureAnimation(s->texinfo->texture);
942                                 if (vertexlit || s->texinfo->texture->transparent)
943                                         RSurf_DrawWallVertex(s, t, true, true);
944                                 else
945                                         RSurf_DrawWall(s, t, true);
946                         }
947                 }
948         }
949         UploadLightmaps();
950 }
951
952 /*
953 =============================================================
954
955         WORLD MODEL
956
957 =============================================================
958 */
959
960 static byte *worldvis;
961 extern cvar_t r_novis;
962
963 void R_MarkLeaves (void)
964 {
965         static float noviscache;
966         if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
967                 return;
968
969         r_oldviewleaf = r_viewleaf;
970         noviscache = r_novis.value;
971
972         worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
973 }
974
975 void R_SolidWorldNode ()
976 {
977         int l;
978         mleaf_t *leaf;
979         msurface_t *surf, **mark, **endmark;
980
981         for (l = 0, leaf = cl.worldmodel->leafs;l < cl.worldmodel->numleafs;l++, leaf++)
982         {
983                 if (/*leaf->efrags || */leaf->nummarksurfaces)
984                 {
985                         if (R_CullBox(leaf->mins, leaf->maxs))
986                                 continue;
987
988                         c_leafs++;
989
990                         leaf->visframe = r_framecount;
991
992                         // deal with model fragments in this leaf
993 //                      if (leaf->efrags)
994 //                              R_StoreEfrags (&leaf->efrags);
995
996                         if (leaf->nummarksurfaces)
997                         {
998                                 mark = leaf->firstmarksurface;
999                                 endmark = mark + leaf->nummarksurfaces;
1000                                 do
1001                                 {
1002                                         surf = *mark++;
1003                                         // make sure surfaces are only processed once
1004                                         if (surf->worldnodeframe == r_framecount)
1005                                                 continue;
1006                                         surf->worldnodeframe = r_framecount;
1007                                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1008                                         {
1009                                                 if (surf->flags & SURF_PLANEBACK)
1010                                                         surf->visframe = r_framecount;
1011                                         }
1012                                         else
1013                                         {
1014                                                 if (!(surf->flags & SURF_PLANEBACK))
1015                                                         surf->visframe = r_framecount;
1016                                         }
1017                                 }
1018                                 while (mark < endmark);
1019                         }
1020                 }
1021         }
1022 }
1023
1024 /*
1025 // experimental and inferior to the other in recursion depth allowances
1026 void R_PortalWorldNode ()
1027 {
1028         int i, j;
1029         mportal_t *p;
1030         msurface_t *surf, **mark, **endmark;
1031         mleaf_t *leaf, *llistbuffer[8192], **l, **llist;
1032
1033         leaf = r_viewleaf;
1034         leaf->worldnodeframe = r_framecount;
1035         l = llist = &llistbuffer[0];
1036         *llist++ = r_viewleaf;
1037         while (l < llist)
1038         {
1039                 leaf = *l++;
1040
1041                 c_leafs++;
1042
1043                 leaf->visframe = r_framecount;
1044
1045                 // deal with model fragments in this leaf
1046         //      if (leaf->efrags)
1047         //              R_StoreEfrags (&leaf->efrags);
1048
1049                 if (leaf->nummarksurfaces)
1050                 {
1051                         mark = leaf->firstmarksurface;
1052                         endmark = mark + leaf->nummarksurfaces;
1053                         do
1054                         {
1055                                 surf = *mark++;
1056                                 // make sure surfaces are only processed once
1057                                 if (surf->worldnodeframe == r_framecount)
1058                                         continue;
1059                                 surf->worldnodeframe = r_framecount;
1060                                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1061                                 {
1062                                         if (surf->flags & SURF_PLANEBACK)
1063                                                 surf->visframe = r_framecount;
1064                                 }
1065                                 else
1066                                 {
1067                                         if (!(surf->flags & SURF_PLANEBACK))
1068                                                 surf->visframe = r_framecount;
1069                                 }
1070                         }
1071                         while (mark < endmark);
1072                 }
1073
1074                 // follow portals into other leafs
1075                 p = leaf->portals;
1076                 for (;p;p = p->next)
1077                 {
1078                         leaf = p->past;
1079                         if (leaf->worldnodeframe != r_framecount)
1080                         {
1081                                 leaf->worldnodeframe = r_framecount;
1082                                 i = (leaf - cl.worldmodel->leafs) - 1;
1083                                 if ((worldvis[i>>3] & (1<<(i&7))) && R_NotCulledBox(leaf->mins, leaf->maxs))
1084                                         *llist++ = leaf;
1085                         }
1086                 }
1087         }
1088
1089         i = 0;
1090         j = 0;
1091         p = r_viewleaf->portals;
1092         for (;p;p = p->next)
1093         {
1094                 j++;
1095                 if (p->past->worldnodeframe != r_framecount)
1096                         i++;
1097         }
1098         if (i)
1099                 Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, j);
1100 }
1101 */
1102
1103 void R_PortalWorldNode ()
1104 {
1105         int portalstack, i;
1106         mportal_t *p, *pstack[8192];
1107         msurface_t *surf, **mark, **endmark;
1108         mleaf_t *leaf;
1109
1110         leaf = r_viewleaf;
1111         leaf->worldnodeframe = r_framecount;
1112         portalstack = 0;
1113 loc0:
1114         c_leafs++;
1115
1116         leaf->visframe = r_framecount;
1117
1118         // deal with model fragments in this leaf
1119 //      if (leaf->efrags)
1120 //              R_StoreEfrags (&leaf->efrags);
1121
1122         if (leaf->nummarksurfaces)
1123         {
1124                 mark = leaf->firstmarksurface;
1125                 endmark = mark + leaf->nummarksurfaces;
1126                 do
1127                 {
1128                         surf = *mark++;
1129                         // make sure surfaces are only processed once
1130                         if (surf->worldnodeframe == r_framecount)
1131                                 continue;
1132                         surf->worldnodeframe = r_framecount;
1133                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1134                         {
1135                                 if (surf->flags & SURF_PLANEBACK)
1136                                         surf->visframe = r_framecount;
1137                         }
1138                         else
1139                         {
1140                                 if (!(surf->flags & SURF_PLANEBACK))
1141                                         surf->visframe = r_framecount;
1142                         }
1143                 }
1144                 while (mark < endmark);
1145         }
1146
1147         // follow portals into other leafs
1148         p = leaf->portals;
1149         for (;p;p = p->next)
1150         {
1151                 leaf = p->past;
1152                 if (leaf->worldnodeframe != r_framecount)
1153                 {
1154                         leaf->worldnodeframe = r_framecount;
1155                         if (leaf->contents != CONTENTS_SOLID)
1156                         {
1157                                 i = (leaf - cl.worldmodel->leafs) - 1;
1158                                 if (worldvis[i>>3] & (1<<(i&7)))
1159                                 {
1160                                         if (R_NotCulledBox(leaf->mins, leaf->maxs))
1161                                         {
1162                                                 pstack[portalstack++] = p;
1163                                                 goto loc0;
1164
1165 loc1:
1166                                                 p = pstack[--portalstack];
1167                                         }
1168                                 }
1169                         }
1170                 }
1171         }
1172
1173         if (portalstack)
1174                 goto loc1;
1175
1176         i = 0;
1177         portalstack = 0;
1178         p = r_viewleaf->portals;
1179         for (;p;p = p->next)
1180         {
1181                 portalstack++;
1182                 if (p->past->worldnodeframe != r_framecount)
1183                         i++;
1184         }
1185         if (i)
1186                 Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, portalstack);
1187 }
1188
1189 void R_DrawSurfaces (void)
1190 {
1191         msurface_t      *surf, *endsurf;
1192         texture_t       *t;
1193         int vertex = gl_vertex.value;
1194
1195         surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
1196         endsurf = surf + cl.worldmodel->nummodelsurfaces;
1197         for (;surf < endsurf;surf++)
1198         {
1199                 if (surf->visframe == r_framecount)
1200                 {
1201                         c_faces++;
1202                         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1203                         {
1204                                 // sky and liquid don't need sorting (skypoly/transpoly)
1205                                 if (surf->flags & SURF_DRAWSKY)
1206                                         RSurf_DrawSky(surf, false);
1207                                 else
1208                                         RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1209                         }
1210                         else
1211                         {
1212                                 t = R_TextureAnimation(surf->texinfo->texture);
1213                                 if (vertex)
1214                                         RSurf_DrawWallVertex(surf, t, false, false);
1215                                 else
1216                                         RSurf_DrawWall(surf, t, false);
1217                         }
1218                 }
1219         }
1220 }
1221
1222 void R_DrawPortals()
1223 {
1224         int drawportals, i, r, g, b;
1225         mleaf_t *leaf, *endleaf;
1226         mportal_t *portal;
1227         mvertex_t *point, *endpoint;
1228         drawportals = (int)r_drawportals.value;
1229         if (drawportals < 1)
1230                 return;
1231         leaf = cl.worldmodel->leafs;
1232         endleaf = leaf + cl.worldmodel->numleafs;
1233         for (;leaf < endleaf;leaf++)
1234         {
1235                 if (leaf->visframe == r_framecount && leaf->portals)
1236                 {
1237                         i = leaf - cl.worldmodel->leafs;
1238                         r = (i & 0x0007) << 5;
1239                         g = (i & 0x0038) << 2;
1240                         b = (i & 0x01C0) >> 1;
1241                         portal = leaf->portals;
1242                         while (portal)
1243                         {
1244                                 transpolybegin(0, 0, 0, TPOLYTYPE_ALPHA);
1245                                 point = portal->points + portal->numpoints - 1;
1246                                 endpoint = portal->points;
1247                                 for (;point >= endpoint;point--)
1248                                         transpolyvertub(point->position[0], point->position[1], point->position[2], 0, 0, r, g, b, 32);
1249                                 transpolyend();
1250                                 portal = portal->next;
1251                         }
1252                 }
1253         }
1254 }
1255
1256 /*
1257 =============
1258 R_DrawWorld
1259 =============
1260 */
1261 void R_DrawWorld (void)
1262 {
1263         entity_t        ent;
1264
1265         wateralpha = bound(0, r_wateralpha.value*255.0f, 255);
1266
1267         memset (&ent, 0, sizeof(ent));
1268         ent.render.model = cl.worldmodel;
1269         ent.render.colormod[0] = ent.render.colormod[1] = ent.render.colormod[2] = 1;
1270         modelalpha = ent.render.alpha = 1;
1271         ent.render.scale = 1;
1272
1273         VectorCopy (r_refdef.vieworg, modelorg);
1274
1275         currententity = &ent;
1276
1277         softwaretransformidentity(); // LordHavoc: clear transform
1278
1279         if (cl.worldmodel)
1280         {
1281                 if (r_viewleaf->contents == CONTENTS_SOLID)
1282                         R_SolidWorldNode ();
1283                 else
1284                 {
1285                         R_MarkLeaves ();
1286                         R_PortalWorldNode ();
1287                 }
1288         }
1289
1290         R_PushDlights (); // now mark the lit surfaces
1291
1292         R_DrawSurfaces ();
1293
1294         R_DrawPortals ();
1295 }
1296
1297 /*
1298 =============================================================================
1299
1300   LIGHTMAP ALLOCATION
1301
1302 =============================================================================
1303 */
1304
1305 // returns a texture number and the position inside it
1306 int AllocBlock (int w, int h, short *x, short *y)
1307 {
1308         int             i, j;
1309         int             best, best2;
1310         int             texnum;
1311
1312         for (texnum = 0;texnum < MAX_LIGHTMAPS;texnum++)
1313         {
1314                 best = BLOCK_HEIGHT;
1315
1316                 for (i = 0;i < BLOCK_WIDTH - w;i += lightmapalign) // LordHavoc: NVIDIA has broken subimage, so align the lightmaps
1317                 {
1318                         best2 = 0;
1319
1320                         for (j=0 ; j<w ; j++)
1321                         {
1322                                 if (allocated[texnum][i+j] >= best)
1323                                         break;
1324                                 if (allocated[texnum][i+j] > best2)
1325                                         best2 = allocated[texnum][i+j];
1326                         }
1327                         if (j == w)
1328                         {       // this is a valid spot
1329                                 *x = i;
1330                                 *y = best = best2;
1331                         }
1332                 }
1333
1334                 if (best + h > BLOCK_HEIGHT)
1335                         continue;
1336
1337                 if (nosubimagefragments || nosubimage)
1338                 {
1339                         if (!lightmaps[texnum])
1340                         {
1341                                 lightmaps[texnum] = qmalloc(BLOCK_WIDTH*BLOCK_HEIGHT*4);
1342                                 memset(lightmaps[texnum], 0, BLOCK_WIDTH*BLOCK_HEIGHT*4);
1343                         }
1344                 }
1345                 // LordHavoc: clear texture to blank image, fragments are uploaded using subimage
1346                 else if (!allocated[texnum][0])
1347                 {
1348                         byte blank[BLOCK_WIDTH*BLOCK_HEIGHT*4];
1349                         memset(blank, 0, sizeof(blank));
1350                         if(r_upload.value)
1351                         {
1352                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + texnum);
1353                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1354                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1355                                 if (lightmaprgba)
1356                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank);
1357                                 else
1358                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, blank);
1359                         }
1360                 }
1361
1362                 for (i = 0;i < w;i++)
1363                         allocated[texnum][*x + i] = best + h;
1364
1365                 return texnum;
1366         }
1367
1368         Host_Error ("AllocBlock: full, unable to find room for %i by %i lightmap", w, h);
1369         return 0;
1370 }
1371
1372
1373 mvertex_t       *r_pcurrentvertbase;
1374 model_t         *currentmodel;
1375
1376 int     nColinElim;
1377
1378 /*
1379 ================
1380 BuildSurfaceDisplayList
1381 ================
1382 */
1383 void BuildSurfaceDisplayList (msurface_t *fa)
1384 {
1385         int                     i, j, lindex, lnumverts;
1386         medge_t         *pedges, *r_pedge;
1387         int                     vertpage;
1388         float           *vec;
1389         float           s, t;
1390         glpoly_t        *poly;
1391
1392 // reconstruct the polygon
1393         pedges = currentmodel->edges;
1394         lnumverts = fa->numedges;
1395         vertpage = 0;
1396
1397         //
1398         // draw texture
1399         //
1400         poly = Hunk_AllocName (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float), "surfaces");
1401         poly->next = fa->polys;
1402         poly->flags = fa->flags;
1403         fa->polys = poly;
1404         poly->numverts = lnumverts;
1405
1406         for (i=0 ; i<lnumverts ; i++)
1407         {
1408                 lindex = currentmodel->surfedges[fa->firstedge + i];
1409
1410                 if (lindex > 0)
1411                 {
1412                         r_pedge = &pedges[lindex];
1413                         vec = r_pcurrentvertbase[r_pedge->v[0]].position;
1414                 }
1415                 else
1416                 {
1417                         r_pedge = &pedges[-lindex];
1418                         vec = r_pcurrentvertbase[r_pedge->v[1]].position;
1419                 }
1420                 s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1421                 t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1422
1423                 VectorCopy (vec, poly->verts[i]);
1424                 poly->verts[i][3] = s / fa->texinfo->texture->width;
1425                 poly->verts[i][4] = t / fa->texinfo->texture->height;
1426
1427                 //
1428                 // lightmap texture coordinates
1429                 //
1430                 s -= fa->texturemins[0];
1431                 t -= fa->texturemins[1];
1432                 s += 8;
1433                 t += 8;
1434                 // LordHavoc: calc lightmap data offset
1435                 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;
1436                 poly->verts[i][7] = j;
1437                 s += fa->light_s*16;
1438                 s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
1439
1440                 t += fa->light_t*16;
1441                 t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
1442
1443                 poly->verts[i][5] = s;
1444                 poly->verts[i][6] = t;
1445         }
1446
1447         //
1448         // remove co-linear points - Ed
1449         //
1450         /*
1451         if (!gl_keeptjunctions.value)
1452         {
1453                 for (i = 0 ; i < lnumverts ; ++i)
1454                 {
1455                         vec3_t v1, v2;
1456                         float *prev, *this, *next;
1457
1458                         prev = poly->verts[(i + lnumverts - 1) % lnumverts];
1459                         this = poly->verts[i];
1460                         next = poly->verts[(i + 1) % lnumverts];
1461
1462                         VectorSubtract( this, prev, v1 );
1463                         VectorNormalize( v1 );
1464                         VectorSubtract( next, prev, v2 );
1465                         VectorNormalize( v2 );
1466
1467                         // skip co-linear points
1468                         #define COLINEAR_EPSILON 0.001
1469                         if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
1470                                 (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) && 
1471                                 (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
1472                         {
1473                                 int j;
1474                                 for (j = i + 1; j < lnumverts; ++j)
1475                                 {
1476                                         int k;
1477                                         for (k = 0; k < VERTEXSIZE; ++k)
1478                                                 poly->verts[j - 1][k] = poly->verts[j][k];
1479                                 }
1480                                 --lnumverts;
1481                                 ++nColinElim;
1482                                 // retry next vertex next time, which is now current vertex
1483                                 --i;
1484                         }
1485                 }
1486         }
1487         */
1488         poly->numverts = lnumverts;
1489 }
1490
1491 /*
1492 ========================
1493 GL_CreateSurfaceLightmap
1494 ========================
1495 */
1496 void GL_CreateSurfaceLightmap (msurface_t *surf)
1497 {
1498         int             smax, tmax;
1499
1500         if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
1501                 return;
1502
1503         smax = (surf->extents[0]>>4)+1;
1504         tmax = (surf->extents[1]>>4)+1;
1505
1506         surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
1507         if (nosubimage || nosubimagefragments)
1508                 return;
1509         glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum);
1510         smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask;
1511         if (lightmaprgba)
1512         {
1513                 R_BuildLightMap (surf, templight, smax * 4);
1514                 if(r_upload.value)
1515                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
1516         }
1517         else
1518         {
1519                 R_BuildLightMap (surf, templight, smax * 3);
1520                 if(r_upload.value)
1521                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
1522         }
1523 }
1524
1525
1526 /*
1527 ==================
1528 GL_BuildLightmaps
1529
1530 Builds the lightmap texture
1531 with all the surfaces from all brush models
1532 ==================
1533 */
1534 void GL_BuildLightmaps (void)
1535 {
1536         int             i, j;
1537         model_t *m;
1538
1539         memset (allocated, 0, sizeof(allocated));
1540
1541         r_framecount = 1;               // no dlightcache
1542
1543         if (gl_nosubimagefragments.value)
1544                 nosubimagefragments = 1;
1545         else
1546                 nosubimagefragments = 0;
1547
1548         if (gl_nosubimage.value)
1549                 nosubimage = 1;
1550         else
1551                 nosubimage = 0;
1552
1553         if (gl_lightmaprgba.value)
1554         {
1555                 lightmaprgba = true;
1556                 lightmapbytes = 4;
1557         }
1558         else
1559         {
1560                 lightmaprgba = false;
1561                 lightmapbytes = 3;
1562         }
1563
1564         // LordHavoc: NVIDIA seems to have a broken glTexSubImage2D,
1565         //            it needs to be aligned on 4 pixel boundaries...
1566         //            so I implemented an adjustable lightmap alignment
1567         if (gl_lightmapalign.value < 1)
1568                 gl_lightmapalign.value = 1;
1569         if (gl_lightmapalign.value > 16)
1570                 gl_lightmapalign.value = 16;
1571         lightmapalign = 1;
1572         while (lightmapalign < gl_lightmapalign.value)
1573                 lightmapalign <<= 1;
1574         gl_lightmapalign.value = lightmapalign;
1575         lightmapalignmask = ~(lightmapalign - 1);
1576         if (nosubimagefragments || nosubimage)
1577         {
1578                 lightmapalign = 1;
1579                 lightmapalignmask = ~0;
1580         }
1581
1582         if (!lightmap_textures)
1583                 lightmap_textures = R_GetTextureSlots(MAX_LIGHTMAPS);
1584
1585         for (j=1 ; j<MAX_MODELS ; j++)
1586         {
1587                 m = cl.model_precache[j];
1588                 if (!m)
1589                         break;
1590                 if (m->name[0] == '*')
1591                         continue;
1592                 r_pcurrentvertbase = m->vertexes;
1593                 currentmodel = m;
1594                 for (i=0 ; i<m->numsurfaces ; i++)
1595                 {
1596                         if ( m->surfaces[i].flags & SURF_DRAWTURB )
1597                                 continue;
1598                         if ( m->surfaces[i].flags & SURF_DRAWSKY )
1599                                 continue;
1600                         GL_CreateSurfaceLightmap (m->surfaces + i);
1601                         BuildSurfaceDisplayList (m->surfaces + i);
1602                 }
1603         }
1604
1605         if (nosubimage || nosubimagefragments)
1606         {
1607                 if(r_upload.value)
1608                         if (gl_mtexable)
1609                                 qglSelectTexture(gl_mtex_enum+1);
1610                 for (i = 0;i < MAX_LIGHTMAPS;i++)
1611                 {
1612                         if (!allocated[i][0])
1613                                 break;
1614                         lightmapupdate[i][0] = BLOCK_HEIGHT;
1615                         lightmapupdate[i][1] = 0;
1616                         if(r_upload.value)
1617                         {
1618                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
1619                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1620                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1621                                 if (lightmaprgba)
1622                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
1623                                 else
1624                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
1625                         }
1626                 }
1627                 if(r_upload.value)
1628                         if (gl_mtexable)
1629                                 qglSelectTexture(gl_mtex_enum+0);
1630         }
1631 }
1632