/* ==========================================================================
* 작 성 자 : 이순규
* 작 성 일 : 2006.12.15
* 내    용 : 장면 관리자
* 주의사항 : 
*===========================================================================*/
#pragma once

#include "SceneTree.h"
#include "VisibleArray.h"
#include "VisibleArraySorter.h"
#include "CullingProcess.h"

class cRay;
class cCamera;
class cDynamicSceneNode;
class cNpcSceneNode;
class cNpcSceneNodeParam;
class cMonsterSceneNode;
class cMonsterSceneNodeParam;
class cPlayerSceneNode;
class cPlayerSceneNodeParam;
class cEffectSceneNode;
class cEffectSceneNodeParam;
class cSoundSceneNode;
class cSoundSceneNodeParam;
class cStaticSceneNode;

/// 장면 파일 헤더
#pragma pack( push, 1 )
class cSceneFileHeader
{
public:
	/// 식별 코드
	char mCode[10];

	/// 버전
	unsigned int mVersion;

	/// 장면 트리 정보
	NiPoint3 mCenter;
	float mMinRadius;
	float mMaxRadius;

	/// 장면 노드 수
	unsigned int mNumSceneNodes;
};
#pragma pack( pop )

/// 장면 컬러
class cSceneCuller : public NiCullingProcess
{
public:
	cSceneCuller( const cCamera* cam, const NiPoint3& heroPos );

public:
	const cCamera* mCamera;
	NiPoint3 mHeroPos;
};

/// 장면 관리자
/// 장면 노드를 생성, 제거하는 관리자이다.
/// 장면을 렌더링하고,
/// 충돌 검사, 가시성 검사, 정렬 등의 작업을 수행한다.
class cSceneManager
{
	static cSceneManager* mSingleton;
public:
	cSceneManager();
	~cSceneManager();

	/// 지움
	void Clear();

	/// 초기화
	bool Init( const NiPoint3& center, float minRadius, float maxRadius );
	bool InitTree( const NiPoint3& center, float minRadius, float maxRadius );
	bool IsInited() const;

	/// 처리
	void Process( float deltaTime, float accumTime );

	/// 렌더링
	void Render();

	/// 화면 상의 좌표에 대응하는 장면 노드들을 리턴
	/// 삼각형 단위로 검사한다.
	bool PickDynamics( tArray<void*>* pickedArray, int mouseX, int mouseY, bool sortByDistance = false );

	/// 충돌하는 장면 노드들을 수집
	bool PickDynamics( tArray<void*>* pickedArray, const cRay& ray, float maxDistance, bool sortByDistance = false );
	bool PickDynamics( tArray<void*>* pickedArray, const cSphere& sphere );
	bool PickSounds( tArray<void*>* pickedArray, const cSphere& sphere );

	/// 노드를 제거
	void DestroyAll();
	bool DestroyDynamic( cSceneNode* node );
	bool DestroyDynamic( unsigned int index );
	bool DestroyEffectNode( cSceneNode* node, bool DelListRemove = false );
	bool DestroySoundNode( cSceneNode* node, bool DelListRemove = false );

	/// 제거 되어야 할 이펙트 노드에 대한 처리
	void AddDeleteEffectNode( cEffectSceneNode* node );
	void AddDeleteSoundNode( cSoundSceneNode* node );

	/// 노드를 생성
	cSoundSceneNode* CreateEffectSound( const cSoundSceneNodeParam& param );

	void ActiveSoundNodeAll( bool active );

	cNpcSceneNode* CreateNPC( unsigned long modelIndex );
	cMonsterSceneNode* CreateMonster( unsigned long modelIndex );
	cPlayerSceneNode* CreatePlayer( unsigned long modelIndex );

	cEffectSceneNode* CreateEffect( const cEffectSceneNodeParam& param );
	cEffectSceneNode* CreateSelfEffect( cString pathName, NiTransform& trans, bool bLoop );

	void AddAmbientLight( NiColor ambientColor, NiColor diffuseColor, float dimmer );
	void AddDirLight( NiColor ambientColor, NiColor diffuseColor, float dimmer, NiMatrix3 rot );

	NiAmbientLight* GetAmbientLight() const;
	NiDirectionalLight* GetDirLight() const;

	inline unsigned int GetLightCount() { return mAmbientLightArray.GetSize(); }
	inline unsigned int GetCurrentLightIndex() { return mCurrentLightIndex; }

	void ChangeLight( unsigned int index );

	/*
	/// 주변광
	void SetAmbientLightAmbient( unsigned int i, const NiColor& color );
	void SetAmbientLightDiffuse( unsigned int i, const NiColor& color );
	void SetAmbientLightDimmer( unsigned int i, float dimmer );

	/// 방향광
	void SetDirLightAmbient( unsigned int i, const NiColor& color );
	void SetDirLightDiffuse( unsigned int i, const NiColor& color );
	void SetDirLightDimmer( unsigned int i, float dimmer );
	void SetDirLightRotate( unsigned int i, float xangle, float yangle, float zangle );
	*/



	/// 장면 트리의 정보
	const NiPoint3& GetCenter() const;
	float GetMinRadius() const;
	float GetMaxRadius() const;

	/// 보이는 장면 노드 수
	unsigned int GetNumVisibleAlphaNodes() const;
	unsigned int GetNumVisibleSolidNodes() const;

	cDynamicSceneNode* GetCurrentSceneNode() { return mpCurrentSceneNode; }

	inline void SetDramaProcess( bool isDrama ) { mDramaProcess = isDrama; }

	inline NiNode* GetSceneDummy() { return mpDummy; }

protected:
	/// 노드를 추가
	unsigned int AddDynamic( cDynamicSceneNode* node );
	unsigned int AddStatic( cSceneNode* node );
	unsigned int AddEffectNode( cSceneNode* node );
	unsigned int AddSound( cSoundSceneNode* node );

	void LoadMapLightSetting( const char* fullPath );
	void ScanDir( LPCTSTR pathname, bool filescan = false );

	bool LoadEnv6( cFileLoader& loader );
	bool LoadEnv7( cFileLoader& loader );
	bool LoadEnv8( cFileLoader& loader );
	bool LoadEnv9( cFileLoader& loader );
	bool LoadEnv10( cFileLoader& loader );
	bool LoadGlobalArea6( cFileLoader& loader );
	bool LoadGlobalArea7( cFileLoader& loader );
	bool LoadGlobalArea8( cFileLoader& loader );
	bool LoadGlobalArea9( cFileLoader& loader );
	bool LoadGlobalArea10( cFileLoader& loader );

	void InterpretPlayer( float accumtime );
	void InterpretMonster( float accumtime );
	void InterpretNpc( float accumtime );

	void CreateDummy( NiPoint3 pos );

public:
	/// 단일체를 리턴
	static cSceneManager* GetSingleton();

protected:
	/// 초기화 여부
	bool mInited;

	/// 텍스처 맵
	typedef tHashMap<unsigned int, NiTexture*> cTextureMap;
	cTextureMap mTextureMap;

	/// 트리
	/// 공간을 분할하여 노드들을 계층적으로 관리한다.
	/// 충돌 검사 및 컬링을 효율적으로 수행하기위해 사용한다.
	NiPoint3 mCenter;
	float mMinRadius;
	float mMaxRadius;

	/// 컬링
	cCullingProcess mCuller;

	typedef tArray<void*> cNodeArray;

	//// 보여질 객체 자체..
	cDynamicSceneNode*			mpCurrentSceneNode;

	unsigned int mDummyIdx;
	NiNode* mpDummy;

	cSceneTree mSoundTree;
	cNodeArray mSoundArray;


	cSceneTree mDynamicTree;
	cNodeArray mDynamicArray;

	cSceneTree mStaticObjectTree;
	cNodeArray mStaticObjectArray;

	/// 이펙트 (트리로 관리할 필요 없음)
	cNodeArray mEffectNodeArray;

	/// 이펙트 삭제용
	//	typedef tPointerList<cSceneNode*> cDelEffectList;
	typedef tPointerList<void*> cDelEffectList;
	cDelEffectList mDelEffectList;

	typedef tPointerList<void*> cDelSoundList;
	cDelSoundList mDelSoundList;


	/// 반투명 노드 가시 배열
	cVisibleArray mAlphaArray;

	/// 불투명 노드 가시 배열
	cVisibleArray mSolidArray;
	cVisibleArray mSkinedArray;

	/// 반투명 노드 가시 배열 정렬자
	cAlphaArraySorter mAlphaArraySorter;

	/// 불투명 노드 가시 배열 정렬자
	cSolidArraySorter mSolidArraySorter;
	cSolidArraySorter mSkinedArraySorter;

	unsigned int mCurrentLightIndex;

	bool mDramaProcess;

	/// light
	NiTObjectArray<NiAmbientLightPtr>		mAmbientLightArray;
	NiTObjectArray<NiDirectionalLightPtr>	mDirLightArray;

	/// 조명
//	NiAmbientLightPtr mAmbientLight[2];
//	NiDirectionalLightPtr mDirLight[2];

	/// 픽킹된 장면 노드 배열
	typedef tArray<void*> cPickedArray;
	cPickedArray mPickedArray;
};

inline
bool cSceneManager::IsInited() const
{
	return mInited;
}

/*
inline
NiFogProperty* cSceneManager::GetFogProperty() const
{
	return mFogProp;
}
*/

inline
NiAmbientLight* cSceneManager::GetAmbientLight() const
{
	return mAmbientLightArray.GetAt( 0 );//mCurrentLightIndex );
}

inline
NiDirectionalLight* cSceneManager::GetDirLight() const
{
	return mDirLightArray.GetAt( 0 );//mCurrentLightIndex);
}

inline
const NiPoint3& cSceneManager::GetCenter() const
{
	return mCenter;
}

inline
float cSceneManager::GetMinRadius() const
{
	return mMinRadius;
}

inline
float cSceneManager::GetMaxRadius() const
{
	return mMaxRadius;
}

inline
unsigned int cSceneManager::GetNumVisibleAlphaNodes() const
{
	return mAlphaArray.GetCount();
}

inline
unsigned int cSceneManager::GetNumVisibleSolidNodes() const
{
	return mSolidArray.GetCount();
}

inline
cSceneManager* cSceneManager::GetSingleton()
{
	return mSingleton;
}

#define SCENEMAN cSceneManager::GetSingleton()
