radial.cpp

来自「hl2 source code. Do not use it illegal.」· C++ 代码 · 共 891 行 · 第 1/2 页

CPP
891
字号
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// $Header: $
// $NoKeywords: $
//
//=============================================================================

#include "vrad.h"
#include "lightmap.h"
#include "radial.h"
#include <bumpvects.h>
#include "UtlRBTree.h"
#include "VMatrix.h"
#include "macro_texture.h"


void WorldToLuxelSpace( lightinfo_t const *l, Vector const &world, Vector2D &coord )
{
	Vector pos;

	VectorSubtract( world, l->luxelOrigin, pos );
	coord[0] = DotProduct( pos, l->worldToLuxelSpace[0] ) - l->face->m_LightmapTextureMinsInLuxels[0];
	coord[1] = DotProduct( pos, l->worldToLuxelSpace[1] ) - l->face->m_LightmapTextureMinsInLuxels[1];
}

void LuxelSpaceToWorld( lightinfo_t const *l, float s, float t, Vector &world )
{
	Vector pos;

	s += l->face->m_LightmapTextureMinsInLuxels[0];
	t += l->face->m_LightmapTextureMinsInLuxels[1];
	VectorMA( l->luxelOrigin, s, l->luxelToWorldSpace[0], pos );
	VectorMA( pos, t, l->luxelToWorldSpace[1], world );
}



void AddDirectToRadial( radial_t *rad, 
				  Vector const &pnt, 
				  Vector2D const &coordmins, Vector2D const &coordmaxs, 
				  Vector const light[NUM_BUMP_VECTS+1],
				  bool hasBumpmap, bool neighborHasBumpmap  )
{
	int     s_min, s_max, t_min, t_max;
	Vector2D  coord;
	int	    s, t;
	float   ds, dt;
	float   r;
	float	area;
	int		bumpSample;

	// convert world pos into local lightmap texture coord
	WorldToLuxelSpace( &rad->l, pnt, coord );

	s_min = ( int )( coordmins[0] );
	t_min = ( int )( coordmins[1] );
	s_max = ( int )( coordmaxs[0] + 0.9999f ) + 1; // ????
	t_max = ( int )( coordmaxs[1] + 0.9999f ) + 1;

	s_min = max( s_min, 0 );
	t_min = max( t_min, 0 );
	s_max = min( s_max, rad->w );
	t_max = min( t_max, rad->h );

	for( s = s_min; s < s_max; s++ )
	{
		for( t = t_min; t < t_max; t++ )
		{
			float s0 = max( coordmins[0] - s, -1.0 );
			float t0 = max( coordmins[1] - t, -1.0 );
			float s1 = min( coordmaxs[0] - s, 1.0 );
			float t1 = min( coordmaxs[1] - t, 1.0 );

			area = (s1 - s0) * (t1 - t0);

			if (area > EQUAL_EPSILON)
			{
				ds = fabs( coord[0] - s );
				dt = fabs( coord[1] - t );

				r = max( ds, dt );

				if (r < 0.1)
				{
					r = area / 0.1;
				}
				else
				{
					r = area / r;
				}

				int i = s+t*rad->w;

				if( hasBumpmap )
				{
					if( neighborHasBumpmap )
					{
						for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
						{
							VectorMA( rad->light[bumpSample][i], r, light[bumpSample], rad->light[bumpSample][i] );
						}
					}
					else
					{
						VectorMA( rad->light[0][i], r, light[0], rad->light[0][i] );
						for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
						{
							VectorMA( rad->light[bumpSample][i], r * OO_SQRT_3, light[0], rad->light[bumpSample][i] );
						}
					}
				}
				else
				{
					VectorMA( rad->light[0][i], r, light[0], rad->light[0][i] );
				}
				
				rad->weight[i] += r;
			}
		}
	}
}



void AddBouncedToRadial( radial_t *rad, 
				  Vector const &pnt, 
				  Vector2D const &coordmins, Vector2D const &coordmaxs, 
				  Vector const light[NUM_BUMP_VECTS+1],
				  bool hasBumpmap, bool neighborHasBumpmap  )
{
	int     s_min, s_max, t_min, t_max;
	Vector2D  coord;
	int	    s, t;
	float   ds, dt;
	float   r;
	int		bumpSample;

	// convert world pos into local lightmap texture coord
	WorldToLuxelSpace( &rad->l, pnt, coord );

	float dists, distt;

	dists = (coordmaxs[0] - coordmins[0]);
	distt = (coordmaxs[1] - coordmins[1]);

	// patches less than a luxel in size could be mistakeningly filtered, so clamp.
	dists = max( 1.0, dists );
	distt = max( 1.0, distt );

	// find possible domain of patch influence
  	s_min = ( int )( coord[0] - dists * RADIALDIST );
  	t_min = ( int )( coord[1] - distt * RADIALDIST );
  	s_max = ( int )( coord[0] + dists * RADIALDIST + 1.0f );
  	t_max = ( int )( coord[1] + distt * RADIALDIST + 1.0f );

	// clamp to valid luxel
	s_min = max( s_min, 0 );
	t_min = max( t_min, 0 );
	s_max = min( s_max, rad->w );
	t_max = min( t_max, rad->h );

	for( s = s_min; s < s_max; s++ )
	{
		for( t = t_min; t < t_max; t++ )
		{
			// patch influence is based on patch size
  			ds = ( coord[0] - s ) / dists;
  			dt = ( coord[1] - t ) / distt;
  
  			r = RADIALDIST2 - (ds * ds + dt * dt);

			int i = s+t*rad->w;
   
  			if (r > 0)
			{
				if( hasBumpmap )
				{
					if( neighborHasBumpmap )
					{
						for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
						{
							VectorMA( rad->light[bumpSample][i], r, light[bumpSample], rad->light[bumpSample][i] );
						}
					}
					else
					{
						VectorMA( rad->light[0][i], r, light[0], rad->light[0][i] );
						for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
						{
							VectorMA( rad->light[bumpSample][i], r * OO_SQRT_3, light[0], rad->light[bumpSample][i] );
						}
					}
				}
				else
				{
					VectorMA( rad->light[0][i], r, light[0], rad->light[0][i] );
				}
				
				rad->weight[i] += r;
			}
		}
	}
}

void PatchLightmapCoordRange( radial_t *rad, int ndxPatch, Vector2D &mins, Vector2D &maxs )
{
	winding_t	*w;
	int i;
	Vector2D coord;

	mins.Init( 1E30, 1E30 );
	maxs.Init( -1E30, -1E30 );

	patch_t *patch = &patches.Element( ndxPatch );
	w = patch->winding;

	for (i = 0; i < w->numpoints; i++)
	{
		WorldToLuxelSpace( &rad->l, w->p[i], coord );
		mins[0] = min( mins[0], coord[0] );
		maxs[0] = max( maxs[0], coord[0] );
		mins[1] = min( mins[1], coord[1] );
		maxs[1] = max( maxs[1], coord[1] );
	}
}

radial_t *AllocateRadial( int facenum )
{
	radial_t *rad;

	rad = ( radial_t* )calloc( 1, sizeof( *rad ) );

	rad->facenum = facenum;
	InitLightinfo( &rad->l, facenum );

	rad->w = rad->l.face->m_LightmapTextureSizeInLuxels[0]+1;
	rad->h = rad->l.face->m_LightmapTextureSizeInLuxels[1]+1;

	return rad;
}

void FreeRadial( radial_t *rad )
{
	if (rad)
		free( rad );
}


radial_t *BuildPatchRadial( int facenum )
{
	int             j;
	radial_t        *rad;
	patch_t	        *patch;
	faceneighbor_t  *fn;
	Vector2D        mins, maxs;
	Vector			light[NUM_BUMP_VECTS+1];
	int				bumpSample;
	bool			needsBumpmap, neighborNeedsBumpmap;

	needsBumpmap = texinfo[dfaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;

	rad = AllocateRadial( facenum );
	
	fn = &faceneighbor[ rad->facenum ];

	patch_t *pNextPatch;

	if( facePatches.Element( rad->facenum ) != facePatches.InvalidIndex() )
	{
		for( patch = &patches.Element( facePatches.Element( rad->facenum ) ); patch; patch = pNextPatch )
		{
			// next patch
			pNextPatch = NULL;
			if( patch->ndxNext != patches.InvalidIndex() )
			{
				pNextPatch = &patches.Element( patch->ndxNext );
			}
			
			// skip patches with children
			if (patch->child1 != patches.InvalidIndex() )
				continue;
			
			// get the range of patch lightmap texture coords
			int ndxPatch = patch - patches.Base();
			PatchLightmapCoordRange( rad, ndxPatch, mins, maxs );
			
			if (patch->numtransfers == 0)
			{
				// Error, using patch that was never evaluated or has no samples
				// patch->totallight[1] = 255;
			}
			
			VectorCopy( patch->totallight, light[0] );
			for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
			{
				VectorCopy( patch->totallight, light[bumpSample] );
				VectorScale( light[bumpSample], OO_SQRT_3, light[bumpSample] );
			}
			
			//
			// displacement surface patch origin position and normal vectors have been changed to
			// represent the displacement surface position and normal -- for radial "blending"
			// we need to get the base surface patch origin!
			//
			if( ValidDispFace( &dfaces[facenum] ) )
			{
				Vector patchOrigin;
				WindingCenter (patch->winding, patchOrigin );
				AddBouncedToRadial( rad, patchOrigin, mins, maxs, light,  
					needsBumpmap, needsBumpmap );			
			}
			else
			{
				AddBouncedToRadial( rad, patch->origin, mins, maxs, light, 
					needsBumpmap, needsBumpmap );
			}
		}
	}

	for (j=0 ; j<fn->numneighbors; j++)
	{
		if( facePatches.Element( fn->neighbor[j] ) != facePatches.InvalidIndex() )
		{
			for( patch = &patches.Element( facePatches.Element( fn->neighbor[j] ) ); patch; patch = pNextPatch )
			{
				// next patch
				pNextPatch = NULL;
				if( patch->ndxNext != patches.InvalidIndex() )
				{
					pNextPatch = &patches.Element( patch->ndxNext );
				}
				
				// skip patches with children
				if (patch->child1 != patches.InvalidIndex() )
					continue;
				
				// get the range of patch lightmap texture coords
				int ndxPatch = patch - patches.Base();
				PatchLightmapCoordRange( rad, ndxPatch, mins, maxs  );
				
				neighborNeedsBumpmap = texinfo[dfaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;
				for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
				{
					VectorCopy( patch->totallight, light[bumpSample] );
				}
				
				//
				// displacement surface patch origin position and normal vectors have been changed to
				// represent the displacement surface position and normal -- for radial "blending"
				// we need to get the base surface patch origin!
				//
				if( ValidDispFace( &dfaces[fn->neighbor[j]] ) )
				{
					Vector patchOrigin;
					WindingCenter (patch->winding, patchOrigin );
					AddBouncedToRadial( rad, patchOrigin, mins, maxs, light, 
						needsBumpmap, needsBumpmap );			
				}
				else
				{
					AddBouncedToRadial( rad, patch->origin, mins, maxs, light,
						needsBumpmap, needsBumpmap );
				}
			}
		}
	}

	return rad;
}


radial_t *BuildLuxelRadial( int facenum, int style )
{
	int		        j, k;
	facelight_t	    *fl;
	faceneighbor_t  *fn;

	radial_t        *rad;
	Vector			light[NUM_BUMP_VECTS + 1];
	int				bumpSample;
	Vector2D		coordmins, coordmaxs;

	fl = &facelight[facenum];
	fn = &faceneighbor[facenum];

	rad = AllocateRadial( facenum );

	bool needsBumpmap = texinfo[dfaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;

	for (k=0 ; k<fl->numsamples ; k++)
	{
		if( needsBumpmap )
		{
			for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
			{
				VectorCopy( fl->light[style][bumpSample][k], light[bumpSample] );
			}
		}
		else
		{
			VectorCopy( fl->light[style][0][k], light[0] );
		}

		AddDirectToRadial( rad, fl->sample[k].pos, fl->sample[k].mins, fl->sample[k].maxs, light, needsBumpmap, needsBumpmap );
	}

	for (j = 0; j < fn->numneighbors; j++)
	{
		fl = &facelight[fn->neighbor[j]];

		bool neighborHasBumpmap = false;
		
		if( texinfo[dfaces[fn->neighbor[j]].texinfo].flags & SURF_BUMPLIGHT )
		{
			neighborHasBumpmap = true;
		}

		int nstyle = 0;

		// look for style that matches
		if (dfaces[fn->neighbor[j]].styles[nstyle] != dfaces[facenum].styles[style])
		{
			for (nstyle = 1; nstyle < MAXLIGHTMAPS; nstyle++ )
				if ( dfaces[fn->neighbor[j]].styles[nstyle] == dfaces[facenum].styles[style] )
					break;

			// if not found, skip this neighbor
			if (nstyle >= MAXLIGHTMAPS)
				continue;
		}

		lightinfo_t l;

		InitLightinfo( &l, fn->neighbor[j] );

		for (k=0 ; k<fl->numsamples ; k++)
		{
			if( neighborHasBumpmap )
			{
				for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
				{

⌨️ 快捷键说明

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