//---DIRECTGEM----------------------------------------------------------------
//	
//	this library is freeware so you can use it in anyway you want, changes 
//	should be listed belowe, credits will be apprecited, if you have any
//	question contact me: bartj@zeus.polsl.gliwice.pl
//
//--desc----------------------------------------------------------------------
//		DirectGem is a util which was designed to replay .3ds files,
//		is suports many features from 3dsR4 keyframing
//--todo----------------------------------------------------------------------
//		+ suport for other formats such as .lws and .max
//		+ some extension for light mapping would be very useful
//--version-------------------------------------------------------------------
//		0.1			acid		20.09.99		+ initial version
//----------------------------------------------------------------------------
//		0.3			acid		15.10.99		+ main class structure
//												+ math class and function
//												+ some other features
//----------------------------------------------------------------------------
//		0.5			acid		30.10.99		+ loader for 3ds
//												+ first functional version
//----------------------------------------------------------------------------
//
//		(c)zone51												1999-2000
//
//----------------------------------------------------------------------------

#ifndef __DIRECTGEM_H_
#define __DIRECTGEM_H_

#define D3D_OVERLOADS

#include <d3d.h>
#include <ddraw.h>
#include <stdio.h>
#include "gemmath.h"
#include "lists.h"
#include "texturemenager.h"

#define	IDLENGTH		6

#define GEMERROR_LOAD	1
#define GEMERROR_OK		0



class gem_Scene;
class gem_KeyInfo;
class gem_Material;
class gem_Object;
class gem_Keyframer;
class gem_Mesh;

class gem_MorphInfo
{
public:

	gem_Mesh*			MorphSource;
	gem_Mesh*			MorphTarget;
	FLOAT				MorphFactor;
};

class gem_Object
{
protected:

	gem_Scene*			pScene;

public:

	gem_Object( gem_Scene* scene )
	{
		pScene = scene;
	}

	~gem_Object()
	{
	}

	virtual VOID Init()=0;
	virtual VOID Render()=0;			
	virtual DWORD Load( FILE* inFile )=0;	
	virtual DWORD Type()=0;
};



class gem_Mesh : public gem_Object
{
public:

	class gem_Group
	{
	public:

		gem_Material*		pMaterial;
		LPWORD				pIndices;
		DWORD				dwIndicesCount;
	};

	DWORD				dwVertexCount;	
	DWORD				dwFlags;

	LPD3DVERTEX			pMeshVertexTab;
	LPD3DVERTEX			pTransformVertexTab;	
	
	List<gem_Group>		GroupList;

	BOOL				bHide;	
	
	gem_Matrix			mtxTransform;
		
	VOID PreTransform( gem_Matrix mtx);	
	VOID Morph( gem_MorphInfo& info );
	VOID SetMaterial( gem_Material* mat );

	DWORD ReadVerticesList( FILE *inFile );
	DWORD ReadFacesList( FILE* inFile );
	DWORD ReadMappingList( FILE* inFile );
	DWORD ReadLocalCoords( FILE* inFile );	

	gem_Mesh( gem_Scene* scene );
	~gem_Mesh();	

	virtual VOID Init();
	virtual VOID Render();			
	virtual DWORD Load( FILE* inFile );		
	virtual DWORD Type();
	
	friend class gem_MeshKeyframer;
	friend class gem_Scene;
};


class gem_Light : public gem_Object
{
public:
		
	gem_Vector			position;	

	DWORD				dwIndex;
	FLOAT				fSize;

	gem_Light( gem_Scene* scene );
	~gem_Light();	

	virtual VOID Init();
	virtual VOID Render();		
	virtual DWORD Load( FILE* inFile );	
	virtual DWORD Type();

	friend class gem_LightKeyframer;
	friend class gem_Scene;
};


class gem_Camera : public gem_Object
{
public:

	FLOAT				fov;
	FLOAT				roll;

	gem_Vector			position;
	gem_Vector			target;

	FLOAT				nearZ;
	FLOAT				farZ;
	FLOAT				aspect;	

	gem_Camera( gem_Scene* scene );
	~gem_Camera();	

	virtual VOID Init();
	virtual VOID Render();			
	virtual DWORD Load( FILE* inFile );
	virtual DWORD Type();
	
	VOID SetGeometry( LPDIRECT3DDEVICE7 lpd3dDevice );

	friend class gem_CameraKeyframer;
	friend class gem_CameraTrgKeyframer;
	friend class gem_Scene;
};


class gem_RotationTrack
{
public:

	class gem_RotationKey
	{
	public:
		DWORD			frame;

		gem_Quat		qtr;
		gem_Quat		an, bn;

		FLOAT			T;
		FLOAT			C;
		FLOAT			B;

		FLOAT			EaseTo;
		FLOAT			EaseFrom;
	};

private:
	
	DWORD					dwKeyNumber;	
	gem_RotationKey*		keys;

public:

	gem_RotationTrack();
	~gem_RotationTrack();

	VOID Init();
	DWORD Load( FILE* inFile );

	gem_Quat Interpolation( FLOAT frame );
	
};


class gem_VectorTrack
{
public:

	class gem_VectorKey
	{
	public:
		DWORD			frame;

		gem_Vector		vec;
		gem_Vector		an, bn;

		FLOAT			T;
		FLOAT			C;
		FLOAT			B;

		FLOAT			EaseTo;
		FLOAT			EaseFrom;
	};

private:
	
	DWORD					dwKeyNumber;	
	gem_VectorKey*			keys;

public:

	gem_VectorTrack();
	~gem_VectorTrack();

	VOID Init();
	DWORD Load( FILE* inFile );

	gem_Vector Interpolation( FLOAT frame );
	
};

class gem_MorphTrack
{
public:

	class gem_MorphKey
	{
	public:
		DWORD			frame;

		gem_Mesh*		mesh;				

		FLOAT			EaseTo;
		FLOAT			EaseFrom;
	};

private:

	DWORD					dwKeyNumber;		
	gem_Scene*				pScene;
	gem_MorphKey*			keys;

public:

	gem_MorphTrack( gem_Scene* scene);
	~gem_MorphTrack();

	VOID Init();	
	DWORD Load( FILE* inFile );

	gem_MorphInfo Interpolation( FLOAT frame );
};

class gem_HideTrack
{
public:

	class gem_HideKey
	{
	public:
		DWORD			frame;

		DWORD			hide;		
	};

private:

	DWORD					dwKeyNumber;		
	gem_HideKey*			keys;

public:

	gem_HideTrack();	
	~gem_HideTrack();

	VOID Init();	
	DWORD Load( FILE* inFile );

	BOOL Interpolation( FLOAT frame );
};


class gem_FloatTrack
{
public:

	class gem_FloatKey
	{
	public:
		DWORD			frame;

		FLOAT			val;
		FLOAT			an, bn;

		FLOAT			T;
		FLOAT			C;
		FLOAT			B;

		FLOAT			EaseTo;
		FLOAT			EaseFrom;
	};

private:

	DWORD					dwKeyNumber;		
	gem_FloatKey*			keys;

public:

	gem_FloatTrack();
	~gem_FloatTrack();	

	VOID Init();	
	DWORD Load( FILE* inFile );

	FLOAT Interpolation( FLOAT frame );

};


class gem_Keyframer
{
protected:

	DWORD					dwType;	
	gem_Scene*				pScene;

	WORD					hierarchyID;
	WORD					parentID;

	gem_Keyframer*			parent;

public:	

	gem_Matrix				frameMtx;

	gem_Keyframer( gem_Scene* scene)
	{
		pScene = scene;		
		parent = NULL;
	}

	~gem_Keyframer()
	{
	}

	virtual VOID UpdateTransform( FLOAT frame )=0;	
	virtual VOID ApplyTransform()=0;

	virtual DWORD Load( FILE* inFile )=0;

	friend gem_Scene;
};

class gem_MeshKeyframer : public gem_Keyframer
{
private:

	gem_Mesh*				mesh;	
	
	gem_HideTrack*			hideTrack;
	gem_MorphTrack*			morphTrack;

	gem_RotationTrack*		rotationTrack;
	gem_VectorTrack*		positionTrack;
	gem_VectorTrack*		scaleTrack;
	
	BOOL					hide;
	BOOL					isMorphing;
	BOOL					dummy;

	gem_Vector				pivot;

	DWORD ReadPivot( FILE *inFile );
	DWORD ReadDummyName( FILE* inFile, TCHAR* name );

public:

	gem_MeshKeyframer( gem_Scene* scene );
	~gem_MeshKeyframer();

	virtual VOID UpdateTransform( FLOAT frame );	
	virtual VOID ApplyTransform();

	virtual DWORD Load( FILE* inFile );		
};

class gem_LightKeyframer : public gem_Keyframer
{
private:

	gem_Light*				light;

	gem_VectorTrack*		positionTrack;

public:

	gem_LightKeyframer( gem_Scene* scene );
	~gem_LightKeyframer();
	
	virtual VOID UpdateTransform( FLOAT frame );	
	virtual VOID ApplyTransform();

	virtual DWORD Load( FILE* inFile );
};

class gem_CameraKeyframer : public gem_Keyframer
{
private:

	gem_Camera*				camera;

	gem_VectorTrack*		positionTrack;
	gem_FloatTrack*			rollTrack;
	gem_FloatTrack*			fovTrack;

public:

	gem_CameraKeyframer( gem_Scene* scene );
	~gem_CameraKeyframer();
	
	virtual VOID UpdateTransform( FLOAT frame );	
	virtual VOID ApplyTransform();

	virtual DWORD Load( FILE* inFile );
};
	
class gem_CameraTrgKeyframer : public gem_Keyframer
{
private:

	gem_Camera*				camera;

	gem_VectorTrack*		positionTrack;
	
public:

	gem_CameraTrgKeyframer( gem_Scene* scene );
	~gem_CameraTrgKeyframer();
	
	virtual VOID UpdateTransform( FLOAT frame );	
	virtual VOID ApplyTransform();

	virtual DWORD Load( FILE* inFile );
};	

class gem_Map
{
public:
	TCHAR			name[80];

	DWORD Load( FILE* inFile );

	gem_Map()
	{
	}

	gem_Map( TCHAR*	texname )
	{		
		strcpy( name, texname );
	}
};

class gem_Material
{
public:

	TCHAR			name[80];

	gem_Map*		texture1;
	gem_Map*		texture2;
	gem_Map*		envmap;

	gem_Scene*		pScene;

	gem_Material( TCHAR* textname, gem_Scene* scene );
	gem_Material( gem_Scene* scene );
	~gem_Material();

	VOID SetMaterial( LPDIRECT3DDEVICE7 pd3dDevice );
	DWORD Load( FILE* inFile );	
};

	
class gem_Scene
{
private:

	DWORD							dwLightNumber;

	FLOAT							aspect;
	FLOAT							farZ;
	FLOAT							nearZ;

	FLOAT							fLitSize;

	DWORD							dwVersion;
	DWORD							dwFlags;

	LPDIRECT3DDEVICE7				lpd3dDevice;	

public:

	NamedItemList<gem_Keyframer>	KeyframerList;
	NamedItemList<gem_Object>		ObjectList;
	NamedItemList<gem_Material>		MaterialList;

	DWORD							dwStartFrame;
	DWORD							dwEndFrame;

	gem_Camera*						currentCam;
	TCHAR							lightText[80];	

	LPDIRECTDRAWSURFACE7			lpddsLightFlare;
			
	VOID LinkHierarchy();	

	DWORD ReadFramesChunk( FILE* inFile );
	DWORD ReadKeyframerChunk( FILE *inFile );
	DWORD ReadEditorChunk( FILE* inFile );
	DWORD ReadObjectChunk( FILE* inFile );

public:

	gem_Scene();
	~gem_Scene();

	VOID SetFlags( DWORD flags );
	VOID SetLightSize( FLOAT size );

	DWORD Load( TCHAR* name );
	
	VOID Transform( FLOAT frame );

	VOID RenderFrame( FLOAT frame );	
	VOID Render();	

	VOID Init( LPDIRECT3DDEVICE7 lpd3dDevice );	
	VOID Close();
	
	VOID SetLightFlare( TCHAR* name );	
	VOID SetRenderStatus( DWORD flags );	
	VOID SetActiveCamera( TCHAR* name );	

	VOID SetViewport( FLOAT _nearZ, FLOAT _farZ, FLOAT _aspect );

	DWORD GetStartFrame();
	DWORD GetEndFrame();

	gem_Keyframer* FindKeyframer( TCHAR* name );
	gem_Object* FindObject( TCHAR* name );
	gem_Material* FindMaterial( TCHAR* name );

	friend class gem_Light;
	friend class gem_Mesh;
	friend class gem_Camera;
	friend class gem_Material;
	friend class gem_MeshKeyframer;
	friend class gem_LightKeyframer;
	friend class gem_CameraKeyframer;
	friend class gem_CameraTrgKeyframer;
	
};

#endif /* __DIRECTGEM_H_ */
