//
// Moppi ASCII .MAS loader
//


#ifndef ASELOADERC_H
#define ASELOADERC_H

#include "PajaTypes.h"
#include "ColorC.h"
#include "Mesh3DC.h"
#include "engine.h"
#include "ImportInterfaceC.h"
#include "ScenegraphItemI.h"


// stl
#include <vector>
#include <string>



class ASEMapC {
public:
	ASEMapC() {
		m_mapping = MAPPING_NONE;
		m_texChannel = -1;
		m_amount = 1.0f;
		m_axis = AXIS_UV;
		m_mapType = MAP_NO_MAP;
	}
	virtual ~ASEMapC() {};

	enum MappingTypeE {
		MAPPING_NONE,
		MAPPING_EXPLICIT,
		MAPPING_OBJ_XYZ,
		MAPPING_WORLD_XYZ,
		MAPPING_SPHERICAL_ENV,
		MAPPING_CYLINDRICAL_ENV,
		MAPPING_SHRINK_WRAP_ENV,
		MAPPING_SCREEN,
		MAPPING_VERTEX_COLORS
	};

	enum MappingAxisE {
		AXIS_UV,
		AXIS_VW,
		AXIS_WU
	};

	enum MapTypeE {
		MAP_NO_MAP,
		MAP_BITMAP,
		MAP_RGB_MULTIPLY,
		MAP_VERTEX_COLOR
	};

	std::string				m_name;
	MappingTypeE			m_mapping;
	MappingAxisE			m_axis;
	PajaTypes::uint16			m_texChannel;
	PajaTypes::float32		m_amount;
	MapTypeE				m_mapType;
	std::vector<ASEMapC>	m_genMaps;
};


class ASEMaterialC
{
public:
	ASEMaterialC() {
		m_id = 0;
		m_converted = false;
		m_twoSided = false;
	}
	virtual ~ASEMaterialC()
	{
		//TRACE( " %d submtls to delete\n", m_submaterials.size() );
		if( m_submaterials.size() ) {
			for( PajaTypes::uint16 i = 0; i < m_submaterials.size(); i++ ) {
				if( m_submaterials[i] )
					delete m_submaterials[i];
			}
		}
	}

	PajaTypes::ColorC			m_amb, m_diff, m_spec;
	ASEMapC						m_mapDiff;
	ASEMapC						m_mapRefl;
	std::vector<ASEMaterialC*>	m_submaterials;
	PajaTypes::uint32			m_id;
	std::string					m_name;
	bool						m_converted;
	PajaTypes::float32			m_shine;
	PajaTypes::float32			m_opacity;
	PajaTypes::float32			m_selfillum;
	bool						m_twoSided;
};


class ASEFaceC {
public:
	ASEFaceC() {};
	virtual ~ASEFaceC() {};
	PajaTypes::uint16		m_verts[3];
	PajaTypes::uint16		m_norms[3];
	PajaTypes::uint16		m_colors[3];
	ASEMaterialC*		m_mtl;
 	PajaTypes::uint16		m_mtlRef;
 	PajaTypes::uint32		m_smthGrp;
	PajaTypes::Vector3C	m_norm;
};


// Texture coordinate set
class ASETCSetC {
public:
	ASETCSetC() {};
	virtual ~ASETCSetC() {};
	std::vector<PajaTypes::Vector3C>	m_coords;
	std::vector<PajaTypes::uint16>	m_indices;
};


class ASENormalC {
public:
	ASENormalC() : m_baseIdx( 0 ) {};
	virtual ~ASENormalC() {};

	PajaTypes::uint32 add_norm( const PajaTypes::Vector3C& v, PajaTypes::uint32 ui32Smooth ) {
		for( PajaTypes::uint32 i = 0; i < m_groups.size(); i++ ) {
			if( m_groups[i] & ui32Smooth ) {
				m_norms[i] = m_norms[i] + v;
				m_groups[i] |= ui32Smooth;
				return i;
			}
		}


		m_norms.push_back( v );
		m_groups.push_back( ui32Smooth );
		return m_norms.size() - 1;
	}

	std::vector<PajaTypes::Vector3C>	m_norms;
	std::vector<PajaTypes::uint32>	m_groups;
	PajaTypes::uint32					m_baseIdx;
};


enum ASEObjectTypeE {
	ASE_OBJECT = 0,
	ASE_GEOM_OBJECT = 1,
	ASE_GROUP_OBJECT = 2,
	ASE_MORPH_OBJECT = 3,
};


enum ContTypeE {
	ASE_TCB = 1,
	ASE_LINEAR = 2,
};

class ASEVector3KeyC
{
public:
	ASEVector3KeyC() {};
	virtual ~ASEVector3KeyC() {};
	PajaTypes::Vector3C	m_rVal;
	PajaTypes::float32	m_f32Tens, m_f32Cont, m_f32Bias;
	PajaTypes::float32	m_f32EaseIn, m_f32EaseOut;
	PajaTypes::int32	m_i32Time;
};

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

	PajaTypes::int32			m_i32StartORT;
	PajaTypes::int32			m_i32EndORT;
	PajaTypes::int32			m_i32Type;
	std::vector<ASEVector3KeyC>	m_rKeys;
};


class ASEQuatKeyC
{
public:
	ASEQuatKeyC() {};
	virtual ~ASEQuatKeyC() {};
	PajaTypes::Vector3C	m_rAxis;
	PajaTypes::float32	m_f32Angle;
	PajaTypes::float32	m_f32Tens, m_f32Cont, m_f32Bias;
	PajaTypes::float32	m_f32EaseIn, m_f32EaseOut;
	PajaTypes::int32	m_i32Time;
};

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

	PajaTypes::int32			m_i32StartORT;
	PajaTypes::int32			m_i32EndORT;
	PajaTypes::int32			m_i32Type;
	std::vector<ASEQuatKeyC>	m_rKeys;
};


class ASEFloatKeyC
{
public:
	ASEFloatKeyC() {};
	virtual ~ASEFloatKeyC() {};
	PajaTypes::float32	m_f32Val;
	PajaTypes::float32	m_f32Tens, m_f32Cont, m_f32Bias;
	PajaTypes::float32	m_f32EaseIn, m_f32EaseOut;
	PajaTypes::int32	m_i32Time;
};

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

	PajaTypes::int32			m_i32StartORT;
	PajaTypes::int32			m_i32EndORT;
	PajaTypes::int32			m_i32Type;
	std::vector<ASEFloatKeyC>	m_rKeys;
};


class ASEObjectC
{
public:
	ASEObjectC() : m_type( ASE_OBJECT ) {
		m_transformed = false;
	}

	virtual ~ASEObjectC() {
		for( PajaTypes::uint32 i = 0; i < m_childs.size(); i++ )
			delete m_childs[i];
	}

	PajaTypes::Matrix3C				m_tm;
	PajaTypes::Matrix3C				m_offset;
	PajaTypes::Vector3C				m_rPos;
	PajaTypes::Vector3C				m_rScale;
	PajaTypes::QuatC				m_rScaleRot;
	PajaTypes::QuatC				m_rRot;
	std::string						m_name;
	std::string						m_parentName;
	ASEObjectTypeE					m_type;
	bool							m_transformed;
	ASEObjectC*						m_parent;
	std::vector<ASEObjectC*>		m_childs;

	ASEVector3ContC					m_rPosCont;
	ASEQuatContC					m_rRotCont;
	ASEVector3ContC					m_rScaleCont;
	ASEQuatContC					m_rScaleRotCont;
	ASEFloatContC					m_rVisibility;
};


class ASECameraC
{
public:
	ASECameraC()
	{
		m_f32FOV = 60 / 180 * M_PI;
		m_f32NearPlane = 1;
		m_f32FarPlane = 2;
	}
	virtual ~ASECameraC() {};

	PajaTypes::Vector3C	m_rPos;
	PajaTypes::Vector3C	m_rTgt;
	std::string			m_rName;
	PajaTypes::float32	m_f32Roll;
	PajaTypes::float32	m_f32FOV;
	PajaTypes::float32	m_f32NearPlane;
	PajaTypes::float32	m_f32FarPlane;

	ASEVector3ContC		m_rPosCont;
	ASEVector3ContC		m_rTgtCont;
	ASEFloatContC		m_rRollCont;
	ASEFloatContC		m_rFOVCont;
	ASEFloatContC		m_rNearCont;
	ASEFloatContC		m_rFarCont;
};


class ASELightC
{
public:
	ASELightC() {
		m_bDoDecay = false;
		m_bIsSpot = false;
		m_f32Multiplier = 1.0f;
		m_f32DecayStart = 0.0f;
	}
	virtual ~ASELightC() {};

	PajaTypes::Vector3C	m_rPos;
	PajaTypes::Vector3C	m_rTgt;
	PajaTypes::ColorC	m_rColor;
	PajaTypes::float32	m_f32Multiplier;
	PajaTypes::float32	m_f32DecayStart;

	ASEVector3ContC		m_rPosCont;
	ASEVector3ContC		m_rTgtCont;
	ASEVector3ContC		m_rColorCont;
	ASEFloatContC		m_rMultCont;
	ASEFloatContC		m_rDecayStartCont;
	bool				m_bDoDecay;
	bool				m_bIsSpot;
};


class ASEGroupObjectC : public ASEObjectC
{
public:
	ASEGroupObjectC() {
		m_type = ASE_GROUP_OBJECT;
	};
};


class ASEGeomObjectC : public ASEObjectC
{
public:
	ASEGeomObjectC() {
		m_type = ASE_GEOM_OBJECT;
		m_mtlRef = -1;
	};
	virtual ~ASEGeomObjectC() {
		for( PajaTypes::uint32 i = 0; i < m_TCsets.size(); i++ )
			if( m_TCsets[i] ) delete m_TCsets[i];
	}

	std::vector<PajaTypes::Vector3C>	m_vertices;
	std::vector<PajaTypes::Vector3C>	m_normals;
	std::vector<ASENormalC>				m_baseNormals;
	std::vector<ASETCSetC*>				m_TCsets;
	std::vector<ASEFaceC>				m_faces;
	std::vector<PajaTypes::Vector3C>	m_vertColors;
	PajaTypes::int32					m_mtlRef;
	PajaTypes::ColorC					m_wireColor;
};

/*
class ASEMorphKeyC
{
public:
	ASEMorphKeyC() {};
	virtual ~ASEMorphKeyC() {};

	PajaTypes::int32		m_i32Time;
	PajaTypes::int32		m_i32Target;
	PajaTypes::float32		m_f32Tens, m_f32Cont, m_f32Bias;
};

class ASEMorphObjectC : public ASEObjectC
{
public:
	ASEMorphObjectC() {
		m_type = ASE_MORPH_OBJECT;
	}
	virtual ~ASEMorphObjectC() {};

	std::vector<ASEGeomObjectC*>		m_rTargets;
	std::vector<ASEMorphKeyC>			m_rMorphKeys;
};
*/


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

	bool				load( const char* szName );
	void				purge();

//	PajaTypes::uint32		get_texture_count();
//	PajaTypes::uint32		get_mesh3D_count();
//	ASETextureC*		get_texture( PajaTypes::uint32 index );
//	ASEMesh3DC*			get_mesh3D( PajaTypes::uint32 index );

//	void				set_progress_callback( ASECallbackC* pCb );

	void				convert( std::vector<ScenegraphItemI*>& rMeshRefs,
								 std::vector<Mesh3DC*>& rMeshes,
								 std::vector<CameraC*>& rCameras,
								 std::vector<LightC*>& rLights,
								 Import::ImportInterfaceC* pImpInterface );

	void				get_time_parameters( PajaTypes::int32& i32FPS, PajaTypes::int32& i32TicksPerFrame, PajaTypes::int32& i32FirstFrame, PajaTypes::int32& i32LastFrame );


protected:
private:
	void				cleanup();
	void				read_row();
	char*				get_row();
	void				remove_nl( char* buf );
	char*				extract_string( char* buf, char startDelimit = '\"', char endDelimit = '\"', int* nRead = 0 );
	bool				is_block();
	bool				is_token( const char* token );
	bool				eof();

	void					convert_camera( ASECameraC* pCam );
	void					convert_light( ASELightC* pLight );
	void					convert_geom_object( ASEGeomObjectC* obj, Mesh3DC* pDest, PajaTypes::Matrix3C& rTM );
	void					convert_map( ASEMapC& map, MtlLayerC* pLayer, ASEGeomObjectC* obj );
	Import::FileHandleC*	get_texture( std::string& name );
	void					convert_object( ASEObjectC* pObj, ScenegraphItemI* pParent );

	ASEObjectC*			find_object( const char* szName, ASEObjectC* pParent = 0 );

	void				parse_scene();

	void				parse_materials();
	void				parse_material( ASEMaterialC* mtl );
	ASEObjectC*			parse_geomobject();
	ASEObjectC*			parse_helperobject( std::string& groupName );
	ASEObjectC*			parse_group( std::string& groupName, PajaTypes::int32 i32Indent );
	PajaTypes::uint32	parse_dummy();
	void				parse_mesh( ASEGeomObjectC* mesh );
//	void				parse_morph( ASEMorphObjectC* mesh );
//	void				parse_morph_targets( ASEMorphObjectC* mesh );
//	void				parse_morph_keys( ASEMorphObjectC* mesh );
	void				parse_mesh_node_tm( PajaTypes::Matrix3C& mat, PajaTypes::Matrix3C& offset, PajaTypes::Vector3C& rPos, PajaTypes::QuatC& rRot, PajaTypes::Vector3C& rScale, PajaTypes::QuatC& rScaleRot );
	void				parse_tcset( ASETCSetC* set );
	void				parse_map( ASEMapC& map );

	ASECameraC*			parse_camera();
	bool				parse_look_at_node_tm( PajaTypes::Vector3C& rPos, PajaTypes::float32& f32Roll );
	void				parse_camera_settings( PajaTypes::float32& f32FOV, PajaTypes::float32& f32NearPlane, PajaTypes::float32& f32FarPlane );

	void				parse_pos_track( ASEVector3ContC* pCont );
	void				parse_vector3_track( ASEVector3ContC* pCont );
	void				parse_rot_track( ASEQuatContC* pCont );
	void				parse_scale_track( ASEVector3ContC* pContScale, ASEQuatContC* pContRot );
	void				parse_float_track( ASEFloatContC* pCont );
	void				parse_camera_tm_anim( ASECameraC* pCam );
	PajaTypes::int32	get_ort( const char* szORT );
	void				parse_camera_settings_anim( ASECameraC* pCam );
	void				parse_camera_param_anim( ASECameraC* pCam );
	void				parse_object_tm_anim( ASEObjectC* pObj );
	void				parse_object_vis_track( ASEObjectC* pObj );

	void				parse_light_settings( PajaTypes::ColorC& rColor, PajaTypes::float32& f32Multiplier, PajaTypes::float32& f32DecayStart, bool& bDoDecay );
	void				parse_light_tm_anim( ASELightC* pLight );
	void				parse_light_param_anim( ASELightC* pLight );
	void				parse_light_settings_anim( ASELightC* pLight );
	ASELightC*			parse_light();

	FILE*							m_fp;
	char							m_row[1024];
//	PajaTypes::char8*				m_row;
	char							m_word[256];
	PajaTypes::uint32				m_version;
	std::vector<ASEObjectC*>		m_objects;
	std::vector<ASECameraC*>		m_rCameras;
	std::vector<ASELightC*>			m_rLights;
	std::vector<ASEMaterialC*>		m_materials;

	std::vector<CameraC*>			m_rConvCameras;
	std::vector<LightC*>			m_rConvLights;
	std::vector<Mesh3DC*>			m_rConvMeshes;
	std::vector<ScenegraphItemI*>	m_rConvMeshRefs;

//	std::vector<ASETextureC*>		m_textures;
//	std::vector<ASEMesh3DC*>		m_meshes;

	// proggress stuff
//	ASECallbackC*					m_pCallback;
//	std::string						m_sProgressMsg;

	char*							m_pFile;
	PajaTypes::uint32				m_ui32FileSize;
	PajaTypes::uint32				m_ui32FilePointer;
	PajaTypes::int32				m_i32Percent;
	Import::ImportInterfaceC*		m_pImpInterface;

	std::string						m_sBaseDir;

	PajaTypes::int32				m_i32FPS;
	PajaTypes::int32				m_i32TicksPerFrame;
	PajaTypes::int32				m_i32FirstFrame;
	PajaTypes::int32				m_i32LastFrame;
};


#endif
