// Level static lights octree, used to boost performance on finding out lightbrightness of a spot.
Class VisOctreeNode extends Object
	transient;

const MAX_NODE_DEPTH=6;

#if GAMEVER==227
const MAX_LIGHTS_PER_NODE=128;
var array<VisLightData> LightSources;
#else
const MAX_LIGHTS_PER_NODE=63;
var VisLightData LightSources[MAX_LIGHTS_PER_NODE];
#endif

var VisOctreeNode Child[8];
var byte NumLSources,NumDepth;
var vector Center;
var float Extent,BrightnessMulti;
var int CurrentTag;

final function Init( vector Pos, float Ext )
{
	Center = Pos;
	Extent = Ext;
}
final function AddChildren()
{
	local byte i,TN;
	local vector V;
	local float E;
#if GAMEVER==227
	local array<VisLightData> T;
#else
	local VisLightData T[MAX_LIGHTS_PER_NODE];
#endif

	E = Extent*0.5;
	for( i=0; i<ArrayCount(Child); ++i )
	{
		V = Center;
		if( (i & 1)!=0 )
			V.X+=E;
		else V.X-=E;
		if( (i & 2)!=0 )
			V.Y+=E;
		else V.Y-=E;
		if( (i & 4)!=0 )
			V.Z+=E;
		else V.Z-=E;

		Child[i] = new(None) Class'VisOctreeNode';
		Child[i].Init(V,E);
		Child[i].NumDepth = NumDepth+1;
	}
	// Now re-filter the children down.
	TN = NumLSources;
#if GAMEVER==227
	T = LightSources;
	Array_Size(LightSources,0);
#else
	for( i=0; i<NumLSources; ++i )
		T[i] = LightSources[i];
#endif
	NumLSources = 0;
	for( i=0; i<TN; ++i )
		AddLightInternal(T[i]);
}
final function bool TouchesLight( vector V, float Radius )
{
	Radius+=Extent;
	return (Abs(V.X-Center.X)<Radius &&
				Abs(V.Y-Center.Y)<Radius && 
				Abs(V.Z-Center.Z)<Radius);
}
final function bool EncompassesLight( vector V, float Radius )
{
	V -= Center;
	return ((V.X+Radius)>Extent && (V.X-Radius)<-Extent &&
			(V.Y+Radius)>Extent && (V.Y-Radius)<-Extent && 
			(V.Z+Radius)>Extent && (V.Z-Radius)<-Extent);
}
final function AddLightInternal( VisLightData L )
{
	local vector V;
	local byte i;

	V = L.Light.Location;

	// Not yet splitted.
	if( Child[0]==None || EncompassesLight(V,L.Radius) )
	{
		// Time to split it up and recheck...
		if( NumLSources>5 && NumDepth<MAX_NODE_DEPTH && Child[0]==None )
		{
			AddChildren();
			AddLightInternal(L);
			return;
		}
		if( NumLSources<MAX_LIGHTS_PER_NODE )
			LightSources[NumLSources++] = L;
	}
	else // Filter it down.
	{
		for( i=0; i<ArrayCount(Child); ++i )
		{
			if( Child[i].TouchesLight(V,L.Radius) )
				Child[i].AddLightInternal(L);
		}
	}
}
final function AddLight( Actor L )
{
	local VisLightData D;
	
	D = new(None)Class'VisLightData';
	D.Light = L;
	D.Radius = 25.f * (L.LightRadius+1);
	D.RRadius = 1.f / D.Radius;
	BrightnessMulti = 1.f/255.f;
	AddLightInternal(D);
}
#if GAMEVER<227
final function bool FastTrace( Actor Other, vector Start, vector End )
{
	local vector D;
	return (A.Trace(D,D,End,Start,false)==None);
}
#endif

final function float GetLights( vector P )
{
	local byte i;
	local float D,Result;
	local VisLightData L;
	local VisOctreeNode N;

	N = Self;
	while( true )
	{
		for( i=0; i<N.NumLSources; ++i )
		{
			L = N.LightSources[i];
			D = VSize(P-L.Light.Location);
			if( L.Light.LightBrightness>0 && D<L.Radius &&
#if GAMEVER>=227
				L.Light.FastTrace(P,L.Light.Location) )
#else
				FastTrace(L.Light,P,L.Light.Location) )
#endif
			{
				Result+=((1.f - (D*L.RRadius)) * L.Light.LightBrightness);
				if( Result>=512 )
					return Result;
			}
		}
		if( N.Child[0]==None )
			break;

		i = int(P.X>N.Center.X) | (int(P.Y>N.Center.Y) << 1) | (int(P.Z>N.Center.Z) << 2);
		N = N.Child[i];
	}
	return Result;
}

defaultproperties
{
	Extent=32768
}