/*****************************************************************************
 * $Id: eng_dyna_model.hh,v 1.5 2006/08/20 16:34:17 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	DynaModel class.
 *//*
 * LEGAL:	COPYRIGHT (C) 2006 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef ENG_DYNA_MODEL_HH
#define ENG_DYNA_MODEL_HH 1

#include "eng_object.hh"
#include "eng_dyna.hh"
#include "eng_import.hh"

////////////////////////////////////////////////////////////////////////////////
/// @brief Dyna object with an imported 3D model.
///
/// @verbatim
/// DynaModel supports switching between a set of imported meshes,
/// but DynaModel can be derived from ObjectPolymorph which switches according to LOD
///
/// Switching polygon lists also requires switching local vertexs/normals
/// which is done by SetPolygonListByIdx() by calling SetLocal*().
/// SetWorld*() isn't called (would be meaningless) as world vertexs/normals
/// are dynamically computed from their local counterparts.
/// @endverbatim
///
class DynaModel : public DynaMesh
{
PREVENT_COPYING(DynaModel)
private:						typedef DynaMesh Parent;
public:							DynaModel( QuadrantPtrc q, const Position& pos, const vector<string>& fnameModelVec );
public:		virtual				~DynaModel();
public:		virtual const string GetName( void ) { return string("DynaModel"); }
public:		void				FinalConstruction( void );
public:		virtual void		Save( void ) { } // for when Reset() is called
public:		virtual void		Reset( void ) { SetNeedRecalc(); Parent::Reset(); }
public:		void				SetPosition( const Position& pos ) { SetNeedRecalc(); Parent::SetPosition( pos ); }
public:		void				Translate( uint axis, fp inc );    // recalc needed as setting position is a translation
public:		void				Rotate( uint axis, fp deg );
public:		virtual void		Draw( void );

// Must call SetNeedRecall() whenever object is transformed.
protected:	virtual void		SetNeedRecalc( void ) { mNeedRecalcWorldVertexs = mNeedRecalcNormals = true; }
protected:	bool				mNeedRecalcWorldVertexs;	///< for speed, avoid recalculation when
protected:	bool				mNeedRecalcNormals;			///< object isn't being transformed

// World vertexs/normals are dynamically computed from active model.
public:		const WorldVertex*	GetWorldVertexs( void );
public:		Normal*				GetWorldNormals( void );
protected:	WorldVertex*		mWorldVertexs;
protected:	Normal*				mNormalsWorld;

// Support for multiple models (imported from Blender).
//
// mModels[].mLocalVertexs/Normals are per-object and writable.
// mModels[].mImportation.mLocalVertexs/Normals are shared and read-only.
// The writable copy supports transforming mesh parts.
//
protected:
	class Model
	{
	public:
		Model( void ) { mLocalVertexs = NULL; mLocalNormals = NULL; }
		~Model() { DeleteArray( mLocalVertexs ); DeleteArray( mLocalNormals ); }
		void SetLocalVertexs( const LocalVertex* lv, uint cnt ) { mLocalVertexs = NewArray( lv, cnt ); } // copy
		void SetLocalNormals( const Normal* norm, uint cnt )    { mLocalNormals = NewArray( norm, cnt ); } // copy
		LocalVertex* GetLocalVertexs( void ) { return mLocalVertexs; }
		Normal*      GetLocalNormals( void ) { return mLocalNormals; }
	public:
		Importation		mImportation;   // imported model
	private:
		LocalVertex*	mLocalVertexs;  // per-object writable copies of local vertexs/normals
		Normal*			mLocalNormals;  // for each imported model
	};
public:     uint                GetModelCnt( void ) { return mModels.size(); }
protected:	void				SetModel( uint modelsIdx );
public:		PolygonList&		GetPolygonList( void )  { return *mModels[mModelsIdx].mImportation.GetPolygonList(); }
public:		uint				GetVertexCnt( void )    { return mModels[mModelsIdx].mImportation.GetVertexCnt(); }
public:		LocalVertex*        GetLocalVertexs( void ) { return mModels[mModelsIdx].GetLocalVertexs(); }
public:		Normal*             GetLocalNormals( void ) { return mModels[mModelsIdx].GetLocalNormals(); }
public:		const LocalVertex*  GetSavedLocalVertexs( void ) { return GET_PTR( mModels[mModelsIdx].mImportation.GetLocalVertexs() ); }
public:		const Normal*		GetSavedLocalNormals( void ) { return GET_PTR( mModels[mModelsIdx].mImportation.GetLocalNormals() ); }
            // Get*Max() return counts great enough to accomodate all polygon lists.
            // Be careful using the non-max GetVertexCnt(): they return the count of only the active polygon list.
protected:	uint				GetVertexCntMax( void ) { return mVertexCntMax; }
protected:	uint				GetNormalCntMax( void ) { return mNormalCntMax; }
protected:  vector<Model>		    mModels;
protected:  uint8                   mModelsIdx;			 // index of active model
protected:  uint                    mVertexCntMax;
protected:  uint                    mNormalCntMax;

//public:	void                RotateModel( uint axis, fp deg );  // (keep, may be needed again)
friend class MeshPart;  // to access SetNeedRecalc()
};

#endif // ENG_DYNA_MODEL_HH
