#include "StdAfx.h"
#include ".\vehiclescenenode.h"

#include "SceneManager.h"
#include "RenderSystem.h"
#include "PlayerSceneNode.h"
#include "EffectSceneNode.h"
#include "ResourceManager.h"
#include "LightAgent.h"
#include "FogAgent.h"
#include "CameraManager.h"

#include "Player_Common.h"
#include "Player.h"
#include "Vehicle_Common.h"
#include "VehicleScript.h"
#include "ObjectNameCard.h"

cVehicleSceneNode::cVehicleSceneNode( eType type )
: cDynamicSceneNode(type)
, mScriptData(0)
, mPlayerSceneNode(0)
{
	mCheckAnimationId = 0;
}

cVehicleSceneNode::~cVehicleSceneNode()
{
}

bool cVehicleSceneNode::Init( const cVehicleSceneNodeParam& param )
{
	mPlayerSceneNode = param.mPlayerSceneNode;
	if( mPlayerSceneNode == 0 )
	{
		assert(0);
		return false;
	}

	mScriptData = VEHICLESCRIPT->GetVehicleInfo( param.mVehicleIndex );
	if( mScriptData == 0 )
	{
		assert(0);
		return false;
	}

	mpGameObject = mPlayerSceneNode->GetGameObject();

	mPlayerSceneNode->AnimationReset();
	mScaleAccumTime = mPlayerSceneNode->GetScaleAccumTime();
	mLastTime = mPlayerSceneNode->GetLastTime();
	UpdateAniScaleFactor( mPlayerSceneNode->GetAniScaleFactor() );

	cString fileName;
	fileName.Format( "./data/monster/%s", mScriptData->mFileName );
	mpModel = RESOURCEMAN->LoadKFM( fileName.Cstr() );
	if( mpModel == 0 )
	{
		assert(0 && "Model file not found");
		return false;
	}

	if( InitLinkInfo() == false )
		return false;

	/// ActorManager 생성..
	mpActorManager = cActorManagerForPartition::Create( mpModel );
	if( mpActorManager == 0 )
	{
		assert( 0 && "null actor manager" );
		return false;
	}

	/// 모핑 정보가 있다면 셋팅한다.
	mpMorpherController = mpActorManager->GetMorpherController();
	if( mpMorpherController )
	{
//		mpMorpherController->SetActive( false );
		mpMorpherController->SetAlwaysUpdate( false );
//		mpMorpherController->Stop();

		StartMorpher();
	}

	/// 갱신
	mpActorManager->Update(0.0f);

	/// 엔진 노드를 설정
	//	NiNode* n = GetNiObj();
	mSceneNiNode = mpActorManager->GetNifRoot();
	if( GetNiObj() == 0 )
	{
		assert( 0 && "null node" );
		return false;
	}

	/// 변환 행렬을 설정
	GetNiObj()->SetTranslate( param.mTranslate );
	GetNiObj()->SetRotate( param.mRotate );
	GetNiObj()->SetScale( param.mScale );

	NiAmbientLight* amb = FindAmbientLight( GetNiObj() );
	if( amb )
		GetNiNode()->DetachChild( amb );

	/// 조명을 부착
	GetNiNode()->AttachEffect( LIGHTAGENT->GetSceneAmbientLight( 1 ) );
	GetNiNode()->AttachEffect( LIGHTAGENT->GetSceneDirLight( 1 ) );

	/// 안개 속성을 부착
	GetNiNode()->AttachProperty( FOGAGENT->GetFogProperty() );

	{
		/// 기하 오브젝트들을 수집
		cString texPath;
		texPath.Format( "./data/monster/%s", mScriptData->mTextureName.Cstr() );
		NiTexture* tex = RESOURCEMAN->LoadTexture( texPath.Cstr() );

		if( tex )
			CollectGeomsEx( GetNiObj(), tex );
		else
			CollectGeoms( GetNiObj() );

		/// 빌보드 노드들을 수집
		CollectBillboards( GetNiObj() );

		/// 픽킹 방식을 설정
		mPick.SetPickType( param.mPickType );
		mPick.SetSortType( param.mPickSort );
		mPick.SetIntersectType( param.mPickIntersect );
		mPick.SetCoordinateType( param.mPickCoordinate );
		mPick.SetFrontOnly( param.mPickFrontOnly );
		mPick.SetReturnTexture( param.mPickReturnTexture );
		mPick.SetReturnNormal( param.mPickReturnNormal );
		mPick.SetReturnSmoothNormal( false );
		mPick.SetReturnColor( param.mPickReturnColor );
		mPick.SetTarget( GetNiObj() );

		//		/// 경계 구를 설정
		GetNiNode()->Update( 0.0f );

		/// 갱신 여부를 설정
		mNeedUpdateTransform = true;
	}

	/// 알파 속성이 없으면 생성
	NiAlphaProperty* alphaProp = (NiAlphaProperty*)GetNiObj()->GetProperty( NiProperty::ALPHA );
	if( alphaProp == 0 )
	{
		alphaProp = NiNew NiAlphaProperty;
		alphaProp->SetAlphaBlending( false );
		alphaProp->SetAlphaTesting( false );
		alphaProp->SetTestMode(NiAlphaProperty::TEST_GREATEREQUAL);
		GetNiObj()->AttachProperty( alphaProp );
	}

	CollectProperties( GetNiObj() );

	/// picking용 데이터를 추출 한다.
	CollectPickData( GetNiObj() );

	mPick.SetPickType( NiPick::FIND_FIRST );
	mPick.SetIntersectType( NiPick::TRIANGLE_INTERSECT );
	mPick.SetSortType( NiPick::NO_SORT );
	mPick.SetFrontOnly( false );

	/// 갱신
	bool selectiveUpdate = true;
	bool rigid = false;
	GetNiObj()->SetSelectiveUpdateFlags( selectiveUpdate, true, rigid );

	GetNiObj()->UpdateProperties();
	GetNiObj()->UpdateEffects();
	GetNiObj()->Update( 0.0f );
	GetNiObj()->UpdateNodeBound();

	mBoundSphere.Set( GetCenter(), GetRadius() );

	NiPoint3 camPos = CAMERAMAN->GetCurrentCameraPos();
	if( (camPos - GetWorldTranslate()).Length() > 4000.0f )
	{
		mAlpha = 0.0f;
		SetAlphaBlended( 0.0f );
	}
	else
	{
		mAlpha = 1.0f;
		SetAlphaBlended( 1.0f );
	}

	mpHead = mPlayerSceneNode->GetDummyObject( eLINK_HEAD );
	if( !mpHead )
	{
		assert(0);
		return false;
	}
	mpFoot = GetDummyObject( eLINK_FOOT );
	if( mpFoot == 0 )
	{
		assert(0);
		return false;
	}

	return true;
}

const NiPoint3& cVehicleSceneNode::GetObjectHead()
{
	if( mPlayerSceneNode == 0 )
		return NiPoint3::ZERO;

	NiNode* spine = mPlayerSceneNode->GetDummyObject( eLINK_HEAD );
	if( spine )	
		return spine->GetWorldTranslate();
	else
		return NiPoint3::ZERO;
}

const NiPoint3& cVehicleSceneNode::GetObjectFoot()
{
	if( mPlayerSceneNode == 0 )
		return NiPoint3::ZERO;

	NiNode* spine = mPlayerSceneNode->GetDummyObject( eLINK_FOOT );
	if( spine )	
		return spine->GetWorldTranslate();
	else
		return NiPoint3::ZERO;
}

const NiPoint3& cVehicleSceneNode::GetObjectCenter()
{
	NiNode* spine = GetDummyObject( eLINK_FOOT );
	if( spine )	
		return spine->GetWorldTranslate();
	else
		return NiPoint3::ZERO;
}

void cVehicleSceneNode::UpdateNameCardTextValue()
{
	if( mPlayerSceneNode )
		mPlayerSceneNode->UpdateNameCardTextValue();
}

void cVehicleSceneNode::UpdateNameCardGaugeValue()
{
	if( mPlayerSceneNode )
		mPlayerSceneNode->UpdateNameCardGaugeValue();
}

void cVehicleSceneNode::UpdateGuildName()
{
	if( mPlayerSceneNode )
		mPlayerSceneNode->UpdateGuildName();
}

void cVehicleSceneNode::UpdateGuildMark()
{
	if( mPlayerSceneNode )
		mPlayerSceneNode->UpdateGuildMark();
}

void cVehicleSceneNode::UpdateAniScaleFactor( float factor )
{
	cDynamicSceneNode::UpdateAniScaleFactor( factor );

	if( mPlayerSceneNode )
		mPlayerSceneNode->UpdateAniScaleFactor( factor );
}

void cVehicleSceneNode::ActiveChatBubble( LPTSTR msg, unsigned long color )
{
	if( mPlayerSceneNode )
		mPlayerSceneNode->ActiveChatBubble( msg, color );
}

void cVehicleSceneNode::ActiveChatBubble( sTextItem* text )
{
	if( mPlayerSceneNode )
		mPlayerSceneNode->ActiveChatBubble( text );
}

NiAVObject* cVehicleSceneNode::GetPartObject( unsigned int partsIdx )
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->GetPartObject( partsIdx );
	}
	return 0;
}

NiNode* cVehicleSceneNode::GetDummyObject( unsigned int dummyIdx )
{
	if( dummyIdx == eLINK_FOOT )
	{
		return cDynamicSceneNode::GetDummyObject( dummyIdx );
	}
	else
	{
		if( mPlayerSceneNode )
			return mPlayerSceneNode->GetDummyObject( dummyIdx );
	}
	return 0;
}

NiAVObject* cVehicleSceneNode::GetWeaponDummy( unsigned int objectIdx, bool left )
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->GetWeaponDummy( objectIdx, left );
	}
	return 0;
}

NiAVObject* cVehicleSceneNode::GetLinkObject( unsigned int linkId )
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->GetLinkObject( linkId );
	}
	return 0;
}

cActorManagerForPartition* cVehicleSceneNode::GetActorManager()
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->GetActorManager();
	}
	return 0;
}

cActorManagerForPartition::EventCode cVehicleSceneNode::GetTargetAnimation() const
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->GetTargetAnimation();
	}
	return 0;
}

void cVehicleSceneNode::SetTargetAnimation( unsigned int code )
{
	if( mCheckAnimationId != code )
	{
		AnimationReset();

		if( mPlayerSceneNode )
			mPlayerSceneNode->AnimationReset();
	}

	unsigned int aniIdx = 0;
	if( code >= ANITYPE_IDLE && code < ANITYPE_IDLE2 )
	{
		aniIdx = mScriptData->mPlayerIdle1;
		cDynamicSceneNode::SetTargetAnimation( V_ANITYPE_IDLE1 );
	}
	else if( code>= ANITYPE_IDLE2 && code < ANITYPE_RUN )
	{
		aniIdx = mScriptData->mPlayerIdle2;
		cDynamicSceneNode::SetTargetAnimation( V_ANITYPE_IDLE2 );
	}
	else if( code>= ANITYPE_RUN && code < ANITYPE_ATTACK1 )
	{
		aniIdx = mScriptData->mPlayerRun;
		cDynamicSceneNode::SetTargetAnimation( V_ANITYPE_RUN );
	}
	else
	{
		return;
	}

	mCheckAnimationId = code;

	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->SetTargetAnimation( aniIdx );
	}
}

bool cVehicleSceneNode::UpdateTargetAnimation( unsigned int code )
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->UpdateTargetAnimation( code );
	}
	return false;
}

void cVehicleSceneNode::ActiveQuestText( LPCTSTR msg, unsigned long color )
{
	if( mPlayerSceneNode && mPlayerSceneNode->GetType() == cSceneNode::eHERO )
	{
		((cHeroSceneNode*)mPlayerSceneNode)->ActiveQuestText( msg, color );
	}
}

void cVehicleSceneNode::ActiveNoticeText( LPCTSTR msg, unsigned long color )
{
	if( mPlayerSceneNode && mPlayerSceneNode->GetType() == cSceneNode::eHERO )
	{
		((cHeroSceneNode*)mPlayerSceneNode)->ActiveNoticeText( msg, color );
	}
}

void cVehicleSceneNode::OnProcess( unsigned long deltaTime, unsigned long accumTime )
{
	cDynamicSceneNode::OnProcess( deltaTime, accumTime );

	//if( mPlayerSceneNode )
	//{
	//	mPlayerSceneNode->SetTranslate( GetTranslate() );
	//	mPlayerSceneNode->SetRotate( GetRotate() );
	//}
}

void cVehicleSceneNode::AddToVisibleArray()
{
	if( IsViewNode() == false )
		return;

	cSceneNode::AddToVisibleArray();

	{
		/// 카메라와의 거리 등록
		NiPoint3 vec = GetWorldTranslate() - CAMERAMAN->GetCurrentCameraPos();
		mVisibleCamLength = vec.Length();

		/// visible dynamic array에 등록
		SCENEMAN->AddVisibleDynamicNode( this );
	}

	/// 
	if( mpFoot == 0 )
	{
		assert(0);
		return;
	}

	///
	float x,y;
	NiPoint3 posF = mpFoot->GetWorldTranslate();
	cPlane::WorldPtToScreenPt( CAMERAMAN->GetCurrentNi(), posF, x, y, false );
	mFootScreenPosX = (int)( x * RENDERSYS->GetScreenWidth() );
	mFootScreenPosY = (int)( (1.0f - y) * RENDERSYS->GetScreenHeight() );
/*
	///
	NiPoint3 posH = mpHead->GetWorldTranslate();
	posF.z = posH.z + mHeadDist;

	cPlane::WorldPtToScreenPt( CAMERAMAN->GetCurrentNi(), posF, x, y, false );
	mHeadScreenPosX = (int)( x * RENDERSYS->GetScreenWidth() );
	mHeadScreenPosY = (int)( (1.0f - y) * RENDERSYS->GetScreenHeight() );
*/
	if( mPlayerSceneNode )
		mPlayerSceneNode->CalcScreenPos();
}

///
void cVehicleSceneNode::AddDepthPlaneObject()
{
	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->AddDepthPlaneObject();
		cObjectNameCard* card = mPlayerSceneNode->GetNameCard();
		if( card )
			card->Set2DFootPos( mFootScreenPosX, mFootScreenPosY );
	}
}

unsigned int cVehicleSceneNode::LinkObject( unsigned int dummyIdx, const char* fileName )
{
	if( mPlayerSceneNode )
	{
		unsigned int rValue = mPlayerSceneNode->LinkObject( dummyIdx, fileName );

		/// Clear collect info
		ClearCollectInfo();

		/// collect info
		CollectGeomInfo( GetNiObj() );

		return rValue;
	}
	return UINT_MAX;
}

void cVehicleSceneNode::UnLinkObject( unsigned int linkIdx )
{
	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->UnLinkObject( linkIdx );

		/// Clear collect info
		ClearCollectInfo();

		/// collect info
		CollectGeomInfo( GetNiObj() );
	}
}


bool cVehicleSceneNode::ChangeParts( unsigned int partIdx, const char* fileName )
{
	if( mPlayerSceneNode )
	{
		bool rValue = mPlayerSceneNode->ChangeParts( partIdx, fileName );

		/// Clear collect info
		ClearCollectInfo();

		/// collect info
		CollectGeomInfo( GetNiObj() );

		return rValue;
	}
	return false;
}

bool cVehicleSceneNode::ChangePartsTexture( unsigned int partsIdx, const char* fileName )
{
	if( mPlayerSceneNode )
	{
		bool rValue = mPlayerSceneNode->ChangePartsTexture( partsIdx, fileName );

		/// Clear collect info
		ClearCollectInfo();

		/// collect info
		CollectGeomInfo( GetNiObj() );

		return rValue;
	}
	return false;
}

cEffectSceneNode* cVehicleSceneNode::LinkEffect( unsigned int dummyIdx, const char* fileName, NiTransform* trans, bool bLoop, bool bFollow )
{
	if( dummyIdx == eLINK_FOOT )
	{
		return cDynamicSceneNode::LinkEffect( dummyIdx, fileName, trans, bLoop, bFollow );
	}
	else
	{
		if( mPlayerSceneNode )
		{
			return mPlayerSceneNode->LinkEffect( dummyIdx, fileName, trans, bLoop, bFollow );
		}
	}
	return 0;
}

void cVehicleSceneNode::UnLinkEffect( cEffectSceneNode* pnode )
{
	if( pnode->GetDummyIdx() == eLINK_FOOT )
	{
		cDynamicSceneNode::UnLinkEffect( pnode );
	}
	else
	{
		if( mPlayerSceneNode )
			mPlayerSceneNode->UnLinkEffect( pnode );
	}
}

cSoundSceneNode* cVehicleSceneNode::LinkSound( unsigned long soundIdx, bool bLoop )
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->LinkSound( soundIdx, bLoop );
	}
	return 0;
}

void cVehicleSceneNode::UnLinkSound( cSoundSceneNode* pnode )
{
	if( mPlayerSceneNode )
		mPlayerSceneNode->UnLinkSound( pnode );
}

cEffectSceneNode* cVehicleSceneNode::LinkDamage( unsigned int dummyIdx, const char* fileName, NiTransform* trans, bool IsMiss, bool zFalse )
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->LinkDamage( dummyIdx, fileName, trans, IsMiss, zFalse );
	}
	return 0;
}

bool cVehicleSceneNode::OnVisible()
{
	if( mPlayerSceneNode )
	{
		return mPlayerSceneNode->OnVisibleVehicle( mNeedUpdateShadow, GetWorldTranslate() );
	}
	return true;
}

void cVehicleSceneNode::HideHair( bool hide )
{
	cDynamicSceneNode::HideHair( hide );

	if( mPlayerSceneNode )
		mPlayerSceneNode->HideHair( hide );
}


void cVehicleSceneNode::SetAlphaBlended( float targetAlpha )
{
	cDynamicSceneNode::SetAlphaBlended( targetAlpha );

	if( mPlayerSceneNode )
		mPlayerSceneNode->SetAlphaBlended( targetAlpha );
}

void cVehicleSceneNode::SetSelectLightFlag( bool attach )
{
	cDynamicSceneNode::SetSelectLightFlag( attach );

	if( mPlayerSceneNode )
		mPlayerSceneNode->SetSelectLightFlag( attach );
}

void cVehicleSceneNode::CollectGeomsEx( NiAVObject* obj, NiTexture* tex )
{
	if( obj == 0 )
	{
		assert( obj );
		return;
	}

	if( mType & eDYNAMIC || mType == eDROPITEM )
	{
		if( obj->GetName() == "EffectSceneNode" )
			return;
		if( obj->GetName() == "PickObj" )
			return;
	}

	NiGeometry* geom = 0;
	if( NiIsKindOf(NiTriBasedGeom, obj) || NiIsKindOf(NiParticleSystem, obj) )
	{
		geom = (NiGeometry*)obj;
		assert( geom );

		if( geom->GetVertexCount() >= 3 )
		{
			NiAlphaProperty* alphaProp = (NiAlphaProperty*)obj->GetProperty(NiProperty::ALPHA);
			NiTexturingProperty* texProp = (NiTexturingProperty*)obj->GetProperty(NiProperty::TEXTURING);

			if( alphaProp )
			{
				if( alphaProp->GetAlphaTesting() )
					mGeomList.PushBack( cGeomPair( geom, 1 ) );
				else
				{
					if( alphaProp->GetAlphaBlending() )
						mGeomList.PushBack( cGeomPair( geom, 2 ) );
					else
						mGeomList.PushBack( cGeomPair( geom, 0 ) );
				}
			}
			else
				mGeomList.PushBack( cGeomPair(geom, 0) );

			if( tex && texProp )
			{
				if( obj->GetName() != "VehicleM1_saddle" )
					texProp->SetBaseTexture( tex );
			}
		}
	}
	else if( NiIsKindOf(NiNode, obj) )
	{
		NiAVObject* child = 0;
		NiNode* node = (NiNode*)obj;
		for( unsigned int i = 0, iend = node->GetArrayCount(); i < iend; ++i )
		{
			child = node->GetAt(i);
			if( child )
				CollectGeomsEx( child, tex );
		}
	}
}

void cVehicleSceneNode::Translate( const NiPoint3& move )
{
	cDynamicSceneNode::Translate( move );

	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->Translate( move );
	}
}

void cVehicleSceneNode::SetTranslate( const NiPoint3& trans )
{
	cDynamicSceneNode::SetTranslate( trans );

	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->SetTranslate( trans );
	}
}

void cVehicleSceneNode::SetWorldTranslate( const NiPoint3& trans )
{
	cDynamicSceneNode::SetWorldTranslate( trans );

	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->SetWorldTranslate( trans );
	}
}

void cVehicleSceneNode::SetScale( float scale )
{
	cDynamicSceneNode::SetScale( scale );

	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->SetScale( scale );
	}
}

void cVehicleSceneNode::SetRotate( const NiPoint3& axis, float angle )
{
	cDynamicSceneNode::SetRotate( axis, angle );

	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->SetRotate( axis, angle );
	}
}

void cVehicleSceneNode::SetRotate( float xangle, float yangle, float zangle )
{
	cDynamicSceneNode::SetRotate( xangle, yangle, zangle );

	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->SetRotate( xangle, yangle, zangle );
	}
}

void cVehicleSceneNode::SetRotate( const NiMatrix3& rot )
{
	cDynamicSceneNode::SetRotate( rot );

	if( mPlayerSceneNode )
	{
		mPlayerSceneNode->SetRotate( rot );
	}
}
