/* * Copyright(c) 1997-2001 Id Software, Inc. * Copyright(c) 2002 The Quakeforge Project. * Copyright(c) 2006 Quetoo. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or(at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "video.h" /* LIGHT SAMPLING */ vec3_t pointcolor; vec3_t lightspot; int RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end){ float front, back, frac; int side; cplane_t *plane; vec3_t mid; msurface_t *surf; int s, t, ds, dt; int i; mtexinfo_t *tex; byte *lightmap; int maps; int r; if(node->contents != -1) return -1; // didn't hit anything // calculate mid point // FIXME: optimize for axial plane = node->plane; front = DotProduct(start, plane->normal) - plane->dist; back = DotProduct(end, plane->normal) - plane->dist; side = front < 0; if((back < 0) == side) return RecursiveLightPoint(node->children[side], start, end); frac = front /(front - back); mid[0] = start[0] +(end[0] - start[0]) * frac; mid[1] = start[1] +(end[1] - start[1]) * frac; mid[2] = start[2] +(end[2] - start[2]) * frac; // go down front side r = RecursiveLightPoint(node->children[side], start, mid); if(r >= 0) return r; // hit something if((back < 0) == side) return -1; // didn't hit anything // check for impact on this node VectorCopy(mid, lightspot); surf = r_worldmodel->surfaces + node->firstsurface; for(i = 0; i < node->numsurfaces; i++, surf++){ if(surf->flags&(SURF_DRAWTURB | SURF_DRAWSKY)) continue; // no lightmaps tex = surf->texinfo; s = DotProduct(mid, tex->vecs[0]) + tex->vecs[0][3]; t = DotProduct(mid, tex->vecs[1]) + tex->vecs[1][3]; if(s < surf->texturemins[0] || t < surf->texturemins[1]) continue; ds = s - surf->texturemins[0]; dt = t - surf->texturemins[1]; if(ds > surf->extents[0] || dt > surf->extents[1]) continue; if(!surf->samples) return 0; ds >>= 4; dt >>= 4; lightmap = surf->samples; VectorCopy(vec3_origin, pointcolor); if(lightmap){ lightmap += 3 *(dt *((surf->extents[0] >> 4) + 1) + ds); for(maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++){ pointcolor[0] += lightmap[0] * gl_modulate->value * (1.0 / 255); pointcolor[1] += lightmap[1] * gl_modulate->value * (1.0 / 255); pointcolor[2] += lightmap[2] * gl_modulate->value * (1.0 / 255); if(gl_monolightmap->value) //white lightmaps pointcolor[0] = pointcolor[1] = pointcolor[2] = (pointcolor[0] + pointcolor[1] + pointcolor[2]) / 3; lightmap += 3 *((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1); } } return 1; } // go down back side return RecursiveLightPoint(node->children[!side], mid, end); } /* GL_LightPoint */ void GL_LightPoint(vec3_t p, vec3_t color){ vec3_t end; float r; if(!r_worldmodel->lightdata){ color[0] = color[1] = color[2] = 1.0; return; } end[0] = p[0]; end[1] = p[1]; end[2] = p[2] - 2048; r = RecursiveLightPoint(r_worldmodel->nodes, p, end); if(r == -1){ VectorCopy(vec3_origin, color); } else { VectorCopy(pointcolor, color); } VectorScale(color, gl_modulate->value, color); } static float s_blocklights[34*34*3]; /* GL_BuildLightMap Combine and scale multiple lightmaps into the floating format in blocklights */ void GL_BuildLightMap(msurface_t *surf, byte *dest, int stride){ int smax, tmax, maps; int r, g, b, a, max; int i, j, size; byte *lightmap; float *bl; if(surf->texinfo->flags &(SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP)) Com_Error(ERR_DROP, "GL_BuildLightMap called for non-lit surface"); smax = (surf->extents[0] >> 4) + 1; tmax = (surf->extents[1] >> 4) + 1; size = smax * tmax; if(size >(sizeof(s_blocklights) >> 4)) Com_Error(ERR_DROP, "Bad s_blocklights size"); // set to full bright if no light data if(!surf->samples || r_fullbright->value){ for(i = 0; i < size * 3; i++) s_blocklights[i] = 255; goto store; } lightmap = surf->samples; // add all the lightmaps for(maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++){ bl = s_blocklights; for(i = 0; i < size; i++, bl += 3){ if(maps > 0){ //add to existing value bl[0] += (lightmap[i * 3 + 0] * gl_modulate->value); bl[1] += (lightmap[i * 3 + 1] * gl_modulate->value); bl[2] += (lightmap[i * 3 + 2] * gl_modulate->value); } else { //or simply set bl[0] = lightmap[i * 3 + 0] * gl_modulate->value; bl[1] = lightmap[i * 3 + 1] * gl_modulate->value; bl[2] = lightmap[i * 3 + 2] * gl_modulate->value; if(gl_monolightmap->value) //white lightmaps bl[0] = bl[1] = bl[2] = (bl[0] + bl[1] + bl[2]) / 3; } } lightmap += size * 3; // skip to next lightmap } // put into texture format store: stride -= (smax << 2); bl = s_blocklights; for(i = 0; i < tmax; i++, dest += stride){ for(j = 0; j < smax; j++){ r = Q_ftol(bl[0]); g = Q_ftol(bl[1]); b = Q_ftol(bl[2]); // catch negative light if(r < 0) r = 0; if(g < 0) g = 0; if(b < 0) b = 0; // determine brightest component if(r > g) max = r; else max = g; if(b > max) max = b; // set alpha to max a = max; // rescale all if the max exceeds 255 if(max > 255){ float t = 255.0F / max; r = r * t; g = g * t; b = b * t; a = a * t; } dest[0] = r; dest[1] = g; dest[2] = b; dest[3] = a; bl += 3; dest += 4; } } }