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