#include "stdafx.h"
#include "Box.h"

#include "Ray.h"
#include "Sphere.h"

bool cBox::IntersectRay( const cRay& r, float& scale ) const
{
	const NiPoint3 &origin = r.GetOrigin();
	const NiPoint3 &dir = r.GetDirection();

	int ax0, ax1, ax2, side, inside;
	float f;
	NiPoint3 hit;

	ax0 = -1;
	inside = 0;

	for( int i = 0; i < 3; ++i )
	{
		if( origin[i] < mPoints[0][i] )
		{
			side = 0;
		}
		else if( origin[i] > mPoints[1][i] )
		{
			side = 1;
		}
		else
		{
			inside++;
			continue;
		}
		if( dir[i] == 0.0f )
		{
			continue;
		}
		f = ( origin[i] - mPoints[side][i] );
		if( ax0 < 0 || NiAbs( f ) > NiAbs( scale * dir[i] ) )
		{
			scale = - ( f / dir[i] );
			ax0 = i;
		}
	}

	if( ax0 < 0 )
	{
		scale = 0.0f;
		/// return true if the start point is inside the bounds
		return ( inside == 3 );
	}

	ax1 = (ax0 + 1) % 3;
	ax2 = (ax0 + 2) % 3;
	hit[ax1] = origin[ax1] + scale * dir[ax1];
	hit[ax2] = origin[ax2] + scale * dir[ax2];

	return ( hit[ax1] >= mPoints[0][ax1] && hit[ax1] <= mPoints[1][ax1] &&
		hit[ax2] >= mPoints[0][ax2] && hit[ax2] <= mPoints[1][ax2] );
}

bool cBox::IntersectRay( const cRay& r, float& scale, float maxDistance ) const
{
	const NiPoint3 &origin = r.GetOrigin();
	const NiPoint3 &dir = r.GetDirection();

	int ax0, ax1, ax2, side, inside;
	float f;
	NiPoint3 hit;

	ax0 = -1;
	inside = 0;

	for( int i = 0; i < 3; ++i )
	{
		if( origin[i] < mPoints[0][i] )
		{
			side = 0;
		}
		else if( origin[i] > mPoints[1][i] )
		{
			side = 1;
		}
		else
		{
			inside++;
			continue;
		}
		if( dir[i] == 0.0f )
		{
			continue;
		}
		f = ( origin[i] - mPoints[side][i] );
		if( ax0 < 0 || NiAbs( f ) > NiAbs( scale * dir[i] ) )
		{
			scale = - ( f / dir[i] );
			ax0 = i;
		}
	}

	if( ax0 < 0 )
	{
		scale = 0.0f;
		/// return true if the start point is inside the bounds
		return ( inside == 3 );
	}
	if( scale > maxDistance )
		return false;

	ax1 = (ax0 + 1) % 3;
	ax2 = (ax0 + 2) % 3;
	hit[ax1] = origin[ax1] + scale * dir[ax1];
	hit[ax2] = origin[ax2] + scale * dir[ax2];

	return ( hit[ax1] >= mPoints[0][ax1] && hit[ax1] <= mPoints[1][ax1] &&
		hit[ax2] >= mPoints[0][ax2] && hit[ax2] <= mPoints[1][ax2] );
}

bool cBox::IntersectSphere( const cSphere& sphere ) const
{
	const NiPoint3& c = sphere.GetCenter();
	float s, d = 0.0f;

	// x
	if( c.x < mPoints[0].x )
	{
		s = c.x - mPoints[0].x;
		d += s * s;
	}
	else if( c.x > mPoints[1].x )
	{
		s = c.x - mPoints[1].x;
		d += s * s;
	}

	// y
	if( c.y < mPoints[0].y )
	{
		s = c.y - mPoints[0].y;
		d += s * s;
	}
	else if( c.y > mPoints[1].y )
	{
		s = c.y - mPoints[1].y;
		d += s * s;
	}

	// z
	if( c.z < mPoints[0].z )
	{
		s = c.z - mPoints[0].z;
		d += s * s;
	}
	else if( c.z > mPoints[1].z )
	{
		s = c.z - mPoints[1].z;
		d += s * s;
	}

	if( d > sphere.GetRadius2() )
		return false;
	return true;
}

bool cBox::IntersectBox( const cBox& box ) const
{
	const NiPoint3& min = box.GetMin();
	const NiPoint3& max = box.GetMax();

	/// x
	if( mPoints[0].x > max.x || mPoints[1].x < min.x ) return false;
	/// y
	if( mPoints[0].y > max.y || mPoints[1].y < min.y ) return false;
	/// z
	if( mPoints[0].z > max.z || mPoints[1].z < min.z ) return false;
	return true;
}
