2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // r_surf.c: surface-related refresh code
24 int lightmap_textures;
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)
35 short allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
37 byte *lightmaps[MAX_LIGHTMAPS];
38 short lightmapupdate[MAX_LIGHTMAPS][2];
40 signed int blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; // LordHavoc: *3 for colored lighting
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"};
56 qboolean lightmaprgba, nosubimagefragments, nosubimage;
65 void gl_surf_shutdown()
76 for (i = 0;i < MAX_LIGHTMAPS;i++)
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);
91 R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
94 int dlightdivtable[32768];
99 int R_AddDynamicLights (msurface_t *surf)
101 int sdtable[18], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, red, green, blue, lit, dist2, impacts, impactt;
104 vec3_t impact, local;
106 // LordHavoc: use 64bit integer... shame it's not very standardized...
107 #if _MSC_VER || __BORLANDC__
115 if (!dlightdivtable[1])
117 dlightdivtable[0] = 4194304;
118 for (s = 1; s < 32768; s++)
119 dlightdivtable[s] = 4194304 / (s << 7);
122 smax = (surf->extents[0] >> 4) + 1;
123 tmax = (surf->extents[1] >> 4) + 1;
125 for (lnum = 0; lnum < MAX_DLIGHTS; lnum++)
127 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
128 continue; // not lit by this light
130 VectorSubtract (cl_dlights[lnum].origin, currententity->render.origin, local);
131 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
133 // for comparisons to minimum acceptable light
134 maxdist = (int) ((cl_dlights[lnum].radius * cl_dlights[lnum].radius));
136 // clamp radius to avoid exceeding 32768 entry division table
137 if (maxdist > 4194304)
141 if (dist2 >= maxdist)
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;
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];
151 s = bound(0, impacts, smax * 16) - impacts;
152 t = bound(0, impactt, tmax * 16) - impactt;
153 i = s * s + t * t + dist2;
157 // reduce calculations
158 for (s = 0, i = impacts; s < smax; s++, i -= 16)
159 sdtable[s] = i * i + dist2 + LIGHTOFFSET;
161 maxdist3 = maxdist - (int) (dist * dist);
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;
170 for (t = 0; t < tmax; t++, i -= 16)
173 // make sure some part of it is visible on this line
176 maxdist2 = maxdist - td;
177 for (s = 0; s < smax; s++)
179 if (sdtable[s] < maxdist2)
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;
198 void R_ConvertLightmap (int *in, byte *out, int width, int height, int stride)
201 stride -= (width*lightmapbytes);
204 // LordHavoc: I shift down by 8 unlike GLQuake's 7,
205 // the image is brightened as a processing pass
208 for (i = 0;i < height;i++, out += stride)
210 for (j = 0;j < width;j++, in += 3, out += 4)
212 out[0] = min(in[0] >> 8, 255);
213 out[1] = min(in[1] >> 8, 255);
214 out[2] = min(in[2] >> 8, 255);
221 for (i = 0;i < height;i++, out += stride)
223 for (j = 0;j < width;j++, in += 3, out += 3)
225 out[0] = min(in[0] >> 8, 255);
226 out[1] = min(in[1] >> 8, 255);
227 out[2] = min(in[2] >> 8, 255);
236 for (i = 0;i < height;i++, out += stride)
238 for (j = 0;j < width;j++, in += 3, out += 4)
240 out[0] = min(in[0] >> 7, 255);
241 out[1] = min(in[1] >> 7, 255);
242 out[2] = min(in[2] >> 7, 255);
249 for (i = 0;i < height;i++, out += stride)
251 for (j = 0;j < width;j++, in += 3, out += 3)
253 out[0] = min(in[0] >> 7, 255);
254 out[1] = min(in[1] >> 7, 255);
255 out[2] = min(in[2] >> 7, 255);
266 Combine and scale multiple lightmaps into the 8.8 format in blocklights
269 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
272 int i, j, size, size3;
278 surf->cached_dlight = 0;
279 surf->cached_lighthalf = lighthalf;
280 surf->cached_ambient = r_ambient.value;
282 smax = (surf->extents[0]>>4)+1;
283 tmax = (surf->extents[1]>>4)+1;
286 lightmap = surf->samples;
288 // set to full bright if no light data
289 if ((currententity && (currententity->render.effects & EF_FULLBRIGHT)) || !cl.worldmodel->lightdata)
292 for (i=0 ; i<size ; i++)
302 j = r_ambient.value * 512.0f; // would be 256.0f logically, but using 512.0f to match winquake style
306 for (i = 0;i < size3;i++)
310 memset(&blocklights[0], 0, size*3*sizeof(int));
312 // add all the lightmaps
315 for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
317 scale = d_lightstylevalue[surf->styles[maps]];
318 surf->cached_light[maps] = scale; // 8.8 fraction
320 for (i = 0;i < size3;i++)
321 *bl++ += *lightmap++ * scale;
324 if (r_dlightmap.value && surf->dlightframe == r_framecount)
325 if ((surf->cached_dlight = R_AddDynamicLights(surf)))
328 R_ConvertLightmap(blocklights, dest, smax, tmax, stride);
331 byte templight[BLOCK_WIDTH*BLOCK_HEIGHT*4];
333 void R_UpdateLightmap(msurface_t *s, int lnum)
336 // upload the new lightmap texture fragment
338 glBindTexture(GL_TEXTURE_2D, lightmap_textures + lnum);
339 if (nosubimage || nosubimagefragments)
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));
346 R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 4, BLOCK_WIDTH * 4);
348 R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 3, BLOCK_WIDTH * 3);
352 smax = ((s->extents[0]>>4)+lightmapalign) & lightmapalignmask;
353 tmax = (s->extents[1]>>4)+1;
356 R_BuildLightMap (s, templight, smax * 4);
358 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
362 R_BuildLightMap (s, templight, smax * 3);
364 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
374 Returns the proper texture for a given time and base texture
377 texture_t *R_TextureAnimation (texture_t *base)
379 // texture_t *original;
383 if (currententity->render.frame)
385 if (base->alternate_anims)
386 base = base->alternate_anims;
389 if (!base->anim_total)
392 return base->anim_frames[(int)(cl.time*5) % base->anim_total];
397 relative = (int)(cl.time*5) % base->anim_total;
400 while (base->anim_min > relative || base->anim_max <= relative)
402 base = base->anim_next;
405 Con_Printf("R_TextureAnimation: broken cycle");
410 Con_Printf("R_TextureAnimation: infinite cycle");
421 =============================================================
425 =============================================================
429 extern int solidskytexture;
430 extern int alphaskytexture;
431 extern float speedscale; // for top sky and bottom sky
433 extern char skyname[];
437 #include "gl_warp_sin.h"
439 #define TURBSCALE (256.0 / (2 * M_PI))
442 void UploadLightmaps()
445 if (nosubimage || nosubimagefragments)
447 for (i = 0;i < MAX_LIGHTMAPS;i++)
449 if (lightmapupdate[i][0] < lightmapupdate[i][1])
453 glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
457 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
459 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
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]));
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]));
470 lightmapupdate[i][0] = BLOCK_HEIGHT;
471 lightmapupdate[i][1] = 0;
476 float wvert[1024*6]; // used by the following functions
478 extern qboolean hlbsp;
480 void RSurf_DrawSky(msurface_t *s, int transform)
486 // LordHavoc: HalfLife maps have freaky skypolys...
490 for (p=s->polys ; p ; p=p->next)
492 if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS)
494 skypoly[currentskypoly].firstvert = currentskyvert;
495 skypoly[currentskypoly++].verts = p->numverts;
498 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
500 softwaretransform(v, skyvert[currentskyvert].v);
506 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
508 VectorCopy(v, skyvert[currentskyvert].v);
516 int RSurf_Light(int *dlightbits, glpoly_t *polys)
518 float cr, cg, cb, radius, radius2, f, *v, *wv;
519 int i, a, b, lit = false;
524 for (a = 0;a < 8;a++)
526 if ((c = dlightbits[a]))
528 for (b = 0, d = 1;c;b++, d <<= 1)
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;
541 for (p = polys;p;p = p->next)
543 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
545 f = VectorDistance2(wv, lightorigin);
548 f = radius2 / (f + LIGHTOFFSET);
564 void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
567 float os = turbsin[(int)(cl.time * TURBSCALE) & 255], ot = turbsin[(int)(cl.time * TURBSCALE + 96.0) & 255];
570 // FIXME: make fog texture if water texture is transparent?
572 if (s->dlightframe != r_framecount)
575 // LordHavoc: fast path for no vertex lighting cases
578 if (r_waterripple.value)
580 for (p=s->polys ; p ; p=p->next)
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)
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);
593 for (p=s->polys ; p ; p=p->next)
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)
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);
607 if (r_waterripple.value)
609 for (p=s->polys ; p ; p=p->next)
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);
619 for (p=s->polys ; p ; p=p->next)
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);
633 for (p = s->polys;p;p = p->next)
635 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
638 softwaretransform(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;
647 if (s->dlightframe == r_framecount)
648 RSurf_Light(s->dlightbits, s->polys);
650 for (p=s->polys ; p ; p=p->next)
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);
660 void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform)
662 int i, lit = false, polys = 0, verts = 0;
667 wallvertcolor_t *outcolor;
668 // check for lightmap modification
670 || (r_dynamic.value && r_dlightmap.value && s->dlightframe == r_framecount)
671 || r_ambient.value != s->cached_ambient
672 || lighthalf != s->cached_lighthalf
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)
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)
686 if ((currentwallpoly >= MAX_WALLPOLYS) || (currentwallvert+p->numverts > MAX_WALLVERTS))
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;
696 currentwallvert += p->numverts;
700 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
702 softwaretransform(v, out->vert);
712 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
714 VectorCopy(v, out->vert);
721 memcpy(out, v, sizeof(vec_t) * VERTEXSIZE * p->numverts);
730 for (p = s->polys;p;p = p->next)
732 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
735 softwaretransform(v, wv);
738 wv[3] = wv[4] = wv[5] = 0.0f;
741 verts += p->numverts;
744 if ((currentwallpoly + polys > MAX_WALLPOLYS) || (currentwallvert+verts > MAX_WALLVERTS))
746 if ((!r_dlightmap.value) && s->dlightframe == r_framecount)
747 lit = RSurf_Light(s->dlightbits, s->polys);
749 wp = &wallpoly[currentwallpoly];
750 out = &wallvert[currentwallvert];
751 outcolor = &wallvertcolor[currentwallvert];
752 currentwallpoly += polys;
753 for (p = s->polys;p;p = p->next)
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;
763 currentwallvert += p->numverts;
764 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++, outcolor++)
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));
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));
783 out->vert[0] = wv[0];
784 out->vert[1] = wv[1];
785 out->vert[2] = wv[2];
795 // LordHavoc: transparent brush models
796 extern float modelalpha;
798 void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel)
801 float *v, *wv, scale;
804 alpha = (int) (modelalpha * 255.0f);
805 size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
807 for (p = s->polys;p;p = p->next)
809 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
812 softwaretransform(v, wv);
815 wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f;
816 if (s->styles[0] != 255)
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)
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)
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)
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;
836 if (s->dlightframe == r_framecount)
837 RSurf_Light(s->dlightbits, s->polys);
839 if (isbmodel && (currententity->render.colormod[0] != 1 || currententity->render.colormod[1] != 1 || currententity->render.colormod[2] != 1))
841 for (p = s->polys;p;p = p->next)
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);
852 for (p = s->polys;p;p = p->next)
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);
863 void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model);
870 void R_DrawBrushModel (entity_t *e)
876 int rotated, vertexlit = false;
881 clmodel = e->render.model;
883 if (e->render.angles[0] || e->render.angles[1] || e->render.angles[2])
886 for (i=0 ; i<3 ; i++)
888 mins[i] = e->render.origin[i] - clmodel->radius;
889 maxs[i] = e->render.origin[i] + clmodel->radius;
895 VectorAdd (e->render.origin, clmodel->mins, mins);
896 VectorAdd (e->render.origin, clmodel->maxs, maxs);
899 if (R_VisibleCullBox (mins, maxs))
904 VectorSubtract (r_refdef.vieworg, e->render.origin, modelorg);
908 vec3_t forward, right, up;
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);
917 s = &clmodel->surfaces[clmodel->firstmodelsurface];
919 // calculate dynamic lighting for bmodel if it's not an
921 for (i = 0;i < MAX_DLIGHTS;i++)
923 if (!cl_dlights[i].radius)
926 VectorSubtract(cl_dlights[i].origin, currententity->render.origin, org);
927 R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel);
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;
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
936 for (i = 0;i < clmodel->nummodelsurfaces;i++, s++)
938 if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
940 // R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent);
941 if (s->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
943 // sky and liquid don't need sorting (skypoly/transpoly)
944 if (s->flags & SURF_DRAWSKY)
945 RSurf_DrawSky(s, true);
947 RSurf_DrawWater(s, R_TextureAnimation(s->texinfo->texture), true, s->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
951 texture_t *t = R_TextureAnimation(s->texinfo->texture);
952 if (vertexlit || s->texinfo->texture->transparent)
953 RSurf_DrawWallVertex(s, t, true, true);
955 RSurf_DrawWall(s, t, true);
963 =============================================================
967 =============================================================
970 int r_vismarkframecount; // bumped when going to a new PVS
972 void R_MarkLeaves (void)
978 if (r_oldviewleaf == r_viewleaf)
981 r_vismarkframecount++;
982 r_oldviewleaf = r_viewleaf;
984 vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
986 for (i = 0;i < cl.worldmodel->numleafs;i++)
988 if (vis[i>>3] & (1<<(i&7)))
990 node = (mnode_t *)&cl.worldmodel->leafs[i+1];
993 if (node->vismarkframe == r_vismarkframecount)
995 node->vismarkframe = r_vismarkframecount;
1002 void R_LeafWorldNode ()
1006 msurface_t *surf, **mark, **endmark;
1008 for (l = 0, leaf = cl.worldmodel->leafs;l < cl.worldmodel->numleafs;l++, leaf++)
1010 if ((leaf->vismarkframe == r_vismarkframecount) && (/*leaf->efrags || */leaf->nummarksurfaces))
1012 if (R_CullBox(leaf->mins, leaf->maxs))
1017 leaf->visframe = r_framecount;
1019 // deal with model fragments in this leaf
1020 // if (leaf->efrags)
1021 // R_StoreEfrags (&leaf->efrags);
1023 if (leaf->nummarksurfaces)
1025 mark = leaf->firstmarksurface;
1026 endmark = mark + leaf->nummarksurfaces;
1030 // make sure surfaces are only processed once
1031 if (surf->worldnodeframe == r_framecount)
1033 surf->worldnodeframe = r_framecount;
1034 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1036 if (surf->flags & SURF_PLANEBACK)
1037 surf->visframe = r_framecount;
1041 if (!(surf->flags & SURF_PLANEBACK))
1042 surf->visframe = r_framecount;
1045 while (mark < endmark);
1051 typedef struct nodestack_s
1053 unsigned short side, clip;
1058 void R_NoVisWorldNode ()
1061 nodestack_t *nstack, nodestack[8192];
1064 msurface_t *surf, *endsurf, **mark, **endmark;
1067 node = cl.worldmodel->nodes;
1075 if (node->contents < 0)
1077 if (node->contents != CONTENTS_SOLID && R_NotCulledBox(node->mins, node->maxs))
1079 // mark surfaces as being visible for processing by code later
1080 pleaf = (mleaf_t *)node;
1084 pleaf->visframe = r_framecount;
1086 if (pleaf->nummarksurfaces)
1088 mark = pleaf->firstmarksurface;
1089 endmark = mark + pleaf->nummarksurfaces;
1091 (*mark++)->visframe = r_framecount;
1092 while (mark < endmark);
1095 // deal with model fragments in this leaf
1096 // if (pleaf->efrags)
1097 // R_StoreEfrags (&pleaf->efrags);
1101 if (nstack <= nodestack)
1104 node = nstack->node;
1105 side = nstack->side;
1106 clip = nstack->clip;
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
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
1131 // node is just a decision point, so go down the apropriate sides
1133 // find which side of the node we are on
1134 side = PlaneDist(modelorg, node->plane) < node->plane->dist;
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;
1141 node = node->children[side];
1146 if (node->numsurfaces)
1148 surf = cl.worldmodel->surfaces + node->firstsurface;
1149 endsurf = surf + node->numsurfaces;
1153 for (;surf < endsurf;surf++)
1154 if (surf->flags & SURF_PLANEBACK)
1155 surf->visframe = -1;
1159 for (;surf < endsurf;surf++)
1160 if (!(surf->flags & SURF_PLANEBACK))
1161 surf->visframe = -1;
1165 // recurse down the back side
1166 node = node->children[side];
1171 void R_BSPWorldNode ()
1173 int side, c, clip/*, oldclip = r_oldclip.value*/;
1174 nodestack_t *nstack, nodestack[8192];
1177 msurface_t *surf, *endsurf, **mark, **endmark;
1180 node = cl.worldmodel->nodes;
1188 if (node->contents < 0)
1190 if (node->contents != CONTENTS_SOLID && R_NotCulledBox(node->mins, node->maxs))
1192 // mark surfaces as being visible for processing by code later
1193 pleaf = (mleaf_t *)node;
1197 pleaf->visframe = r_framecount;
1199 if (pleaf->nummarksurfaces)
1201 mark = pleaf->firstmarksurface;
1202 endmark = mark + pleaf->nummarksurfaces;
1204 (*mark++)->visframe = r_framecount;
1205 while (mark < endmark);
1208 // deal with model fragments in this leaf
1209 // if (pleaf->efrags)
1210 // R_StoreEfrags (&pleaf->efrags);
1214 if (nstack <= nodestack)
1217 node = nstack->node;
1218 side = nstack->side;
1219 clip = nstack->clip;
1225 if (R_CullBox(node->mins, node->maxs))
1227 if (nstack <= nodestack)
1230 node = nstack->node;
1231 side = nstack->side;
1232 clip = nstack->clip;
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
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
1259 // node is just a decision point, so go down the apropriate sides
1261 // find which side of the node we are on
1262 side = PlaneDist(modelorg, node->plane) < node->plane->dist;
1264 // recurse down the children, front side first
1265 if (node->children[side]->vismarkframe == r_vismarkframecount)
1267 nstack->node = node;
1268 nstack->side = !side; // go down back side when we come back up
1269 nstack->clip = clip;
1271 node = node->children[side];
1278 if (node->numsurfaces)
1280 surf = cl.worldmodel->surfaces + node->firstsurface;
1281 endsurf = surf + node->numsurfaces;
1285 for (;surf < endsurf;surf++)
1286 if (surf->flags & SURF_PLANEBACK)
1287 surf->visframe = -1;
1291 for (;surf < endsurf;surf++)
1292 if (!(surf->flags & SURF_PLANEBACK))
1293 surf->visframe = -1;
1297 // recurse down the back side
1298 if (node->children[side]->vismarkframe == r_vismarkframecount)
1300 node = node->children[side];
1304 if (nstack <= nodestack)
1307 node = nstack->node;
1308 side = nstack->side;
1309 clip = nstack->clip;
1314 void R_PortalWorldNode ()
1317 mportal_t *p, *pstack[8192];
1318 msurface_t *surf, **mark, **endmark;
1326 leaf->visframe = r_framecount;
1328 // deal with model fragments in this leaf
1329 // if (leaf->efrags)
1330 // R_StoreEfrags (&leaf->efrags);
1332 if (leaf->nummarksurfaces)
1334 mark = leaf->firstmarksurface;
1335 endmark = mark + leaf->nummarksurfaces;
1339 // make sure surfaces are only processed once
1340 if (surf->worldnodeframe == r_framecount)
1342 surf->worldnodeframe = r_framecount;
1343 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1345 if (surf->flags & SURF_PLANEBACK)
1346 surf->visframe = r_framecount;
1350 if (!(surf->flags & SURF_PLANEBACK))
1351 surf->visframe = r_framecount;
1354 while (mark < endmark);
1357 // follow portals into other leafs
1358 for (p = leaf->portals;p;p = p->next)
1360 if (p->past->worldnodeframe != r_framecount)
1363 leaf->worldnodeframe = r_framecount;
1364 if (leaf->contents != CONTENTS_SOLID && leaf->vismarkframe == r_vismarkframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
1366 pstack[portalstack++] = p;
1375 p = pstack[--portalstack];
1380 void R_DrawSurfaces (void)
1382 msurface_t *surf, *endsurf;
1384 int vertex = gl_vertex.value;
1386 surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
1387 endsurf = surf + cl.worldmodel->nummodelsurfaces;
1388 for (;surf < endsurf;surf++)
1390 if (surf->visframe == r_framecount)
1393 if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1395 // sky and liquid don't need sorting (skypoly/transpoly)
1396 if (surf->flags & SURF_DRAWSKY)
1397 RSurf_DrawSky(surf, false);
1399 RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1403 t = R_TextureAnimation(surf->texinfo->texture);
1405 RSurf_DrawWallVertex(surf, t, false, false);
1407 RSurf_DrawWall(surf, t, false);
1413 void R_DrawPortals()
1415 int drawportals, i, r, g, b;
1416 mleaf_t *leaf, *endleaf;
1418 mvertex_t *point, *endpoint;
1419 drawportals = (int)r_drawportals.value;
1420 if (drawportals < 1)
1422 leaf = cl.worldmodel->leafs;
1423 endleaf = leaf + cl.worldmodel->numleafs;
1424 for (;leaf < endleaf;leaf++)
1426 if (leaf->visframe == r_framecount && leaf->portals)
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;
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);
1441 portal = portal->next;
1452 void R_DrawWorld (void)
1456 wateralpha = bound(0, r_wateralpha.value*255.0f, 255);
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;
1464 VectorCopy (r_refdef.vieworg, modelorg);
1466 currententity = &ent;
1468 softwaretransformidentity(); // LordHavoc: clear transform
1472 if (r_novis.value || !r_viewleaf->compressed_vis)
1473 R_NoVisWorldNode ();
1477 if (r_portalworldnode.value)
1478 R_PortalWorldNode ();
1479 else if (r_leafworldnode.value)
1486 R_PushDlights (); // now mark the lit surfaces
1494 =============================================================================
1498 =============================================================================
1501 // returns a texture number and the position inside it
1502 int AllocBlock (int w, int h, short *x, short *y)
1508 for (texnum = 0;texnum < MAX_LIGHTMAPS;texnum++)
1510 best = BLOCK_HEIGHT;
1512 for (i = 0;i < BLOCK_WIDTH - w;i += lightmapalign) // LordHavoc: NVIDIA has broken subimage, so align the lightmaps
1516 for (j=0 ; j<w ; j++)
1518 if (allocated[texnum][i+j] >= best)
1520 if (allocated[texnum][i+j] > best2)
1521 best2 = allocated[texnum][i+j];
1524 { // this is a valid spot
1530 if (best + h > BLOCK_HEIGHT)
1533 if (nosubimagefragments || nosubimage)
1535 if (!lightmaps[texnum])
1537 lightmaps[texnum] = qmalloc(BLOCK_WIDTH*BLOCK_HEIGHT*4);
1538 memset(lightmaps[texnum], 0, BLOCK_WIDTH*BLOCK_HEIGHT*4);
1541 // LordHavoc: clear texture to blank image, fragments are uploaded using subimage
1542 else if (!allocated[texnum][0])
1544 byte blank[BLOCK_WIDTH*BLOCK_HEIGHT*4];
1545 memset(blank, 0, sizeof(blank));
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);
1552 glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank);
1554 glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, blank);
1558 for (i = 0;i < w;i++)
1559 allocated[texnum][*x + i] = best + h;
1564 Host_Error ("AllocBlock: full, unable to find room for %i by %i lightmap", w, h);
1569 mvertex_t *r_pcurrentvertbase;
1570 model_t *currentmodel;
1576 BuildSurfaceDisplayList
1579 void BuildSurfaceDisplayList (msurface_t *fa)
1581 int i, j, lindex, lnumverts;
1582 medge_t *pedges, *r_pedge;
1588 // reconstruct the polygon
1589 pedges = currentmodel->edges;
1590 lnumverts = fa->numedges;
1596 poly = Hunk_AllocName (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float), "surfaces");
1597 poly->next = fa->polys;
1598 poly->flags = fa->flags;
1600 poly->numverts = lnumverts;
1602 for (i=0 ; i<lnumverts ; i++)
1604 lindex = currentmodel->surfedges[fa->firstedge + i];
1608 r_pedge = &pedges[lindex];
1609 vec = r_pcurrentvertbase[r_pedge->v[0]].position;
1613 r_pedge = &pedges[-lindex];
1614 vec = r_pcurrentvertbase[r_pedge->v[1]].position;
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];
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;
1624 // lightmap texture coordinates
1626 s -= fa->texturemins[0];
1627 t -= fa->texturemins[1];
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;
1636 t += fa->light_t*16;
1637 t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
1639 poly->verts[i][5] = s;
1640 poly->verts[i][6] = t;
1644 // remove co-linear points - Ed
1647 if (!gl_keeptjunctions.value)
1649 for (i = 0 ; i < lnumverts ; ++i)
1652 float *prev, *this, *next;
1654 prev = poly->verts[(i + lnumverts - 1) % lnumverts];
1655 this = poly->verts[i];
1656 next = poly->verts[(i + 1) % lnumverts];
1658 VectorSubtract( this, prev, v1 );
1659 VectorNormalize( v1 );
1660 VectorSubtract( next, prev, v2 );
1661 VectorNormalize( v2 );
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))
1670 for (j = i + 1; j < lnumverts; ++j)
1673 for (k = 0; k < VERTEXSIZE; ++k)
1674 poly->verts[j - 1][k] = poly->verts[j][k];
1678 // retry next vertex next time, which is now current vertex
1684 poly->numverts = lnumverts;
1688 ========================
1689 GL_CreateSurfaceLightmap
1690 ========================
1692 void GL_CreateSurfaceLightmap (msurface_t *surf)
1696 if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
1699 smax = (surf->extents[0]>>4)+1;
1700 tmax = (surf->extents[1]>>4)+1;
1702 surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
1703 if (nosubimage || nosubimagefragments)
1705 glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum);
1706 smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask;
1709 R_BuildLightMap (surf, templight, smax * 4);
1711 glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
1715 R_BuildLightMap (surf, templight, smax * 3);
1717 glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
1726 Builds the lightmap texture
1727 with all the surfaces from all brush models
1730 void GL_BuildLightmaps (void)
1735 memset (allocated, 0, sizeof(allocated));
1737 r_framecount = 1; // no dlightcache
1739 if (gl_nosubimagefragments.value)
1740 nosubimagefragments = 1;
1742 nosubimagefragments = 0;
1744 if (gl_nosubimage.value)
1749 if (gl_lightmaprgba.value)
1751 lightmaprgba = true;
1756 lightmaprgba = false;
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;
1768 while (lightmapalign < gl_lightmapalign.value)
1769 lightmapalign <<= 1;
1770 gl_lightmapalign.value = lightmapalign;
1771 lightmapalignmask = ~(lightmapalign - 1);
1772 if (nosubimagefragments || nosubimage)
1775 lightmapalignmask = ~0;
1778 if (!lightmap_textures)
1779 lightmap_textures = R_GetTextureSlots(MAX_LIGHTMAPS);
1781 for (j=1 ; j<MAX_MODELS ; j++)
1783 m = cl.model_precache[j];
1786 if (m->name[0] == '*')
1788 r_pcurrentvertbase = m->vertexes;
1790 for (i=0 ; i<m->numsurfaces ; i++)
1792 if ( m->surfaces[i].flags & SURF_DRAWTURB )
1794 if ( m->surfaces[i].flags & SURF_DRAWSKY )
1796 GL_CreateSurfaceLightmap (m->surfaces + i);
1797 BuildSurfaceDisplayList (m->surfaces + i);
1801 if (nosubimage || nosubimagefragments)
1805 qglSelectTexture(gl_mtex_enum+1);
1806 for (i = 0;i < MAX_LIGHTMAPS;i++)
1808 if (!allocated[i][0])
1810 lightmapupdate[i][0] = BLOCK_HEIGHT;
1811 lightmapupdate[i][1] = 0;
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);
1818 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
1820 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
1825 qglSelectTexture(gl_mtex_enum+0);