aboutsummaryrefslogtreecommitdiffstats
path: root/q3map/light.c
diff options
context:
space:
mode:
authortma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-09-28 18:55:31 +0000
committertma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-09-28 18:55:31 +0000
commitec912002d3f75729c627cf467903c4607a529495 (patch)
treeb944aa3ec6a159d4607b3bb25cb09640bca02ddb /q3map/light.c
parentea1ca0473a510a02fff82788a2a6c8d95a6bf2d3 (diff)
downloadioquake3-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.c2149
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;
-}
-