#ifndef __MESHC_H__
#define __MESHC_H__

#include "PajaTypes.h"
#include "ColorC.h"
#include "ImportableI.h"
#include "FileIO.h"
#include "ScenegraphItemI.h"
#include "QuatC.h"
#include "Vector2C.h"
#include "Vector3C.h"
#include "ContVector3C.h"
#include "ContQuatC.h"
#include "ContBoolC.h"
#include "ContFloatC.h"
#include "ControllerC.h"
#include "BoneC.h"
#include "MaterialC.h"

const PajaTypes::int32	CGITEM_MESH = 0x1000;


// forwadelcr
class MeshC;


class TexCoordListC {
public:

	TexCoordListC();
	virtual ~TexCoordListC();

	virtual void						add_texcoord( const PajaTypes::Vector2C& rTex );
	virtual PajaTypes::uint32			get_texcoord_count() const;
	virtual PajaTypes::Vector2C			get_texcoord( PajaTypes::uint32 ui32Index );
	virtual PajaTypes::float32*			get_texcoord_pointer();

	// serialize
	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

private:
	std::vector<PajaTypes::float32>	m_rTexCoords;
};


class IndexListC {
public:
	IndexListC();
	virtual ~IndexListC();

	virtual void						eval_state( PajaTypes::int32 i32Time );

	virtual void						add_index( PajaTypes::uint32 ui32Index );		
	virtual PajaTypes::uint32			get_index_count() const;
	virtual PajaTypes::uint32			get_index( PajaTypes::uint32 ui32Index );
	virtual PajaTypes::uint32*			get_index_pointer();

	virtual void						add_cusp_edge( PajaTypes::uint8 ui8Flag );
	virtual PajaTypes::uint32			get_cusp_edge_count() const;
	virtual PajaTypes::uint8			get_cusp_edge( PajaTypes::uint32 ui32Index );
	virtual PajaTypes::uint8*			get_cusp_edge_pointer();

	virtual void						sort_faces( PajaTypes::float32* pVertices );
	
	// material
	virtual void						set_diffuse_texture( Import::FileHandleC* pHandle );
	virtual Import::FileHandleC*		get_diffuse_texture() const;
	virtual void						set_diffuse_mapping_type( PajaTypes::uint32 ui32Type );
	virtual PajaTypes::uint32			get_diffuse_mapping_type() const;
	virtual void						set_diffuse_tex_channel( PajaTypes::uint32 ui32Type );
	virtual PajaTypes::uint32			get_diffuse_tex_channel() const;

	virtual void						set_reflection_texture( Import::FileHandleC* pHandle );
	virtual Import::FileHandleC*		get_reflection_texture() const;
	virtual void						set_reflection_mapping_type( PajaTypes::uint32 ui32Type );
	virtual PajaTypes::uint32			get_reflection_mapping_type() const;
	virtual void						set_reflection_tex_channel( PajaTypes::uint32 ui32Type );
	virtual PajaTypes::uint32			get_reflection_tex_channel() const;

	virtual void						set_lightmap_texture( Import::FileHandleC* pHandle );
	virtual Import::FileHandleC*		get_lightmap_texture() const;
	virtual void						set_lightmap_mapping_type( PajaTypes::uint32 ui32Type );
	virtual PajaTypes::uint32			get_lightmap_mapping_type() const;
	virtual void						set_lightmap_tex_channel( PajaTypes::uint32 ui32Type );
	virtual PajaTypes::uint32			get_lightmap_tex_channel() const;

	virtual void						set_ambient( const PajaTypes::ColorC &rAmbient );
	virtual void						set_diffuse( const PajaTypes::ColorC &rDiffuse );
	virtual void						set_specular( const PajaTypes::ColorC &rSpecular );
	virtual void						set_shininess( const PajaTypes::float32 f32Shininess );
	virtual void						set_transparency( const PajaTypes::float32 f32Trans );
	virtual void						set_two_sided( bool bState );
	virtual void						set_selfillum( const PajaTypes::float32 f32SelfIllum );

	virtual const PajaTypes::ColorC&	get_ambient() const;
	virtual const PajaTypes::ColorC&	get_diffuse() const;
	virtual const PajaTypes::ColorC&	get_specular() const;
	virtual PajaTypes::float32			get_shininess() const;
	virtual PajaTypes::float32			get_transparency() const;
	virtual bool						get_two_sided() const;
	virtual PajaTypes::float32			get_selfillum() const;

	virtual void						set_diffuse_controller(  ContVector3C* pCont );
	virtual void						set_specular_controller( ContVector3C* pCont );
	virtual void						set_transparency_controller( ContFloatC* pCont );
	virtual void						set_selfillum_controller( ContFloatC* pCont );

	virtual bool						is_transparent() const;

	// serialize
	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

private:

	struct SortIndexS {
		PajaTypes::int32				m_i32Depth;
		PajaTypes::uint32				m_ui32BaseIdx;

		bool	operator<( const SortIndexS& rOther ) const
		{
			if( m_i32Depth > rOther.m_i32Depth )
				return true;
			return false;
		}
	};

	// Material
	PajaTypes::ColorC					m_rAmbient;
	PajaTypes::ColorC					m_rDiffuse;
	PajaTypes::ColorC					m_rSpecular;
	PajaTypes::float32					m_f32Shininess;
	PajaTypes::float32					m_f32Transparency;
	bool								m_bTwoSided;
	PajaTypes::float32					m_f32SelfIllum;

	ContFloatC*							m_pTransparencyCont;
	ContFloatC*							m_pSelfIllumCont;
	ContVector3C*						m_pDiffuseCont;
	ContVector3C*						m_pSpecularCont;

	Import::FileHandleC*				m_pDiffuseTextureHandle;
	PajaTypes::uint32					m_ui32DiffuseMappingType;
	PajaTypes::uint32					m_ui32DiffuseTexChannel;

	Import::FileHandleC*				m_pReflectionTextureHandle;
	PajaTypes::uint32					m_ui32ReflectionMappingType;
	PajaTypes::uint32					m_ui32ReflectionTexChannel;

	Import::FileHandleC*				m_pLightmapTextureHandle;
	PajaTypes::uint32					m_ui32LightmapMappingType;
	PajaTypes::uint32					m_ui32LightmapTexChannel;

	bool								m_bTransparent;

	std::vector<PajaTypes::uint8>		m_rCuspEdges;
	std::vector<PajaTypes::uint8>		m_rEdges;

	std::vector<PajaTypes::uint32>		m_rIndices;
	std::vector<PajaTypes::uint32>		m_rIndexCache;
	std::vector<SortIndexS>				m_rSortList;
};



class ModifierI
{
public:
	ModifierI() {};
	virtual ~ModifierI() {};

	virtual void	process( MeshC* pMesh, PajaTypes::int32 i32Time, PajaTypes::uint32 ui32VertCount, PajaTypes::float32* pInVertices, PajaTypes::float32* pInNormals,
					 PajaTypes::float32* pOutVertices, PajaTypes::float32* pOutNormals) = 0;

	virtual PajaTypes::uint32			get_type() const = 0;

	virtual void						update_dependencies( MeshC* pMesh, std::vector<ScenegraphItemI*> rScenegraph ) = 0;

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave ) = 0;
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad ) = 0;
};



enum ModifierTypeE {
	MODIFIER_SKIN		= 1,
	MODIFIER_OLD_SKIN	= 2,
	MODIFIER_MORPH		= 3,
};

class OldSkinModifierC : public ModifierI
{
public:
	OldSkinModifierC();
	virtual ~OldSkinModifierC();

	virtual void	process( MeshC* pMesh, PajaTypes::int32 i32Time, PajaTypes::uint32 ui32VertCount, PajaTypes::float32* pInVertices, PajaTypes::float32* pInNormals,
					 PajaTypes::float32* pOutVertices, PajaTypes::float32* pOutNormals);

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

	virtual PajaTypes::uint32			get_type() const;

	virtual void						update_dependencies( MeshC* pMesh, std::vector<ScenegraphItemI*> rScenegraph );

	virtual void						add_bone_vertex( PajaTypes::uint32 ui32VertIdx, PajaTypes::float32 f32Weight, PajaTypes::uint32 ui32BoneId );
	virtual PajaTypes::uint32			get_bonelist_count() const;
	virtual BoneC*						get_bonelist_bone( PajaTypes::uint32 ui32Idx ) const;
	virtual PajaTypes::uint32			get_bonelist_boneid( PajaTypes::uint32 ui32Idx ) const;
	virtual void						set_bonelist_bone( PajaTypes::uint32 ui32Idx, BoneC* pBone );

	struct BoneVertListS {
		std::vector<PajaTypes::float32>	m_rWeights;
		std::vector<PajaTypes::uint32>	m_rIndices;
		BoneC*							m_pBone;
		PajaTypes::uint32				m_ui32BoneId;
	};

	virtual void						add_bonevertlist( BoneVertListS& rList );

protected:

	BoneC*		find_bone( PajaTypes::uint32 ui32Id, std::vector<ScenegraphItemI*>& rSceneGraph );

	std::vector<BoneVertListS>			m_rBoneVertLists;

};



class BoneWeightListC {
public:
	BoneWeightListC();
	virtual ~BoneWeightListC();

	virtual void				add_weight( PajaTypes::uint32 ui32Index, PajaTypes::float32 f32Weight );
	virtual void				get_weight( PajaTypes::uint32 ui32Idx, PajaTypes::uint32& ui32Index, PajaTypes::float32& f32Weight );
	PajaTypes::uint32*			get_weight_index_ptr();
	PajaTypes::float32*			get_weight_value_ptr();
	virtual PajaTypes::uint32	get_weight_count() const;

	void						set_base_tm( const PajaTypes::Matrix3C& rTm );
	const PajaTypes::Matrix3C&	get_base_tm() const;

	void						set_bone_name( const char* szName );
	const char*					get_bone_name() const;

	void						set_bone( ScenegraphItemI* pBone );
	ScenegraphItemI*			get_bone();

	// serialize
	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

protected:
	std::string						m_sBoneName;
	std::vector<PajaTypes::float32>	m_rWeights;
	std::vector<PajaTypes::uint32>	m_rIndices;
	ScenegraphItemI*				m_pBone;
	PajaTypes::Matrix3C				m_rBaseTM;
};


class SkinModifierC : public ModifierI
{
public:
	SkinModifierC();
	virtual ~SkinModifierC();

	virtual void	process( MeshC* pMesh, PajaTypes::int32 i32Time, PajaTypes::uint32 ui32VertCount, PajaTypes::float32* pInVertices, PajaTypes::float32* pInNormals,
					 PajaTypes::float32* pOutVertices, PajaTypes::float32* pOutNormals);
	virtual PajaTypes::uint32			get_type() const;

	virtual void						update_dependencies( MeshC* pMesh, std::vector<ScenegraphItemI*> rScenegraph );

	virtual void						set_skin_base_tm( const PajaTypes::Matrix3C& rTM );
	virtual void						add_boneweightlist( BoneWeightListC* pList );
	virtual PajaTypes::uint32			get_boneweightlist_count() const;
	virtual BoneWeightListC*			get_boneweightlist( PajaTypes::uint32 ui32Idx ) const;

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

protected:
	ScenegraphItemI*					find_bone( const char* szName, std::vector<ScenegraphItemI*>& rScenegraph );

	std::vector<BoneWeightListC*>		m_rBoneWeightLists;
	PajaTypes::Matrix3C					m_rSkinBaseTM;
	PajaTypes::Matrix3C					m_rInvSkinBaseTM;
};


class MorphChannelC
{
public:
	MorphChannelC();
	virtual ~MorphChannelC();

	virtual void						add_delta( PajaTypes::uint32 ui32Idx, const PajaTypes::Vector3C& rPoint, const PajaTypes::Vector3C& rNormal );

	virtual void						set_percentage_controller( ContFloatC* pCont );
	virtual void						set_percentage( PajaTypes::float32 f32Value );
	virtual PajaTypes::float32			get_percentage( PajaTypes::int32 i32Time );

	virtual void						set_use_limits( bool bState );
	virtual bool						get_use_limits() const;
	virtual void						set_limits( PajaTypes::float32 f32Min, PajaTypes::float32 f32Max );
	virtual PajaTypes::float32			get_min_limit() const;
	virtual PajaTypes::float32			get_max_limit() const;

	virtual void	process( MeshC* pMesh, PajaTypes::int32 i32Time, PajaTypes::uint32 ui32VertCount, PajaTypes::float32* pOutVertices, PajaTypes::float32* pOutNormals );

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

protected:
	ContFloatC*			m_pPercentageCont;
	PajaTypes::float32	m_f32Percentage;
	PajaTypes::float32	m_f32Min, m_f32Max;
	bool				m_bUseLimits;

	std::vector<PajaTypes::uint32>	m_rIndices;
	std::vector<PajaTypes::float32>	m_rVertexDeltas;
	std::vector<PajaTypes::float32>	m_rNormalDeltas;
};


class MorphModifierC : public ModifierI
{
public:
	MorphModifierC();
	virtual ~MorphModifierC();

	virtual void	process( MeshC* pMesh, PajaTypes::int32 i32Time, PajaTypes::uint32 ui32VertCount, PajaTypes::float32* pInVertices, PajaTypes::float32* pInNormals,
					 PajaTypes::float32* pOutVertices, PajaTypes::float32* pOutNormals);
	virtual PajaTypes::uint32			get_type() const;

	virtual void						update_dependencies( MeshC* pMesh, std::vector<ScenegraphItemI*> rScenegraph );

	virtual void						add_morph_channel( MorphChannelC* pChannel );

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

protected:

	std::vector<MorphChannelC*>		m_rChannels;
};



class MeshC : public ScenegraphItemI
{
public:
	MeshC();
	virtual ~MeshC();

	virtual PajaTypes::int32			get_type();

	// transformation

	virtual void						eval_state( PajaTypes::int32 i32Time );

	virtual void						eval_geom( PajaTypes::int32 i32Time );

	virtual void						set_position( const PajaTypes::Vector3C& rPos );
	virtual const PajaTypes::Vector3C&	get_position();

	virtual void						set_scale( const PajaTypes::Vector3C& rScale );
	virtual const PajaTypes::Vector3C&	get_scale();

	virtual void						set_scale_rotation( const PajaTypes::QuatC& rRot );
	virtual const PajaTypes::QuatC&		get_scale_rotation();

	virtual void						set_rotation( const PajaTypes::QuatC& rRot );
	virtual const PajaTypes::QuatC&		get_rotation();

	virtual void						set_position_controller( ContVector3C* pCont );
	virtual ContVector3C*				get_position_controller();

	virtual void						set_rotation_controller( ContQuatC* pCont );
	virtual ContQuatC*					get_rotation_controller();

	virtual void						set_scale_controller( ContVector3C* pCont );
	virtual ContVector3C*				get_scale_controller();

	virtual void						set_scale_rotation_controller( ContQuatC* pCont );
	virtual ContQuatC*					get_scale_rotation_controller();

	virtual void						set_vis_controller( ContBoolC* pCont );
	virtual ContBoolC*					get_vis_controller();

	virtual bool						get_visible() const;

	// geometry

	virtual void						add_index_list( IndexListC* pList );
	virtual PajaTypes::uint32			get_index_list_count() const;
	virtual IndexListC*					get_index_list( PajaTypes::uint32 ui32Index );

	virtual void						add_texcoord_list( TexCoordListC* pList );
	virtual PajaTypes::uint32			get_texcoord_list_count() const;
	virtual TexCoordListC*				get_texcoord_list( PajaTypes::uint32 ui32Index );

	virtual void						add_vert( const PajaTypes::Vector3C& rVec );
	virtual void						add_norm( const PajaTypes::Vector3C& rNorm );

	virtual PajaTypes::uint32			get_vert_count() const;
	virtual PajaTypes::uint32			get_norm_count() const;

	virtual PajaTypes::Vector3C			get_vert( PajaTypes::uint32 ui32Index );
	virtual PajaTypes::Vector3C			get_norm( PajaTypes::uint32 ui32Index );

	virtual PajaTypes::float32*			get_vert_pointer();
	virtual PajaTypes::float32*			get_norm_pointer();

	virtual bool						is_transparent() const;

	virtual void						sort_faces( const PajaTypes::Matrix3C& rTM );

	virtual void						set_toon( bool bState );
	virtual bool						get_toon() const;

	virtual void						set_alphatest( bool bState );
	virtual bool						get_alphatest() const;

	virtual void						set_cast_shadows( bool bState );
	virtual bool						get_cast_shadows() const;

	virtual void						set_additive( bool bState );
	virtual bool						get_additive() const;

	virtual void						calc_bbox();
	virtual PajaTypes::Vector3C			get_bbox_min() const;
	virtual PajaTypes::Vector3C			get_bbox_max() const;

	virtual void						add_modifier( ModifierI* pMod );
	virtual void						update_dependencies( std::vector<ScenegraphItemI*> rScenegraph );

	// serialize
	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

private:

	struct SortIndexS {
		PajaTypes::int32				m_i32Depth;
		PajaTypes::uint32				m_ui32BaseIdx;

		bool	operator<( const SortIndexS& rOther ) const
		{
			if( m_i32Depth > rOther.m_i32Depth )
				return true;
			return false;
		}
	};


	bool								m_bAdditive;
	bool								m_bToon;
	bool								m_bAlphaTest;
	bool								m_bCastShadows;
	bool								m_bVis;

	PajaTypes::Vector3C					m_rPosition;
	PajaTypes::Vector3C					m_rScale;
	PajaTypes::QuatC					m_rScaleRot;
	PajaTypes::QuatC					m_rRotation;

	ContVector3C*						m_pPosCont;
	ContQuatC*							m_pRotCont;
	ContVector3C*						m_pScaleCont;
	ContQuatC*							m_pScaleRotCont;
	ContBoolC*							m_pVisCont;

	PajaTypes::Vector3C					m_rMin;
	PajaTypes::Vector3C					m_rMax;

	//Geometry
	std::vector<PajaTypes::float32>		m_rVertices;
	std::vector<PajaTypes::float32>		m_rNormals;
	std::vector<IndexListC*>			m_rIndexLists;
	std::vector<TexCoordListC*>			m_rTexCoordLists;

	// geom caches
	std::vector<PajaTypes::float32>		m_rVertexCache;
	std::vector<PajaTypes::float32>		m_rNormalCache;

	std::vector<PajaTypes::float32>		m_rSortCache;

	std::vector<ModifierI*>				m_rModifiers;
};

#endif // __MESHC_H__	