diff options
author | tma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-09-28 18:55:31 +0000 |
---|---|---|
committer | tma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-09-28 18:55:31 +0000 |
commit | ec912002d3f75729c627cf467903c4607a529495 (patch) | |
tree | b944aa3ec6a159d4607b3bb25cb09640bca02ddb /q3map/light.c | |
parent | ea1ca0473a510a02fff82788a2a6c8d95a6bf2d3 (diff) | |
download | ioquake3-aero-ec912002d3f75729c627cf467903c4607a529495.tar.gz ioquake3-aero-ec912002d3f75729c627cf467903c4607a529495.zip |
* Removed q3map and associated common and libs directories
git-svn-id: svn://svn.icculus.org/quake3/trunk@123 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'q3map/light.c')
-rw-r--r-- | q3map/light.c | 2149 |
1 files changed, 0 insertions, 2149 deletions
diff --git a/q3map/light.c b/q3map/light.c deleted file mode 100644 index 1563d58..0000000 --- a/q3map/light.c +++ /dev/null @@ -1,2149 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Foobar; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// light.c - -#include "light.h" -#ifdef _WIN32 -#ifdef _TTIMOBUILD -#include "pakstuff.h" -#else -#include "../libs/pakstuff.h" -#endif -#endif - - -#define EXTRASCALE 2 - -typedef struct { - float plane[4]; - vec3_t origin; - vec3_t vectors[2]; - shaderInfo_t *si; -} filter_t; - -#define MAX_FILTERS 1024 -filter_t filters[MAX_FILTERS]; -int numFilters; - -extern char source[1024]; - -qboolean notrace; -qboolean patchshadows; -qboolean dump; -qboolean extra; -qboolean extraWide; -qboolean lightmapBorder; - -qboolean noSurfaces; - -int samplesize = 16; //sample size in units -int novertexlighting = 0; -int nogridlighting = 0; - -// for run time tweaking of all area sources in the level -float areaScale = 0.25; - -// for run time tweaking of all point sources in the level -float pointScale = 7500; - -qboolean exactPointToPolygon = qtrue; - -float formFactorValueScale = 3; - -float linearScale = 1.0 / 8000; - -light_t *lights; -int numPointLights; -int numAreaLights; - -FILE *dumpFile; - -int c_visible, c_occluded; - -//int defaultLightSubdivide = 128; // vary by surface size? -int defaultLightSubdivide = 999; // vary by surface size? - -vec3_t ambientColor; - -vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ]; -int entitySurface[ MAX_MAP_DRAW_SURFS ]; - -// 7,9,11 normalized to avoid being nearly coplanar with common faces -//vec3_t sunDirection = { 0.441835, 0.56807, 0.694313 }; -//vec3_t sunDirection = { 0.45, 0, 0.9 }; -//vec3_t sunDirection = { 0, 0, 1 }; - -// these are usually overrided by shader values -vec3_t sunDirection = { 0.45, 0.3, 0.9 }; -vec3_t sunLight = { 100, 100, 50 }; - - - -typedef struct { - dbrush_t *b; - vec3_t bounds[2]; -} skyBrush_t; - -int numSkyBrushes; -skyBrush_t skyBrushes[MAX_MAP_BRUSHES]; - - -/* - -the corners of a patch mesh will always be exactly at lightmap samples. -The dimensions of the lightmap will be equal to the average length of the control -mesh in each dimension divided by 2. -The lightmap sample points should correspond to the chosen subdivision points. - -*/ - -/* -=============================================================== - -SURFACE LOADING - -=============================================================== -*/ - -#define MAX_FACE_POINTS 128 - -/* -=============== -SubdivideAreaLight - -Subdivide area lights that are very large -A light that is subdivided will never backsplash, avoiding weird pools of light near edges -=============== -*/ -void SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal, - float areaSubdivide, qboolean backsplash ) { - float area, value, intensity; - light_t *dl, *dl2; - vec3_t mins, maxs; - int axis; - winding_t *front, *back; - vec3_t planeNormal; - float planeDist; - - if ( !w ) { - return; - } - - WindingBounds( w, mins, maxs ); - - // check for subdivision - for ( axis = 0 ; axis < 3 ; axis++ ) { - if ( maxs[axis] - mins[axis] > areaSubdivide ) { - VectorClear( planeNormal ); - planeNormal[axis] = 1; - planeDist = ( maxs[axis] + mins[axis] ) * 0.5; - ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back ); - SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse ); - SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse ); - FreeWinding( w ); - return; - } - } - - // create a light from this - area = WindingArea (w); - if ( area <= 0 || area > 20000000 ) { - return; - } - - numAreaLights++; - dl = malloc(sizeof(*dl)); - memset (dl, 0, sizeof(*dl)); - dl->next = lights; - lights = dl; - dl->type = emit_area; - - WindingCenter( w, dl->origin ); - dl->w = w; - VectorCopy ( normal, dl->normal); - dl->dist = DotProduct( dl->origin, normal ); - - value = ls->value; - intensity = value * area * areaScale; - VectorAdd( dl->origin, dl->normal, dl->origin ); - - VectorCopy( ls->color, dl->color ); - - dl->photons = intensity; - - // emitColor is irrespective of the area - VectorScale( ls->color, value*formFactorValueScale*areaScale, dl->emitColor ); - - dl->si = ls; - - if ( ls->contents & CONTENTS_FOG ) { - dl->twosided = qtrue; - } - - // optionally create a point backsplash light - if ( backsplash && ls->backsplashFraction > 0 ) { - dl2 = malloc(sizeof(*dl)); - memset (dl2, 0, sizeof(*dl2)); - dl2->next = lights; - lights = dl2; - dl2->type = emit_point; - - VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin ); - - VectorCopy( ls->color, dl2->color ); - - dl2->photons = dl->photons * ls->backsplashFraction; - dl2->si = ls; - } -} - - -/* -=============== -CountLightmaps -=============== -*/ -void CountLightmaps( void ) { - int count; - int i; - dsurface_t *ds; - - qprintf ("--- CountLightmaps ---\n"); - count = 0; - for ( i = 0 ; i < numDrawSurfaces ; i++ ) { - // see if this surface is light emiting - ds = &drawSurfaces[i]; - if ( ds->lightmapNum > count ) { - count = ds->lightmapNum; - } - } - - count++; - numLightBytes = count * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3; - if ( numLightBytes > MAX_MAP_LIGHTING ) { - Error("MAX_MAP_LIGHTING exceeded"); - } - - qprintf( "%5i drawSurfaces\n", numDrawSurfaces ); - qprintf( "%5i lightmaps\n", count ); -} - -/* -=============== -CreateSurfaceLights - -This creates area lights -=============== -*/ -void CreateSurfaceLights( void ) { - int i, j, side; - dsurface_t *ds; - shaderInfo_t *ls; - winding_t *w; - cFacet_t *f; - light_t *dl; - vec3_t origin; - drawVert_t *dv; - int c_lightSurfaces; - float lightSubdivide; - vec3_t normal; - - qprintf ("--- CreateSurfaceLights ---\n"); - c_lightSurfaces = 0; - - for ( i = 0 ; i < numDrawSurfaces ; i++ ) { - // see if this surface is light emiting - ds = &drawSurfaces[i]; - - ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); - if ( ls->value == 0 ) { - continue; - } - - // determine how much we need to chop up the surface - if ( ls->lightSubdivide ) { - lightSubdivide = ls->lightSubdivide; - } else { - lightSubdivide = defaultLightSubdivide; - } - - c_lightSurfaces++; - - // an autosprite shader will become - // a point light instead of an area light - if ( ls->autosprite ) { - // autosprite geometry should only have four vertexes - if ( surfaceTest[i] ) { - // curve or misc_model - f = surfaceTest[i]->facets; - if ( surfaceTest[i]->numFacets != 1 || f->numBoundaries != 4 ) { - _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n", - (int)f->points[0], (int)f->points[1], (int)f->points[2] ); - } - VectorAdd( f->points[0], f->points[1], origin ); - VectorAdd( f->points[2], origin, origin ); - VectorAdd( f->points[3], origin, origin ); - VectorScale( origin, 0.25, origin ); - } else { - // normal polygon - dv = &drawVerts[ ds->firstVert ]; - if ( ds->numVerts != 4 ) { - _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n", - (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] ); - continue; - } - - VectorAdd( dv[0].xyz, dv[1].xyz, origin ); - VectorAdd( dv[2].xyz, origin, origin ); - VectorAdd( dv[3].xyz, origin, origin ); - VectorScale( origin, 0.25, origin ); - } - - - numPointLights++; - dl = malloc(sizeof(*dl)); - memset (dl, 0, sizeof(*dl)); - dl->next = lights; - lights = dl; - - VectorCopy( origin, dl->origin ); - VectorCopy( ls->color, dl->color ); - dl->photons = ls->value * pointScale; - dl->type = emit_point; - continue; - } - - // possibly create for both sides of the polygon - for ( side = 0 ; side <= ls->twoSided ; side++ ) { - // create area lights - if ( surfaceTest[i] ) { - // curve or misc_model - for ( j = 0 ; j < surfaceTest[i]->numFacets ; j++ ) { - f = surfaceTest[i]->facets + j; - w = AllocWinding( f->numBoundaries ); - w->numpoints = f->numBoundaries; - memcpy( w->p, f->points, f->numBoundaries * 12 ); - - VectorCopy( f->surface, normal ); - if ( side ) { - winding_t *t; - - t = w; - w = ReverseWinding( t ); - FreeWinding( t ); - VectorSubtract( vec3_origin, normal, normal ); - } - SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue ); - } - } else { - // normal polygon - - w = AllocWinding( ds->numVerts ); - w->numpoints = ds->numVerts; - for ( j = 0 ; j < ds->numVerts ; j++ ) { - VectorCopy( drawVerts[ds->firstVert+j].xyz, w->p[j] ); - } - VectorCopy( ds->lightmapVecs[2], normal ); - if ( side ) { - winding_t *t; - - t = w; - w = ReverseWinding( t ); - FreeWinding( t ); - VectorSubtract( vec3_origin, normal, normal ); - } - SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue ); - } - } - } - - _printf( "%5i light emitting surfaces\n", c_lightSurfaces ); -} - - - -/* -================ -FindSkyBrushes -================ -*/ -void FindSkyBrushes( void ) { - int i, j; - dbrush_t *b; - skyBrush_t *sb; - shaderInfo_t *si; - dbrushside_t *s; - - // find the brushes - for ( i = 0 ; i < numbrushes ; i++ ) { - b = &dbrushes[i]; - for ( j = 0 ; j < b->numSides ; j++ ) { - s = &dbrushsides[ b->firstSide + j ]; - if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) { - sb = &skyBrushes[ numSkyBrushes ]; - sb->b = b; - sb->bounds[0][0] = -dplanes[ dbrushsides[ b->firstSide + 0 ].planeNum ].dist - 1; - sb->bounds[1][0] = dplanes[ dbrushsides[ b->firstSide + 1 ].planeNum ].dist + 1; - sb->bounds[0][1] = -dplanes[ dbrushsides[ b->firstSide + 2 ].planeNum ].dist - 1; - sb->bounds[1][1] = dplanes[ dbrushsides[ b->firstSide + 3 ].planeNum ].dist + 1; - sb->bounds[0][2] = -dplanes[ dbrushsides[ b->firstSide + 4 ].planeNum ].dist - 1; - sb->bounds[1][2] = dplanes[ dbrushsides[ b->firstSide + 5 ].planeNum ].dist + 1; - numSkyBrushes++; - break; - } - } - } - - // default - VectorNormalize( sunDirection, sunDirection ); - - // find the sky shader - for ( i = 0 ; i < numDrawSurfaces ; i++ ) { - si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader ); - if ( si->surfaceFlags & SURF_SKY ) { - VectorCopy( si->sunLight, sunLight ); - VectorCopy( si->sunDirection, sunDirection ); - break; - } - } -} - -/* -================================================================= - - LIGHT SETUP - -================================================================= -*/ - -/* -================== -FindTargetEntity -================== -*/ -entity_t *FindTargetEntity( const char *target ) { - int i; - const char *n; - - for ( i = 0 ; i < num_entities ; i++ ) { - n = ValueForKey (&entities[i], "targetname"); - if ( !strcmp (n, target) ) { - return &entities[i]; - } - } - - return NULL; -} - - - -/* -============= -CreateEntityLights -============= -*/ -void CreateEntityLights (void) -{ - int i; - light_t *dl; - entity_t *e, *e2; - const char *name; - const char *target; - vec3_t dest; - const char *_color; - float intensity; - int spawnflags; - - // - // entities - // - for ( i = 0 ; i < num_entities ; i++ ) { - e = &entities[i]; - name = ValueForKey (e, "classname"); - if (strncmp (name, "light", 5)) - continue; - - numPointLights++; - dl = malloc(sizeof(*dl)); - memset (dl, 0, sizeof(*dl)); - dl->next = lights; - lights = dl; - - spawnflags = FloatForKey (e, "spawnflags"); - if ( spawnflags & 1 ) { - dl->linearLight = qtrue; - } - - GetVectorForKey (e, "origin", dl->origin); - dl->style = FloatForKey (e, "_style"); - if (!dl->style) - dl->style = FloatForKey (e, "style"); - if (dl->style < 0) - dl->style = 0; - - intensity = FloatForKey (e, "light"); - if (!intensity) - intensity = FloatForKey (e, "_light"); - if (!intensity) - intensity = 300; - _color = ValueForKey (e, "_color"); - if (_color && _color[0]) - { - sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]); - ColorNormalize (dl->color, dl->color); - } - else - dl->color[0] = dl->color[1] = dl->color[2] = 1.0; - - intensity = intensity * pointScale; - dl->photons = intensity; - - dl->type = emit_point; - - // lights with a target will be spotlights - target = ValueForKey (e, "target"); - - if ( target[0] ) { - float radius; - float dist; - - e2 = FindTargetEntity (target); - if (!e2) { - _printf ("WARNING: light at (%i %i %i) has missing target\n", - (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]); - } else { - GetVectorForKey (e2, "origin", dest); - VectorSubtract (dest, dl->origin, dl->normal); - dist = VectorNormalize (dl->normal, dl->normal); - radius = FloatForKey (e, "radius"); - if ( !radius ) { - radius = 64; - } - if ( !dist ) { - dist = 64; - } - dl->radiusByDist = (radius + 16) / dist; - dl->type = emit_spotlight; - } - } - } -} - -//================================================================= - -/* -================ -SetEntityOrigins - -Find the offset values for inline models -================ -*/ -void SetEntityOrigins( void ) { - int i, j; - entity_t *e; - vec3_t origin; - const char *key; - int modelnum; - dmodel_t *dm; - - for ( i=0 ; i < num_entities ; i++ ) { - e = &entities[i]; - key = ValueForKey (e, "model"); - if ( key[0] != '*' ) { - continue; - } - modelnum = atoi( key + 1 ); - dm = &dmodels[ modelnum ]; - - // set entity surface to true for all surfaces for this model - for ( j = 0 ; j < dm->numSurfaces ; j++ ) { - entitySurface[ dm->firstSurface + j ] = qtrue; - } - - key = ValueForKey (e, "origin"); - if ( !key[0] ) { - continue; - } - GetVectorForKey ( e, "origin", origin ); - - // set origin for all surfaces for this model - for ( j = 0 ; j < dm->numSurfaces ; j++ ) { - VectorCopy( origin, surfaceOrigin[ dm->firstSurface + j ] ); - } - } -} - - -/* -================================================================= - - -================================================================= -*/ - -#define MAX_POINTS_ON_WINDINGS 64 - -/* -================ -PointToPolygonFormFactor -================ -*/ -float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) { - vec3_t triVector, triNormal; - int i, j; - vec3_t dirs[MAX_POINTS_ON_WINDING]; - float total; - float dot, angle, facing; - - for ( i = 0 ; i < w->numpoints ; i++ ) { - VectorSubtract( w->p[i], point, dirs[i] ); - VectorNormalize( dirs[i], dirs[i] ); - } - - // duplicate first vertex to avoid mod operation - VectorCopy( dirs[0], dirs[i] ); - - total = 0; - for ( i = 0 ; i < w->numpoints ; i++ ) { - j = i+1; - dot = DotProduct( dirs[i], dirs[j] ); - - // roundoff can cause slight creep, which gives an IND from acos - if ( dot > 1.0 ) { - dot = 1.0; - } else if ( dot < -1.0 ) { - dot = -1.0; - } - - angle = acos( dot ); - CrossProduct( dirs[i], dirs[j], triVector ); - if ( VectorNormalize( triVector, triNormal ) < 0.0001 ) { - continue; - } - facing = DotProduct( normal, triNormal ); - total += facing * angle; - - if ( total > 6.3 || total < -6.3 ) { - static qboolean printed; - - if ( !printed ) { - printed = qtrue; - _printf( "WARNING: bad PointToPolygonFormFactor: %f at %1.1f %1.1f %1.1f from %1.1f %1.1f %1.1f\n", total, - w->p[i][0], w->p[i][1], w->p[i][2], point[0], point[1], point[2]); - } - return 0; - } - - } - - total /= 2*3.141592657; // now in the range of 0 to 1 over the entire incoming hemisphere - - return total; -} - - -/* -================ -FilterTrace - -Returns 0 to 1.0 filter fractions for the given trace -================ -*/ -void FilterTrace( const vec3_t start, const vec3_t end, vec3_t filter ) { - float d1, d2; - filter_t *f; - int filterNum; - vec3_t point; - float frac; - int i; - float s, t; - int u, v; - int x, y; - byte *pixel; - float radius; - float len; - vec3_t total; - - filter[0] = 1.0; - filter[1] = 1.0; - filter[2] = 1.0; - - for ( filterNum = 0 ; filterNum < numFilters ; filterNum++ ) { - f = &filters[ filterNum ]; - - // see if the plane is crossed - d1 = DotProduct( start, f->plane ) - f->plane[3]; - d2 = DotProduct( end, f->plane ) - f->plane[3]; - - if ( ( d1 < 0 ) == ( d2 < 0 ) ) { - continue; - } - - // calculate the crossing point - frac = d1 / ( d1 - d2 ); - - for ( i = 0 ; i < 3 ; i++ ) { - point[i] = start[i] + frac * ( end[i] - start[i] ); - } - - VectorSubtract( point, f->origin, point ); - - s = DotProduct( point, f->vectors[0] ); - t = 1.0 - DotProduct( point, f->vectors[1] ); - if ( s < 0 || s >= 1.0 || t < 0 || t >= 1.0 ) { - continue; - } - - // decide the filter size - radius = 10 * frac; - len = VectorLength( f->vectors[0] ); - if ( !len ) { - continue; - } - radius = radius * len * f->si->width; - - // look up the filter, taking multiple samples - VectorClear( total ); - for ( u = -1 ; u <= 1 ; u++ ) { - for ( v = -1 ; v <=1 ; v++ ) { - x = s * f->si->width + u * radius; - if ( x < 0 ) { - x = 0; - } - if ( x >= f->si->width ) { - x = f->si->width - 1; - } - y = t * f->si->height + v * radius; - if ( y < 0 ) { - y = 0; - } - if ( y >= f->si->height ) { - y = f->si->height - 1; - } - - pixel = f->si->pixels + ( y * f->si->width + x ) * 4; - total[0] += pixel[0]; - total[1] += pixel[1]; - total[2] += pixel[2]; - } - } - - filter[0] *= total[0]/(255.0*9); - filter[1] *= total[1]/(255.0*9); - filter[2] *= total[2]/(255.0*9); - } - -} - -/* -================ -SunToPoint - -Returns an amount of light to add at the point -================ -*/ -int c_sunHit, c_sunMiss; -void SunToPoint( const vec3_t origin, traceWork_t *tw, vec3_t addLight ) { - int i; - trace_t trace; - skyBrush_t *b; - vec3_t end; - - if ( !numSkyBrushes ) { - VectorClear( addLight ); - return; - } - - VectorMA( origin, MAX_WORLD_COORD * 2, sunDirection, end ); - - TraceLine( origin, end, &trace, qtrue, tw ); - - // see if trace.hit is inside a sky brush - for ( i = 0 ; i < numSkyBrushes ; i++) { - b = &skyBrushes[ i ]; - - // this assumes that sky brushes are axial... - if ( trace.hit[0] < b->bounds[0][0] - || trace.hit[0] > b->bounds[1][0] - || trace.hit[1] < b->bounds[0][1] - || trace.hit[1] > b->bounds[1][1] - || trace.hit[2] < b->bounds[0][2] - || trace.hit[2] > b->bounds[1][2] ) { - continue; - } - - - // trace again to get intermediate filters - TraceLine( origin, trace.hit, &trace, qtrue, tw ); - - // we hit the sky, so add sunlight - if ( numthreads == 1 ) { - c_sunHit++; - } - addLight[0] = trace.filter[0] * sunLight[0]; - addLight[1] = trace.filter[1] * sunLight[1]; - addLight[2] = trace.filter[2] * sunLight[2]; - - return; - } - - if ( numthreads == 1 ) { - c_sunMiss++; - } - - VectorClear( addLight ); -} - -/* -================ -SunToPlane -================ -*/ -void SunToPlane( const vec3_t origin, const vec3_t normal, vec3_t color, traceWork_t *tw ) { - float angle; - vec3_t sunColor; - - if ( !numSkyBrushes ) { - return; - } - - angle = DotProduct( normal, sunDirection ); - if ( angle <= 0 ) { - return; // facing away - } - - SunToPoint( origin, tw, sunColor ); - VectorMA( color, angle, sunColor, color ); -} - -/* -================ -LightingAtSample -================ -*/ -void LightingAtSample( vec3_t origin, vec3_t normal, vec3_t color, - qboolean testOcclusion, qboolean forceSunLight, traceWork_t *tw ) { - light_t *light; - trace_t trace; - float angle; - float add; - float dist; - vec3_t dir; - - VectorCopy( ambientColor, color ); - - // trace to all the lights - for ( light = lights ; light ; light = light->next ) { - - //MrE: if the light is behind the surface - if ( DotProduct(light->origin, normal) - DotProduct(normal, origin) < 0 ) - continue; - // testing exact PTPFF - if ( exactPointToPolygon && light->type == emit_area ) { - float factor; - float d; - vec3_t pushedOrigin; - - // see if the point is behind the light - d = DotProduct( origin, light->normal ) - light->dist; - if ( !light->twosided ) { - if ( d < -1 ) { - continue; // point is behind light - } - } - - // test occlusion and find light filters - // clip the line, tracing from the surface towards the light - if ( !notrace && testOcclusion ) { - TraceLine( origin, light->origin, &trace, qfalse, tw ); - - // other light rays must not hit anything - if ( trace.passSolid ) { - continue; - } - } else { - trace.filter[0] = 1.0; - trace.filter[1] = 1.0; - trace.filter[2] = 1.0; - } - - // nudge the point so that it is clearly forward of the light - // so that surfaces meeting a light emiter don't get black edges - if ( d > -8 && d < 8 ) { - VectorMA( origin, (8-d), light->normal, pushedOrigin ); - } else { - VectorCopy( origin, pushedOrigin ); - } - - // calculate the contribution - factor = PointToPolygonFormFactor( pushedOrigin, normal, light->w ); - if ( factor <= 0 ) { - if ( light->twosided ) { - factor = -factor; - } else { - continue; - } - } - color[0] += factor * light->emitColor[0] * trace.filter[0]; - color[1] += factor * light->emitColor[1] * trace.filter[1]; - color[2] += factor * light->emitColor[2] * trace.filter[2]; - - continue; - } - - // calculate the amount of light at this sample - if ( light->type == emit_point ) { - VectorSubtract( light->origin, origin, dir ); - dist = VectorNormalize( dir, dir ); - // clamp the distance to prevent super hot spots - if ( dist < 16 ) { - dist = 16; - } - angle = DotProduct( normal, dir ); - if ( light->linearLight ) { - add = angle * light->photons * linearScale - dist; - if ( add < 0 ) { - add = 0; - } - } else { - add = light->photons / ( dist * dist ) * angle; - } - } else if ( light->type == emit_spotlight ) { - float distByNormal; - vec3_t pointAtDist; - float radiusAtDist; - float sampleRadius; - vec3_t distToSample; - float coneScale; - - VectorSubtract( light->origin, origin, dir ); - - distByNormal = -DotProduct( dir, light->normal ); - if ( distByNormal < 0 ) { - continue; - } - VectorMA( light->origin, distByNormal, light->normal, pointAtDist ); - radiusAtDist = light->radiusByDist * distByNormal; - - VectorSubtract( origin, pointAtDist, distToSample ); - sampleRadius = VectorLength( distToSample ); - - if ( sampleRadius >= radiusAtDist ) { - continue; // outside the cone - } - if ( sampleRadius <= radiusAtDist - 32 ) { - coneScale = 1.0; // fully inside - } else { - coneScale = ( radiusAtDist - sampleRadius ) / 32.0; - } - - dist = VectorNormalize( dir, dir ); - // clamp the distance to prevent super hot spots - if ( dist < 16 ) { - dist = 16; - } - angle = DotProduct( normal, dir ); - add = light->photons / ( dist * dist ) * angle * coneScale; - - } else if ( light->type == emit_area ) { - VectorSubtract( light->origin, origin, dir ); - dist = VectorNormalize( dir, dir ); - // clamp the distance to prevent super hot spots - if ( dist < 16 ) { - dist = 16; - } - angle = DotProduct( normal, dir ); - if ( angle <= 0 ) { - continue; - } - angle *= -DotProduct( light->normal, dir ); - if ( angle <= 0 ) { - continue; - } - - if ( light->linearLight ) { - add = angle * light->photons * linearScale - dist; - if ( add < 0 ) { - add = 0; - } - } else { - add = light->photons / ( dist * dist ) * angle; - } - } - - if ( add <= 1.0 ) { - continue; - } - - // clip the line, tracing from the surface towards the light - if ( !notrace && testOcclusion ) { - TraceLine( origin, light->origin, &trace, qfalse, tw ); - - // other light rays must not hit anything - if ( trace.passSolid ) { - continue; - } - } else { - trace.filter[0] = 1; - trace.filter[1] = 1; - trace.filter[2] = 1; - } - - // add the result - color[0] += add * light->color[0] * trace.filter[0]; - color[1] += add * light->color[1] * trace.filter[1]; - color[2] += add * light->color[2] * trace.filter[2]; - } - - // - // trace directly to the sun - // - if ( testOcclusion || forceSunLight ) { - SunToPlane( origin, normal, color, tw ); - } -} - -/* -============= -PrintOccluded - -For debugging -============= -*/ -void PrintOccluded( byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE], - int width, int height ) { - int i, j; - - _printf( "\n" ); - - for ( i = 0 ; i < height ; i++ ) { - for ( j = 0 ; j < width ; j++ ) { - _printf("%i", (int)occluded[j][i] ); - } - _printf( "\n" ); - } -} - - -/* -============= -VertexLighting - -Vertex lighting will completely ignore occlusion, because -shadows would not be resolvable anyway. -============= -*/ -void VertexLighting( dsurface_t *ds, qboolean testOcclusion, qboolean forceSunLight, float scale, traceWork_t *tw ) { - int i, j; - drawVert_t *dv; - vec3_t sample, normal; - float max; - - VectorCopy( ds->lightmapVecs[2], normal ); - - // generate vertex lighting - for ( i = 0 ; i < ds->numVerts ; i++ ) { - dv = &drawVerts[ ds->firstVert + i ]; - - if ( ds->patchWidth ) { - LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw ); - } - else if (ds->surfaceType == MST_TRIANGLE_SOUP) { - LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw ); - } - else { - LightingAtSample( dv->xyz, normal, sample, testOcclusion, forceSunLight, tw ); - } - - if (scale >= 0) - VectorScale(sample, scale, sample); - // clamp with color normalization - max = sample[0]; - if ( sample[1] > max ) { - max = sample[1]; - } - if ( sample[2] > max ) { - max = sample[2]; - } - if ( max > 255 ) { - VectorScale( sample, 255/max, sample ); - } - - // save the sample - for ( j = 0 ; j < 3 ; j++ ) { - if ( sample[j] > 255 ) { - sample[j] = 255; - } - dv->color[j] = sample[j]; - } - - // Don't bother writing alpha since it will already be set to 255, - // plus we don't want to write over alpha generated by SetTerrainTextures - //dv->color[3] = 255; - } -} - - -/* -================= -LinearSubdivideMesh - -For extra lighting, just midpoint one of the axis. -The edges are clamped at the original edges. -================= -*/ -mesh_t *LinearSubdivideMesh( mesh_t *in ) { - int i, j; - mesh_t *out; - drawVert_t *v1, *v2, *vout; - - out = malloc( sizeof( *out ) ); - - out->width = in->width * 2; - out->height = in->height; - out->verts = malloc( out->width * out->height * sizeof(*out->verts) ); - for ( j = 0 ; j < in->height ; j++ ) { - out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ]; - out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ]; - for ( i = 1 ; i < out->width - 1 ; i+= 2 ) { - v1 = in->verts + j * in->width + (i >> 1); - v2 = v1 + 1; - vout = out->verts + j * out->width + i; - - vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0]; - vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1]; - vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2]; - - vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0]; - vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1]; - vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2]; - - VectorNormalize( vout->normal, vout->normal ); - - vout++; - - vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0]; - vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1]; - vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2]; - - vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0]; - vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1]; - vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2]; - - VectorNormalize( vout->normal, vout->normal ); - - } - } - - FreeMesh( in ); - - return out; -} - -/* -============== -ColorToBytes -============== -*/ -void ColorToBytes( const float *color, byte *colorBytes ) { - float max; - vec3_t sample; - - VectorCopy( color, sample ); - - // clamp with color normalization - max = sample[0]; - if ( sample[1] > max ) { - max = sample[1]; - } - if ( sample[2] > max ) { - max = sample[2]; - } - if ( max > 255 ) { - VectorScale( sample, 255/max, sample ); - } - colorBytes[ 0 ] = sample[0]; - colorBytes[ 1 ] = sample[1]; - colorBytes[ 2 ] = sample[2]; -} - - - -/* -============= -TraceLtm -============= -*/ -void TraceLtm( int num ) { - dsurface_t *ds; - int i, j, k; - int x, y; - int position, numPositions; - vec3_t base, origin, normal; - byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE]; - vec3_t color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE]; - traceWork_t tw; - vec3_t average; - int count; - mesh_t srcMesh, *mesh, *subdivided; - shaderInfo_t *si; - static float nudge[2][9] = { - { 0, -1, 0, 1, -1, 1, -1, 0, 1 }, - { 0, -1, -1, -1, 0, 0, 1, 1, 1 } - }; - int sampleWidth, sampleHeight, ssize; - vec3_t lightmapOrigin, lightmapVecs[2]; - int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH]; - - ds = &drawSurfaces[num]; - si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); - - // vertex-lit triangle model - if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { - VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw ); - return; - } - - if ( ds->lightmapNum == -1 ) { - return; // doesn't need lighting at all - } - - if (!novertexlighting) { - // calculate the vertex lighting for gouraud shade mode - VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw ); - } - - if ( ds->lightmapNum < 0 ) { - return; // doesn't need lightmap lighting - } - - si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); - ssize = samplesize; - if (si->lightmapSampleSize) - ssize = si->lightmapSampleSize; - - if (si->patchShadows) - tw.patchshadows = qtrue; - else - tw.patchshadows = patchshadows; - - if ( ds->surfaceType == MST_PATCH ) { - srcMesh.width = ds->patchWidth; - srcMesh.height = ds->patchHeight; - srcMesh.verts = drawVerts + ds->firstVert; - mesh = SubdivideMesh( srcMesh, 8, 999 ); - PutMeshOnCurve( *mesh ); - MakeMeshNormals( *mesh ); - - subdivided = RemoveLinearMeshColumnsRows( mesh ); - FreeMesh(mesh); - - mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable); - if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) { - Error( "Mesh lightmap miscount"); - } - - if ( extra ) { - mesh_t *mp; - - // chop it up for more light samples (leaking memory...) - mp = mesh;//CopyMesh( mesh ); - mp = LinearSubdivideMesh( mp ); - mp = TransposeMesh( mp ); - mp = LinearSubdivideMesh( mp ); - mp = TransposeMesh( mp ); - - mesh = mp; - } - } else { - VectorCopy( ds->lightmapVecs[2], normal ); - - if ( !extra ) { - VectorCopy( ds->lightmapOrigin, lightmapOrigin ); - VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] ); - VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] ); - } else { - // sample at a closer spacing for antialiasing - VectorCopy( ds->lightmapOrigin, lightmapOrigin ); - VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] ); - VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] ); - VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin ); - VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin ); - } - } - - if ( extra ) { - sampleWidth = ds->lightmapWidth * 2; - sampleHeight = ds->lightmapHeight * 2; - } else { - sampleWidth = ds->lightmapWidth; - sampleHeight = ds->lightmapHeight; - } - - memset ( color, 0, sizeof( color ) ); - - // determine which samples are occluded - memset ( occluded, 0, sizeof( occluded ) ); - for ( i = 0 ; i < sampleWidth ; i++ ) { - for ( j = 0 ; j < sampleHeight ; j++ ) { - - if ( ds->patchWidth ) { - numPositions = 9; - VectorCopy( mesh->verts[j*mesh->width+i].normal, normal ); - // VectorNormalize( normal, normal ); - // push off of the curve a bit - VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base ); - - MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] ); - } else { - numPositions = 9; - for ( k = 0 ; k < 3 ; k++ ) { - base[k] = lightmapOrigin[k] + normal[k] - + i * lightmapVecs[0][k] - + j * lightmapVecs[1][k]; - } - } - VectorAdd( base, surfaceOrigin[ num ], base ); - - // we may need to slightly nudge the sample point - // if directly on a wall - for ( position = 0 ; position < numPositions ; position++ ) { - // calculate lightmap sample position - for ( k = 0 ; k < 3 ; k++ ) { - origin[k] = base[k] + - + ( nudge[0][position]/16 ) * lightmapVecs[0][k] - + ( nudge[1][position]/16 ) * lightmapVecs[1][k]; - } - - if ( notrace ) { - break; - } - if ( !PointInSolid( origin ) ) { - break; - } - } - - // if none of the nudges worked, this sample is occluded - if ( position == numPositions ) { - occluded[i][j] = qtrue; - if ( numthreads == 1 ) { - c_occluded++; - } - continue; - } - - if ( numthreads == 1 ) { - c_visible++; - } - occluded[i][j] = qfalse; - LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw ); - } - } - - if ( dump ) { - PrintOccluded( occluded, sampleWidth, sampleHeight ); - } - - // calculate average values for occluded samples - for ( i = 0 ; i < sampleWidth ; i++ ) { - for ( j = 0 ; j < sampleHeight ; j++ ) { - if ( !occluded[i][j] ) { - continue; - } - // scan all surrounding samples - count = 0; - VectorClear( average ); - for ( x = -1 ; x <= 1; x++ ) { - for ( y = -1 ; y <= 1 ; y++ ) { - if ( i + x < 0 || i + x >= sampleWidth ) { - continue; - } - if ( j + y < 0 || j + y >= sampleHeight ) { - continue; - } - if ( occluded[i+x][j+y] ) { - continue; - } - count++; - VectorAdd( color[i+x][j+y], average, average ); - } - } - if ( count ) { - VectorScale( average, 1.0/count, color[i][j] ); - } - } - } - - // average together the values if we are extra sampling - if ( ds->lightmapWidth != sampleWidth ) { - for ( i = 0 ; i < ds->lightmapWidth ; i++ ) { - for ( j = 0 ; j < ds->lightmapHeight ; j++ ) { - for ( k = 0 ; k < 3 ; k++ ) { - float value, coverage; - - value = color[i*2][j*2][k] + color[i*2][j*2+1][k] + - color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k]; - coverage = 4; - if ( extraWide ) { - // wider than box filter - if ( i > 0 ) { - value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k]; - value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k]; - coverage += 4; - } - if ( i < ds->lightmapWidth - 1 ) { - value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k]; - value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k]; - coverage += 4; - } - if ( j > 0 ) { - value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k]; - value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k]; - coverage += 4; - } - if ( j < ds->lightmapHeight - 1 ) { - value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k]; - value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k]; - coverage += 2; - } - } - - color[i][j][k] = value / coverage; - } - } - } - } - - // optionally create a debugging border around the lightmap - if ( lightmapBorder ) { - for ( i = 0 ; i < ds->lightmapWidth ; i++ ) { - color[i][0][0] = 255; - color[i][0][1] = 0; - color[i][0][2] = 0; - - color[i][ds->lightmapHeight-1][0] = 255; - color[i][ds->lightmapHeight-1][1] = 0; - color[i][ds->lightmapHeight-1][2] = 0; - } - for ( i = 0 ; i < ds->lightmapHeight ; i++ ) { - color[0][i][0] = 255; - color[0][i][1] = 0; - color[0][i][2] = 0; - - color[ds->lightmapWidth-1][i][0] = 255; - color[ds->lightmapWidth-1][i][1] = 0; - color[ds->lightmapWidth-1][i][2] = 0; - } - } - - // clamp the colors to bytes and store off - for ( i = 0 ; i < ds->lightmapWidth ; i++ ) { - for ( j = 0 ; j < ds->lightmapHeight ; j++ ) { - k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j) - * LIGHTMAP_WIDTH + ds->lightmapX + i; - - ColorToBytes( color[i][j], lightBytes + k*3 ); - } - } - - if (ds->surfaceType == MST_PATCH) - { - FreeMesh(mesh); - } -} - - -//============================================================================= - -vec3_t gridMins; -vec3_t gridSize = { 64, 64, 128 }; -int gridBounds[3]; - - -/* -======================== -LightContributionToPoint -======================== -*/ -qboolean LightContributionToPoint( const light_t *light, const vec3_t origin, - vec3_t color, traceWork_t *tw ) { - trace_t trace; - float add; - - add = 0; - - VectorClear( color ); - - // testing exact PTPFF - if ( exactPointToPolygon && light->type == emit_area ) { - float factor; - float d; - vec3_t normal; - - // see if the point is behind the light - d = DotProduct( origin, light->normal ) - light->dist; - if ( !light->twosided ) { - if ( d < 1 ) { - return qfalse; // point is behind light - } - } - - // test occlusion - // clip the line, tracing from the surface towards the light - TraceLine( origin, light->origin, &trace, qfalse, tw ); - if ( trace.passSolid ) { - return qfalse; - } - - // calculate the contribution - VectorSubtract( light->origin, origin, normal ); - if ( VectorNormalize( normal, normal ) == 0 ) { - return qfalse; - } - factor = PointToPolygonFormFactor( origin, normal, light->w ); - if ( factor <= 0 ) { - if ( light->twosided ) { - factor = -factor; - } else { - return qfalse; - } - } - VectorScale( light->emitColor, factor, color ); - return qtrue; - } - - // calculate the amount of light at this sample - if ( light->type == emit_point || light->type == emit_spotlight ) { - vec3_t dir; - float dist; - - VectorSubtract( light->origin, origin, dir ); - dist = VectorLength( dir ); - // clamp the distance to prevent super hot spots - if ( dist < 16 ) { - dist = 16; - } - if ( light->linearLight ) { - add = light->photons * linearScale - dist; - if ( add < 0 ) { - add = 0; - } - } else { - add = light->photons / ( dist * dist ); - } - } else { - return qfalse; - } - - if ( add <= 1.0 ) { - return qfalse; - } - - // clip the line, tracing from the surface towards the light - TraceLine( origin, light->origin, &trace, qfalse, tw ); - - // other light rays must not hit anything - if ( trace.passSolid ) { - return qfalse; - } - - // add the result - color[0] = add * light->color[0]; - color[1] = add * light->color[1]; - color[2] = add * light->color[2]; - - return qtrue; -} - -typedef struct { - vec3_t dir; - vec3_t color; -} contribution_t; - -/* -============= -TraceGrid - -Grid samples are foe quickly determining the lighting -of dynamically placed entities in the world -============= -*/ -#define MAX_CONTRIBUTIONS 1024 -void TraceGrid( int num ) { - int x, y, z; - vec3_t origin; - light_t *light; - vec3_t color; - int mod; - vec3_t directedColor; - vec3_t summedDir; - contribution_t contributions[MAX_CONTRIBUTIONS]; - int numCon; - int i; - traceWork_t tw; - float addSize; - - mod = num; - z = mod / ( gridBounds[0] * gridBounds[1] ); - mod -= z * ( gridBounds[0] * gridBounds[1] ); - - y = mod / gridBounds[0]; - mod -= y * gridBounds[0]; - - x = mod; - - origin[0] = gridMins[0] + x * gridSize[0]; - origin[1] = gridMins[1] + y * gridSize[1]; - origin[2] = gridMins[2] + z * gridSize[2]; - - if ( PointInSolid( origin ) ) { - vec3_t baseOrigin; - int step; - - VectorCopy( origin, baseOrigin ); - - // try to nudge the origin around to find a valid point - for ( step = 9 ; step <= 18 ; step += 9 ) { - for ( i = 0 ; i < 8 ; i++ ) { - VectorCopy( baseOrigin, origin ); - if ( i & 1 ) { - origin[0] += step; - } else { - origin[0] -= step; - } - if ( i & 2 ) { - origin[1] += step; - } else { - origin[1] -= step; - } - if ( i & 4 ) { - origin[2] += step; - } else { - origin[2] -= step; - } - - if ( !PointInSolid( origin ) ) { - break; - } - } - if ( i != 8 ) { - break; - } - } - if ( step > 18 ) { - // can't find a valid point at all - for ( i = 0 ; i < 8 ; i++ ) { - gridData[ num*8 + i ] = 0; - } - return; - } - } - - VectorClear( summedDir ); - - // trace to all the lights - - // find the major light direction, and divide the - // total light between that along the direction and - // the remaining in the ambient - numCon = 0; - for ( light = lights ; light ; light = light->next ) { - vec3_t add; - vec3_t dir; - float addSize; - - if ( !LightContributionToPoint( light, origin, add, &tw ) ) { - continue; - } - - VectorSubtract( light->origin, origin, dir ); - VectorNormalize( dir, dir ); - - VectorCopy( add, contributions[numCon].color ); - VectorCopy( dir, contributions[numCon].dir ); - numCon++; - - addSize = VectorLength( add ); - VectorMA( summedDir, addSize, dir, summedDir ); - - if ( numCon == MAX_CONTRIBUTIONS-1 ) { - break; - } - } - - // - // trace directly to the sun - // - SunToPoint( origin, &tw, color ); - addSize = VectorLength( color ); - if ( addSize > 0 ) { - VectorCopy( color, contributions[numCon].color ); - VectorCopy( sunDirection, contributions[numCon].dir ); - VectorMA( summedDir, addSize, sunDirection, summedDir ); - numCon++; - } - - - // now that we have identified the primary light direction, - // go back and seperate all the light into directed and ambient - VectorNormalize( summedDir, summedDir ); - VectorCopy( ambientColor, color ); - VectorClear( directedColor ); - - for ( i = 0 ; i < numCon ; i++ ) { - float d; - - d = DotProduct( contributions[i].dir, summedDir ); - if ( d < 0 ) { - d = 0; - } - - VectorMA( directedColor, d, contributions[i].color, directedColor ); - - // the ambient light will be at 1/4 the value of directed light - d = 0.25 * ( 1.0 - d ); - VectorMA( color, d, contributions[i].color, color ); - } - - // now do some fudging to keep the ambient from being too low - VectorMA( color, 0.25, directedColor, color ); - - // - // save the resulting value out - // - ColorToBytes( color, gridData + num*8 ); - ColorToBytes( directedColor, gridData + num*8 + 3 ); - - VectorNormalize( summedDir, summedDir ); - NormalToLatLong( summedDir, gridData + num*8 + 6); -} - - -/* -============= -SetupGrid -============= -*/ -void SetupGrid( void ) { - int i; - vec3_t maxs; - - for ( i = 0 ; i < 3 ; i++ ) { - gridMins[i] = gridSize[i] * ceil( dmodels[0].mins[i] / gridSize[i] ); - maxs[i] = gridSize[i] * floor( dmodels[0].maxs[i] / gridSize[i] ); - gridBounds[i] = (maxs[i] - gridMins[i])/gridSize[i] + 1; - } - - numGridPoints = gridBounds[0] * gridBounds[1] * gridBounds[2]; - if (numGridPoints * 8 >= MAX_MAP_LIGHTGRID) - Error("MAX_MAP_LIGHTGRID"); - qprintf( "%5i gridPoints\n", numGridPoints ); -} - -//============================================================================= - -/* -============= -RemoveLightsInSolid -============= -*/ -void RemoveLightsInSolid(void) -{ - light_t *light, *prev; - int numsolid = 0; - - prev = NULL; - for ( light = lights ; light ; ) { - if (PointInSolid(light->origin)) - { - if (prev) prev->next = light->next; - else lights = light->next; - if (light->w) - FreeWinding(light->w); - free(light); - numsolid++; - if (prev) - light = prev->next; - else - light = lights; - } - else - { - prev = light; - light = light->next; - } - } - _printf (" %7i lights in solid\n", numsolid); -} - -/* -============= -LightWorld -============= -*/ -void LightWorld (void) { - float f; - - // determine the number of grid points - SetupGrid(); - - // find the optional world ambient - GetVectorForKey( &entities[0], "_color", ambientColor ); - f = FloatForKey( &entities[0], "ambient" ); - VectorScale( ambientColor, f, ambientColor ); - - // create lights out of patches and lights - qprintf ("--- CreateLights ---\n"); - CreateEntityLights (); - qprintf ("%i point lights\n", numPointLights); - qprintf ("%i area lights\n", numAreaLights); - - if (!nogridlighting) { - qprintf ("--- TraceGrid ---\n"); - RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid ); - qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1], - gridBounds[2], numGridPoints); - } - - qprintf ("--- TraceLtm ---\n"); - RunThreadsOnIndividual( numDrawSurfaces, qtrue, TraceLtm ); - qprintf( "%5i visible samples\n", c_visible ); - qprintf( "%5i occluded samples\n", c_occluded ); -} - -/* -======== -CreateFilters - -EXPERIMENTAL, UNUSED - -Look for transparent light filter surfaces. - -This will only work for flat 3*3 patches that exactly hold one copy of the texture. -======== -*/ -#define PLANAR_PATCH_EPSILON 0.1 -void CreateFilters( void ) { - int i; - filter_t *f; - dsurface_t *ds; - shaderInfo_t *si; - drawVert_t *v1, *v2, *v3; - vec3_t d1, d2; - int vertNum; - - numFilters = 0; - - return; - - for ( i = 0 ; i < numDrawSurfaces ; i++ ) { - ds = &drawSurfaces[i]; - if ( !ds->patchWidth ) { - continue; - } - si = ShaderInfoForShader( dshaders[ ds->shaderNum ].shader ); -/* - if ( !(si->surfaceFlags & SURF_LIGHTFILTER) ) { - continue; - } -*/ - - // we have a filter patch - v1 = &drawVerts[ ds->firstVert ]; - - if ( ds->patchWidth != 3 || ds->patchHeight != 3 ) { - _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't a 3 by 3\n", - v1->xyz[0], v1->xyz[1], v1->xyz[2] ); - continue; - } - - if ( numFilters == MAX_FILTERS ) { - Error( "MAX_FILTERS" ); - } - f = &filters[ numFilters ]; - numFilters++; - - v2 = &drawVerts[ ds->firstVert + 2 ]; - v3 = &drawVerts[ ds->firstVert + 6 ]; - - VectorSubtract( v2->xyz, v1->xyz, d1 ); - VectorSubtract( v3->xyz, v1->xyz, d2 ); - VectorNormalize( d1, d1 ); - VectorNormalize( d2, d2 ); - CrossProduct( d1, d2, f->plane ); - f->plane[3] = DotProduct( v1->xyz, f->plane ); - - // make sure all the control points are on the plane - for ( vertNum = 0 ; vertNum < ds->numVerts ; vertNum++ ) { - float d; - - d = DotProduct( drawVerts[ ds->firstVert + vertNum ].xyz, f->plane ) - f->plane[3]; - if ( fabs( d ) > PLANAR_PATCH_EPSILON ) { - break; - } - } - if ( vertNum != ds->numVerts ) { - numFilters--; - _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't flat\n", - v1->xyz[0], v1->xyz[1], v1->xyz[2] ); - continue; - } - } - - f = &filters[0]; - numFilters = 1; - - f->plane[0] = 1; - f->plane[1] = 0; - f->plane[2] = 0; - f->plane[3] = 448; - - f->origin[0] = 448; - f->origin[1] = 192; - f->origin[2] = 0; - - f->vectors[0][0] = 0; - f->vectors[0][1] = -1.0 / 128; - f->vectors[0][2] = 0; - - f->vectors[1][0] = 0; - f->vectors[1][1] = 0; - f->vectors[1][2] = 1.0 / 128; - - f->si = ShaderInfoForShader( "textures/hell/blocks11ct" ); -} - -/* -============= -VertexLightingThread -============= -*/ -void VertexLightingThread(int num) { - dsurface_t *ds; - traceWork_t tw; - shaderInfo_t *si; - - ds = &drawSurfaces[num]; - - // vertex-lit triangle model - if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { - return; - } - - if (novertexlighting) - return; - - if ( ds->lightmapNum == -1 ) { - return; // doesn't need lighting at all - } - - si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); - - // calculate the vertex lighting for gouraud shade mode - VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw ); -} - -/* -============= -TriSoupLightingThread -============= -*/ -void TriSoupLightingThread(int num) { - dsurface_t *ds; - traceWork_t tw; - shaderInfo_t *si; - - ds = &drawSurfaces[num]; - si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); - - // vertex-lit triangle model - if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { - VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw ); - } -} - -/* -============= -GridAndVertexLighting -============= -*/ -void GridAndVertexLighting(void) { - SetupGrid(); - - FindSkyBrushes(); - CreateFilters(); - InitTrace(); - CreateEntityLights (); - CreateSurfaceLights(); - - if (!nogridlighting) { - _printf ("--- TraceGrid ---\n"); - RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid ); - } - - if (!novertexlighting) { - _printf ("--- Vertex Lighting ---\n"); - RunThreadsOnIndividual( numDrawSurfaces, qtrue, VertexLightingThread ); - } - - _printf("--- Model Lighting ---\n"); - RunThreadsOnIndividual( numDrawSurfaces, qtrue, TriSoupLightingThread ); -} - -/* -======== -LightMain - -======== -*/ -int LightMain (int argc, char **argv) { - int i; - double start, end; - const char *value; - - _printf ("----- Lighting ----\n"); - - verbose = qfalse; - - for (i=1 ; i<argc ; i++) { - if (!strcmp(argv[i],"-tempname")) - { - i++; - } else if (!strcmp(argv[i],"-v")) { - verbose = qtrue; - } else if (!strcmp(argv[i],"-threads")) { - numthreads = atoi (argv[i+1]); - i++; - } else if (!strcmp(argv[i],"-area")) { - areaScale *= atof(argv[i+1]); - _printf ("area light scaling at %f\n", areaScale); - i++; - } else if (!strcmp(argv[i],"-point")) { - pointScale *= atof(argv[i+1]); - _printf ("point light scaling at %f\n", pointScale); - i++; - } else if (!strcmp(argv[i],"-notrace")) { - notrace = qtrue; - _printf ("No occlusion tracing\n"); - } else if (!strcmp(argv[i],"-patchshadows")) { - patchshadows = qtrue; - _printf ("Patch shadow casting enabled\n"); - } else if (!strcmp(argv[i],"-extra")) { - extra = qtrue; - _printf ("Extra detail tracing\n"); - } else if (!strcmp(argv[i],"-extrawide")) { - extra = qtrue; - extraWide = qtrue; - _printf ("Extra wide detail tracing\n"); - } else if (!strcmp(argv[i], "-samplesize")) { - samplesize = atoi(argv[i+1]); - if (samplesize < 1) samplesize = 1; - i++; - _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize); - } else if (!strcmp(argv[i], "-novertex")) { - novertexlighting = qtrue; - _printf("no vertex lighting = true\n"); - } else if (!strcmp(argv[i], "-nogrid")) { - nogridlighting = qtrue; - _printf("no grid lighting = true\n"); - } else if (!strcmp(argv[i],"-border")) { - lightmapBorder = qtrue; - _printf ("Adding debug border to lightmaps\n"); - } else if (!strcmp(argv[i],"-nosurf")) { - noSurfaces = qtrue; - _printf ("Not tracing against surfaces\n" ); - } else if (!strcmp(argv[i],"-dump")) { - dump = qtrue; - _printf ("Dumping occlusion maps\n"); - } else { - break; - } - } - - ThreadSetDefault (); - - if (i != argc - 1) { - _printf("usage: q3map -light [-<switch> [-<switch> ...]] <mapname>\n" - "\n" - "Switches:\n" - " v = verbose output\n" - " threads <X> = set number of threads to X\n" - " area <V> = set the area light scale to V\n" - " point <W> = set the point light scale to W\n" - " notrace = don't cast any shadows\n" - " extra = enable super sampling for anti-aliasing\n" - " extrawide = same as extra but smoothen more\n" - " nogrid = don't calculate light grid for dynamic model lighting\n" - " novertex = don't calculate vertex lighting\n" - " samplesize <N> = set the lightmap pixel size to NxN units\n"); - exit(0); - } - - start = I_FloatTime (); - - SetQdirFromPath (argv[i]); - -#ifdef _WIN32 - InitPakFile(gamedir, NULL); -#endif - - strcpy (source, ExpandArg(argv[i])); - StripExtension (source); - DefaultExtension (source, ".bsp"); - - LoadShaderInfo(); - - _printf ("reading %s\n", source); - - LoadBSPFile (source); - - FindSkyBrushes(); - - ParseEntities(); - - value = ValueForKey( &entities[0], "gridsize" ); - if (strlen(value)) { - sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] ); - _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]); - } - - CreateFilters(); - - InitTrace(); - - SetEntityOrigins(); - - CountLightmaps(); - - CreateSurfaceLights(); - - LightWorld(); - - _printf ("writing %s\n", source); - WriteBSPFile (source); - - end = I_FloatTime (); - _printf ("%5.0f seconds elapsed\n", end-start); - - return 0; -} - |