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