⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 light.c

📁 quake3工具源码。包括生成bsp文件
💻 C
📖 第 1 页 / 共 4 页
字号:
// 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;
			}
		}
	}
}

//=================================================================

/*
================

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -