#ifndef __SCENE_H_
#define __SCENE_H_

#include <d3d8.h>

enum HE3D_SCENEFLAGS
{
	FLAG_RENDERFLARE		= 1,
	FLAG_LENSFALER			= 2,
	FLAG_MORPH				= 4,
	FLAG_SHADOW				= 8,
	FLAG_HW					= 16,
	FLAG_THROWTEXEXC		= 32,
	FLAG_SCENE_DWORD		= 0x7fffffff
};

enum HE3D_ERRORCODES
{
	HE3DERR_UNABLETOLOAD,
	HE3DERR_UNABLETOINITIALIZE,
	HE3DERR_NOCAMERA,
	HE3DERR_TEXTUREEXCEPTION,
	HE3DERR_NOTINITIALIZED,
	HE3DERR_GENERIC
};

#define	MESHFVF	D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1
#define SKINFVF	D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4 | D3DFVF_NORMAL | D3DFVF_TEX1

class he3d_CMaterial;
class he3d_CCameraObject;
class he3d_CKeyframer;
class he3d_CObject;

template<class T> class CNameMap;

#pragma pack(4)
typedef struct _tag_MESHVERTEX
{
	D3DVECTOR		p;
	D3DVECTOR		n;
	FLOAT			u, v;
} MESHVERTEX, *LPMESHVERTEX, *PMESHVERTEX;
#pragma pack()

#pragma pack(4)
typedef struct _tag_SKINVERTEX
{
	D3DVECTOR		p;
	FLOAT			w0;
	FLOAT			w1;
	FLOAT			w2;
	DWORD			index;
	D3DVECTOR		n;
	FLOAT			u, v;
} SKINVERTEX, *LPSKINVERTEX, *PSKINVERTEX;
#pragma pack()

#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }

class he3d_CException
{
public:

	DWORD		code;

public:

	he3d_CException( DWORD _code ) : code( _code )
	{
	}
};

class he3d_CScene
{
private:

	CNameMap<he3d_CKeyframer>*	nmKeyframersList;
	CNameMap<he3d_CObject>*		nmObjectsList;
	CNameMap<he3d_CMaterial>*	nmMaterialsList;	

public:

	DWORD						dwFlags;

	PDIRECT3DDEVICE8			pd3dDevice;

	FLOAT						zMin;
	FLOAT						zMax;
	FLOAT						fAspect;

	he3d_CCameraObject*			pcamCurrent;

	DWORD						dwFramesCount;

	DWORD						dwLightsCount;

	he3d_CMaterial*				pmatLight;	

	he3d_CKeyframer*			pkfRoot;

	PDIRECT3DVERTEXBUFFER8		pvbFlare;
	PDIRECT3DINDEXBUFFER8		pibFlare;

	DWORD						hVS;	

public:

	he3d_CScene();
	~he3d_CScene();

	void Initialize( PDIRECT3DDEVICE8 pDevice, DWORD dwFlags = 0 );

	he3d_CKeyframer* GetKeyframer( const char* name );
	he3d_CObject* GetObject( const char* name );
	he3d_CMaterial* GetMaterial( const char* name );
	he3d_CKeyframer* GetObjectKeyframer( const char* name );
	he3d_CKeyframer* GetObjectKeyframer( he3d_CObject* obj );

	void AddMaterial( const char* name, he3d_CMaterial* mat );
	void AddObject( const char* name, he3d_CObject* object );
	void AddKeyframer( const char* name, he3d_CKeyframer* keyframer );
	void ReplaceMaterial( const char* name, he3d_CMaterial* mat );

	void SetFlags( DWORD flags );
	void SetVieport( FLOAT zmin, FLOAT zmax, FLOAT aspect );
	void SetLightMaterial( he3d_CMaterial* mat );

	void RenderFrame( FLOAT frame );
	void Transform( FLOAT frame );
	void Render();
	
	void Load( const char* filename );

	void CloseScene();
};

#endif