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