//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//=============================================================================//

//===================================================================
// Useful macros
//
#define CONSTRUCTOR
#define DESTRUCTOR

#define EXPORT_THIS		__declspec(dllexport)

#define DEFAULT_EXT		_T("vvw")

#define FStrEq(sz1, sz2) (strcmp((sz1), (sz2)) == 0)


//=============================================================================
//							TREE-ENUMERATION PROCEDURES
//=============================================================================

#define ASSERT_AND_ABORT(f, sz)							\
	if (!(f))											\
	{													\
		ASSERT_MBOX(FALSE, sz);							\
		cleanup( );										\
		return TREE_ABORT;								\
	}


// Integer constants for this class
enum
	{
	MAX_NAME_CHARS			= 70,
	UNDESIRABLE_NODE_MARKER	= -7777
	};

// For keeping info about each (non-ignored) 3dsMax node in the tree
typedef struct
{
	char		szNodeName[MAX_NAME_CHARS];	// usefull for lookups
	Matrix3		mat3NodeTM;					// node's transformation matrix (at time zero)
	Matrix3		mat3ObjectTM;				// object-offset transformation matrix (at time zero)
	int			imaxnodeParent;				// cached index of parent node
} MaxNode;

typedef struct
{
	float		flDist;
	float		flWeight;
} MaxVertWeight;

//===================================================================
// Class that implements the scene-export.
//
class VWeightExportClass : public SceneExport
{
	friend BOOL CALLBACK ExportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
	friend class CollectModelTEP;

public:
	CONSTRUCTOR				VWeightExportClass	(void);
	DESTRUCTOR				~VWeightExportClass	(void);

	// Required by classes derived from SceneExport
	virtual int				ExtCount		(void)		{ return 1;						}
	virtual const TCHAR*	Ext				(int i)		{ return DEFAULT_EXT;			}
	virtual const TCHAR*	LongDesc		(void)		{ return _T("Valve Skeletal Model Exporter for 3D Studio Max");	}
	virtual const TCHAR*	ShortDesc		(void)		{ return _T("Valve VVW");			}
	virtual const TCHAR*	AuthorName		(void)		{ return _T("Valve, LLC");			}
	virtual const TCHAR*	CopyrightMessage(void)		{ return _T("Copyright (c) 1998, Valve LLC");			}
	virtual const TCHAR*	OtherMessage1	(void)		{ return _T("");				}
	virtual const TCHAR*	OtherMessage2	(void)		{ return _T("");				}
	virtual unsigned int	Version			(void)		{ return 201;					}
	virtual void			ShowAbout		(HWND hWnd)	{ return;						}
	// virtual int				DoExport		(const TCHAR *name, ExpInterface *ei, Interface *i);
	virtual int		DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE,DWORD options=0); // Export	file

	MaxNode		m_MaxNode[512];		// array of nodes
	long		m_cMaxNode;		// # of nodes

	MaxVertWeight *m_MaxVertex[10000];
	long		m_cMaxVertex;

	// Animation metrics (gleaned from 3dsMax and cached for convenience)
	Interval	m_intervalOfAnimation;
	TimeValue	m_tvStart;
	TimeValue	m_tvEnd;
	int			m_tpf;		// ticks-per-frame

private:
	void					CollectNodes( INode *pnode );
	BOOL					CollectModel( ExpInterface *pexpiface );
};


//===================================================================
// Basically just a ClassFactory for communicating with 3DSMAX.
//
class VWeightExportClassDesc : public ClassDesc
{
public:
	int				IsPublic		(void)					{ return TRUE;								}
	void *			Create			(BOOL loading=FALSE)	{ return new VWeightExportClass;				}
	const TCHAR *	ClassName		(void)					{ return _T("VWeightExport");					}
	SClass_ID 		SuperClassID	(void)					{ return SCENE_EXPORT_CLASS_ID;				}
	Class_ID 		ClassID			(void)					{ return Class_ID(0x554b1092, 0x206a444f);	}
	const TCHAR *	Category		(void)					{ return _T("");							}
};


//===================================================================
// Tree Enumeration Callback
//		Just counts the nodes in the node tree
//
class CountNodesTEP : public ITreeEnumProc
{
public:
	virtual int				callback(INode *node);
	int						m_cNodes;		// running count of nodes
};


//===================================================================
// Tree Enumeration Callback
//		Collects the nodes in the tree into the global array
//
class CollectNodesTEP : public ITreeEnumProc
{
public:
	virtual int				callback(INode *node);
	VWeightExportClass			*m_phec;
};



//===================================================================
// Tree Enumeration Callback
//		Dumps the triangle meshes to a file.
//
class CollectModelTEP : public ITreeEnumProc
{
public:
	virtual int				callback(INode *node);
	void					cleanup(void);
	// FILE					*m_pfile;		// write to this file
	TimeValue				m_tvToDump;		// dump snapshot at this frame time
	VWeightExportClass			*m_phec;
	IPhyContextExport		*m_mcExport;
	IPhysiqueExport			*m_phyExport;
    Modifier				*m_phyMod;
	Modifier				*m_bonesProMod;
	BonesPro_WeightArray	*m_wa;
private:
	int						CollectWeights( int iVertex, MaxVertWeight *pweight );
};


//===================================================================
// Prototype declarations
//
void ResetINodeMap( void );
int BuildINodeMap(INode *pnode);
void AddINode( INode *pnode );
int GetIndexOfNodeName( TCHAR *szNodeName, BOOL fAssertPropExists = TRUE );
int GetIndexOfINode( INode *pnode, BOOL fAssertPropExists = TRUE);

BOOL FUndesirableNode( INode *pnode);
BOOL FNodeMarkedToSkip( INode *pnode);
Modifier *FindPhysiqueModifier( INode *nodePtr );
Modifier *FindBonesProModifier( INode *nodePtr );
int AssertFailedFunc(char *sz);
#define ASSERT_MBOX(f, sz) ((f) ? 1 : AssertFailedFunc(sz))
void GetUnifiedCoord( Point3 &p1, MaxVertWeight pweight[], MaxNode maxNode[], int cMaxNode );

int GetBoneWeights( IPhyContextExport *mcExport, int iVertex, MaxVertWeight *pweight);
int GetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight);
void SetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight);