#include "stdafx.h"
#include "TerrainNode.h"

void cTerrainBranchNode::Cull()
{
	unsigned int saveActive = mFrustum->GetActivePlaneState();
	unsigned int side = 0;
	unsigned int c = 0;
	{
		if( mFrustum->IsPlaneActive( NiFrustumPlanes::FAR_PLANE ) )
		{
			side = mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::FAR_PLANE) );

			if( side == NiPlane::NEGATIVE_SIDE )
			{
				// The object is not visible since it is on the negative
				// side of the plane.
				mFrustum->SetActivePlaneState(saveActive);
				return;
			}
			if( side == NiPlane::POSITIVE_SIDE )
			{
				// The object is fully on the positive side of the plane,
				// so there is no need to compare child objects to this plane.
				mFrustum->DisablePlane( NiFrustumPlanes::FAR_PLANE );
				++c;
			}
		}
		if( mFrustum->IsPlaneActive( NiFrustumPlanes::LEFT_PLANE ) )
		{
			side = mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::LEFT_PLANE) );

			if( side == NiPlane::NEGATIVE_SIDE )
			{
				mFrustum->SetActivePlaneState(saveActive);
				return;
			}
			if( side == NiPlane::POSITIVE_SIDE )
			{
				mFrustum->DisablePlane( NiFrustumPlanes::LEFT_PLANE );
				++c;
			}
		}
		if( mFrustum->IsPlaneActive( NiFrustumPlanes::RIGHT_PLANE ) )
		{
			side = mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::RIGHT_PLANE) );

			if( side == NiPlane::NEGATIVE_SIDE )
			{
				mFrustum->SetActivePlaneState(saveActive);
				return;
			}
			if( side == NiPlane::POSITIVE_SIDE )
			{
				mFrustum->DisablePlane( NiFrustumPlanes::RIGHT_PLANE );
				++c;
			}
		}
		if( mFrustum->IsPlaneActive( NiFrustumPlanes::TOP_PLANE ) )
		{
			side = mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::TOP_PLANE) );

			if( side == NiPlane::NEGATIVE_SIDE )
			{
				mFrustum->SetActivePlaneState(saveActive);
				return;
			}
			if( side == NiPlane::POSITIVE_SIDE )
			{
				mFrustum->DisablePlane( NiFrustumPlanes::TOP_PLANE );
				++c;
			}
		}
		if( mFrustum->IsPlaneActive( NiFrustumPlanes::BOTTOM_PLANE ) )
		{
			side = mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::BOTTOM_PLANE) );

			if( side == NiPlane::NEGATIVE_SIDE )
			{
				mFrustum->SetActivePlaneState(saveActive);
				return;
			}
			if( side == NiPlane::POSITIVE_SIDE )
			{
				mFrustum->DisablePlane( NiFrustumPlanes::BOTTOM_PLANE );
				++c;
			}
		}
	}

	if( c == 5 )
	{
		/// 완전 포함 -> 자손들을 모두 추가
		AddToVisibleArray();
	}
	else
	{
		/// 교차 -> 컬링 검사를 계속
		mChild[0]->Cull();
		mChild[1]->Cull();
		mChild[2]->Cull();
		mChild[3]->Cull();
	}

	mFrustum->SetActivePlaneState( saveActive );
}

void cTerrainBranchNode::AddToVisibleArray()
{
	mChild[0]->AddToVisibleArray();
	mChild[1]->AddToVisibleArray();
	mChild[2]->AddToVisibleArray();
	mChild[3]->AddToVisibleArray();
}

void cTerrainLeafNode::Cull()
{
	if( mVisible == false )
		return;
	if( mFrustum->IsPlaneActive(NiFrustumPlanes::FAR_PLANE) && mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::FAR_PLANE) ) == NiPlane::NEGATIVE_SIDE )
		return;
	if( mFrustum->IsPlaneActive(NiFrustumPlanes::LEFT_PLANE) && mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::LEFT_PLANE) ) == NiPlane::NEGATIVE_SIDE )
		return;
	if( mFrustum->IsPlaneActive(NiFrustumPlanes::RIGHT_PLANE) && mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::RIGHT_PLANE) ) == NiPlane::NEGATIVE_SIDE )
		return;
	if( mFrustum->IsPlaneActive(NiFrustumPlanes::TOP_PLANE) && mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::TOP_PLANE) ) == NiPlane::NEGATIVE_SIDE )
		return;
	if( mFrustum->IsPlaneActive(NiFrustumPlanes::BOTTOM_PLANE) && mBoundBox.WhichSide( mFrustum->GetPlane(NiFrustumPlanes::BOTTOM_PLANE) ) == NiPlane::NEGATIVE_SIDE )
		return;

	mVisibleArray->PushBack( this );
}

void cTerrainLeafNode::AddToVisibleArray()
{
	if( mVisible )
	{
		mVisibleArray->PushBack( this );
	}
}
