/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2006 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef __LIB_CA_H__
#define __LIB_CA_H__

#include "c4d_library.h"
#include "c4d_baseobject.h"
#include "c4d_basetag.h"
#include "c4d_tooldata.h"
#include "c4d_descriptiondialog.h"
#include "c4d_general.h"

struct JointRestState
{
	JointRestState() { m_Len=0.0; }
	Matrix m_Mg,m_Mi;
	Real m_Len;
};

class CAWeightTag;

class CAJointObject : public PluginObject
{
private:
	CAJointObject();
	~CAJointObject();
public:
	static CAJointObject *Alloc() { return (CAJointObject*)PluginObject::Alloc(Ojoint); }
	static void Free(CAJointObject *&pObject) { PluginObject *op=pObject; PluginObject::Free(op); pObject=NULL; }

	void GetBone(Matrix &m, Real &len);
	CAWeightTag *GetWeightTag(LONG &index);
};

class CAWeightTag : public PluginTag
{
private:
	CAWeightTag();
	~CAWeightTag();
public:
	static CAWeightTag *Alloc() { return (CAWeightTag*)PluginTag::Alloc(Tweights); }
	static void Free(CAWeightTag *&pTag) { PluginTag *tag=pTag; PluginTag::Free(tag); pTag=NULL; }

	BaseObject *GetJoint(LONG index, BaseDocument *doc);	// get joint object at 'index', doc can be NULL
	LONG GetJointCount();				// get total joints; can also be found and changed using SetParameter with ID_CA_WEIGHT_TAG_JOINTS
	LONG FindJoint(BaseObject *op, BaseDocument *doc);		// return the index of this object or NOTOK if not found, doc can be NULL
	
	JointRestState GetJointRestState(LONG index);	// get the rest state for the joint at 'index'
	void SetJointRestState(LONG index, const JointRestState &state);	// set the rest state for the joint
	
	void GetWeightMap(LONG index, Real *map, LONG cnt);	// fill in the weights to 'map' that must be allocated with 'cnt' (this should be the point count)
	Bool SetWeightMap(LONG index, Real *map, LONG cnt); // set the entire weight map using 'map'
	
	LONG GetWeightCount(LONG index);	// get total stored weights, zero weights are not stored
	void GetIndexWeight(LONG index, LONG windex, LONG &pntindex, Real &weight);	// get the windex weight and which point index it is for plus the weight

	Real GetWeight(LONG index, LONG pntindex);	// return the weight for the point pntindex
	Bool SetWeight(LONG index, LONG pntindex, Real weight); // set the weight for pntindex

	ULONG GetDirty();	// get the dirty state of the weights
	void Dirty();		// make the weights dirty
};

//////////////////////////////////////////////////////////////////////////

#define BRUSHBASE_MOUSE_FLAG_ADDUNDO				(1<<0)
#define BRUSHBASE_MOUSE_FLAG_ADDUNDO_FULL			(1<<1)
#define BRUSHBASE_MOUSE_FLAG_SORTED_DIST			(1<<2)
#define BRUSHBASE_MOUSE_FLAG_SORTED_OBJECT			(1<<3)
#define BRUSHBASE_MOUSE_FLAG_SORTED_ORIGINOBJECT	(1<<4)

#define BRUSHBASE_FALLOFF_STRENGTH		(1<<0)

class _BrushToolBase;
class iBrushBase;
class BrushObjectData;
class BrushToolData;

class BrushObjectInfo
{
public:
	BrushObjectInfo()
	{
		m_pObject=NULL;
		m_pOriginObject=NULL;
		m_pDeformObject=NULL;
		m_pNeighbor=NULL;
		m_pPoints=NULL;
		m_pGlobalPoints=NULL;
		m_pNormals=NULL;
		m_pPolys=NULL;
		m_PointCount=0;
		m_PolyCount=0;
	}

	BaseObject *m_pObject;
	BaseObject *m_pOriginObject;
	BaseObject *m_pDeformObject;
	
	Neighbor *m_pNeighbor;
	const Vector *m_pPoints;
	Vector *m_pGlobalPoints,*m_pNormals;
	const CPolygon *m_pPolys;
	LONG m_PointCount,m_PolyCount;
};

class BrushVertexData
{
public:
	Real m_Dist;
	LONG m_Index;
	BrushObjectData *m_pObject;
};

class BrushPixelData
{
public:
	BrushObjectData *m_pObject;
	LONG m_Index;
	Real m_Z;
	BrushPixelData *m_pNext;
};

class BrushBase
{
private:

	BrushBase();
	~BrushBase();

	_BrushToolBase *m_pBase;

public:

	static BrushBase *Alloc();
	static void Free(BrushBase *&p);

	Bool InitTool(BaseDocument* doc, BaseContainer& data, BaseThread* bt, BrushToolData *tool);
	void FreeTool(BaseDocument* doc, BaseContainer& data);
	void InitDefaultSettings(BaseDocument *doc, BaseContainer &data);
	Bool GetDEnabling(BaseDocument* doc, BaseContainer& data, const DescID& id, GeData& t_data, LONG flags, const BaseContainer* itemdesc);
	Bool SetDParameter(BaseDocument* doc, BaseContainer& data, const DescID& id, const GeData& t_data, LONG& flags);
	Bool GetDDescription(BaseDocument* doc, BaseContainer& data, Description* description, LONG& flags);
	Bool Message(BaseDocument *doc, BaseContainer &data, LONG type, void *t_data);
	Bool GetCursorInfo(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, Real x, Real y, BaseContainer& bc);
	Bool MouseInput(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, EditorWindow* win, const BaseContainer& msg);
	BrushVertexData *GetSelected(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, LONG &vcnt, LONG x, LONG y, Real rad, BaseObject *op);	// must call ValidateObjects before any calls to this
	Real GetCursor(LONG &x, LONG &y);
	void GetObjectInfo(BrushObjectData *data, BrushObjectInfo &info);
	Bool GetObjectInfo(BaseObject *op, BrushObjectInfo &info);
	Bool ValidateObjects(BaseDocument *doc, BaseContainer& data);
	BrushPixelData *GetObjectAt(LONG x, LONG y);	// must call ValidateObjects before any calls to this
	Real GetFalloff(Real dst, LONG flags);	// only valid within mouseinput
	Bool GetObjects(BaseDocument *doc, AtomArray *objects);
	Bool UpdateCache(BaseDocument *doc, BaseContainer& data, BaseDraw *bd, Bool force);
	Real *CalcSurfaceDistances(PolygonObject *pObject, BaseSelect *selected, Neighbor *pNeighbor=NULL, Vector *pNormals=NULL, Vector *pGlobalPoints=NULL, Real *pDistance=NULL);
	Real *CalcSurfaceDistancesFromPoint(PolygonObject *pObject, LONG pindex, Neighbor *pNeighbor=NULL, Vector *pNormals=NULL, Vector *pGlobalPoints=NULL, Real *pDistance=NULL);
};

class BrushToolData : public DescriptionToolData
{
	INSTANCEOF(BrushToolData,DescriptionToolData)

public:

	BrushToolData() { m_pBrushBase=NULL; }
	~BrushToolData() { BrushBase::Free(m_pBrushBase); }

	BrushBase *m_pBrushBase;

	//////////////////////////////////////////////////////////////////////////

	virtual Bool InitTool(BaseDocument* doc, BaseContainer& data, BaseThread* bt);
	virtual void FreeTool(BaseDocument* doc, BaseContainer& data);
	virtual void InitDefaultSettings(BaseDocument *doc, BaseContainer &data);
	virtual Bool GetDEnabling(BaseDocument* doc, BaseContainer& data, const DescID& id, GeData& t_data, LONG flags, const BaseContainer* itemdesc);
	virtual Bool SetDParameter(BaseDocument* doc, BaseContainer& data, const DescID& id, const GeData& t_data, LONG& flags);
	virtual Bool GetDDescription(BaseDocument* doc, BaseContainer& data, Description* description, LONG& flags);	
	virtual Bool Message(BaseDocument *doc, BaseContainer &data, LONG type, void *t_data);
	virtual Bool GetCursorInfo(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, Real x, Real y, BaseContainer& bc);
	virtual Bool MouseInput(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, EditorWindow* win, const BaseContainer& msg);

	//////////////////////////////////////////////////////////////////////////
	
	virtual Bool MouseInputStart(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, EditorWindow* win, const BaseContainer& msg, LONG &flags) { return TRUE; }
	virtual Bool MouseInputDrag(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, EditorWindow* win, const BaseContainer& msg, BrushVertexData* vdata, LONG vcnt, Real x, Real y, LONG &flags) { return TRUE; }
	virtual Bool MouseInputEnd(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, EditorWindow* win, const BaseContainer& msg) { return TRUE; }
};

//////////////////////////////////////////////////////////////////////////

// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF

//////////////////////////////////////////////////////////////////////////
#define LIBRARY_CA		1019742
#define LIBRARY_BRUSH	1019809
//////////////////////////////////////////////////////////////////////////

struct CALibrary : public C4DLibrary
{
	//////////////////////////////////////////////////////////////////////////
	// Weight Tag

	BaseObject *(*weightGetJoint)(CAWeightTag *tag, LONG index, BaseDocument *doc);
	LONG (*weightGetJointCount)(CAWeightTag *tag);
	LONG (*weightFindJoint)(CAWeightTag *tag, BaseObject *op, BaseDocument *doc);
	JointRestState (*weightGetJointRestState)(CAWeightTag *tag, LONG index);
	void (*weightSetJointRestState)(CAWeightTag *tag, LONG index, const JointRestState &state);
	void (*weightGetWeightMap)(CAWeightTag *tag, LONG index, Real *map, LONG cnt);
	Bool (*weightSetWeightMap)(CAWeightTag *tag, LONG index, Real *map, LONG cnt);
	LONG (*weightGetWeightCount)(CAWeightTag *tag, LONG index);
	void (*weightGetIndexWeight)(CAWeightTag *tag, LONG index, LONG windex, LONG &pntindex, Real &weight);
	Real (*weightGetWeight)(CAWeightTag *tag, LONG index, LONG pntindex);
	Bool (*weightSetWeight)(CAWeightTag *tag, LONG index, LONG pntindex, Real weight);
	ULONG (*weightGetDirty)(CAWeightTag *tag);
	void (*weightDirty)(CAWeightTag *tag);

	//////////////////////////////////////////////////////////////////////////
	// Joint Object

	void (*jointGetBone)(CAJointObject *op, Matrix &m, Real &len);
	CAWeightTag *(*jointGetWeightTag)(CAJointObject *op, LONG &index);
};

struct BrushBaseLibrary : public C4DLibrary
{
	iBrushBase *(*Alloc)();
	void (*Free)(iBrushBase *&p);

	Bool (iBrushBase::*InitTool)(BaseDocument* doc, BaseContainer& data, BaseThread* bt, BrushToolData *tool);
	void (iBrushBase::*FreeTool)(BaseDocument* doc, BaseContainer& data);
	void (iBrushBase::*InitDefaultSettings)(BaseDocument *doc, BaseContainer &data);
	Bool (iBrushBase::*GetDEnabling)(BaseDocument* doc, BaseContainer& data, const DescID& id, GeData& t_data, LONG flags, const BaseContainer* itemdesc);
	Bool (iBrushBase::*SetDParameter)(BaseDocument* doc, BaseContainer& data, const DescID& id, const GeData& t_data, LONG& flags);
	Bool (iBrushBase::*GetDDescription)(BaseDocument* doc, BaseContainer& data, Description* description, LONG& flags);
	Bool (iBrushBase::*Message)(BaseDocument *doc, BaseContainer &data, LONG type, void *t_data);
	Bool (iBrushBase::*GetCursorInfo)(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, Real x, Real y, BaseContainer& bc);
	Bool (iBrushBase::*MouseInput)(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, EditorWindow* win, const BaseContainer& msg);
	BrushVertexData *(iBrushBase::*GetSelected)(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, LONG &vcnt, LONG x, LONG y, Real rad, BaseObject *op);
	Real (iBrushBase::*GetCursor)(LONG &x, LONG &y);
	void (iBrushBase::*GetObjectInfo)(BrushObjectData *data, BrushObjectInfo &info);
	Bool (iBrushBase::*GetObjectInfoOp)(BaseObject *op, BrushObjectInfo &info);
	Bool (iBrushBase::*ValidateObjects)(BaseDocument *doc, BaseContainer& data);
	BrushPixelData *(iBrushBase::*GetObjectAt)(LONG x, LONG y);
	Real (iBrushBase::*GetFalloff)(Real dst, LONG flags);
	Bool (iBrushBase::*GetObjects)(BaseDocument *doc, AtomArray *objects);
	Bool (iBrushBase::*UpdateCache)(BaseDocument *doc, BaseContainer& data, BaseDraw *bd, Bool force);
	Real *(iBrushBase::*CalcSurfaceDistances)(PolygonObject *pObject, BaseSelect *selected, Neighbor *pNeighbor, Vector *pNormals, Vector *pGlobalPoints, Real *pDistance);
	Real *(iBrushBase::*CalcSurfaceDistancesFromPoint)(PolygonObject *pObject, LONG pindex, Neighbor *pNeighbor, Vector *pNormals, Vector *pGlobalPoints, Real *pDistance);
};

// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF

#endif	// __LIB_CA_H__
