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

//Base Effector class
#ifndef _C4D_BASEEFFECTOR_H_
#define _C4D_BASEEFFECTOR_H_

#include "c4d.h"
#include "ge_dynamicarray.h"

#define Obaseeffector										1018560
#define Obasemogen											1018639
#define ID_BASE_EDEFORMER								1019305	
#define ID_MOTAGDATA										1018625

#define BASEEFFECTORLIB_ID							1019554

#define MSG_EXECUTE_EFFECTOR						1018630
#define MSG_SAMPLE_EFFECTOR_VALUE				1019294
#define MSG_GET_MODATA									1019522

#define BLEND_COUNT 21

//Effector Flags
#define EFFECTORFLAGS_HASFALLOFF				(1 << 0)
#define EFFECTORFLAGS_TIMEDEPENDENT			(1 << 1)
#define EFFECTORFLAGS_CAMERADEPENDENT		(1 << 2)

//MoData Flags
#define MOGENFLAG_CLONE_ON							(1 << 0)	//particles visibility
#define MOGENFLAG_DISABLE								(1 << 1)	//particle permanently disabled
#define MOGENFLAG_BORN									(1 << 2)	//just generated (INTERNAL USE ONLY)
#define MOGENFLAG_MODATASET							(1 << 3)	//the modata has been set and doesn't need the input of the transform panel
#define MOGENFLAG_COLORSET							(1 << 4)	//the modata color has been set and doesn't need to be updated
#define MOGENFLAG_TIMESET								(1 << 5)	//the modata time has been set and doesn't need to be updated

class C4D_Falloff;

// Motion Particle Transformation Data
struct Dpoint
{
	Matrix	m;

	inline Vector GetPos(void) const
	{
		return m.off;
	}

	inline Vector GetSize(void)
	{
		return Len(m.v1), Len(m.v2), Len(m.v3);
	}

	inline void GetMatrix(Matrix &h, const Vector &size) const
	{
		h = m;
		h.v1 -= h.off;
		h.v2 -= h.off;
		h.v3 -= h.off;
		h.v1 = !(h.v2 % h.v3) * size.x;
		h.v2 = !(h.v3 % h.v1) * size.y;
		h.v3 = !(h.v2 % h.v1) * size.z;
	}
};

// "Info Point" handles the information for each particle.
struct Ipoint
{
public:
	Ipoint()
	{
		flags =		MOGENFLAG_CLONE_ON|MOGENFLAG_BORN;
		color =		0.5f;
		size =		1.0f;
		weight =	0.0f;
		clone =		1.0f;
		uvw =			0.0f;
		time =		0.0f;
		alt_index = NOTOK;
	}
	~Ipoint()
	{
	}

	Vector	color;			//color of the particle
	Vector	size;				//size of the particle
	Vector	uvw;				//particles direct UVW position
	LONG		flags;			//particle flags
	Real		weight;			//offset against falloff value to allow effectors to drive other effectors
	Real		clone;			//the index of the child that will be cloned in the cloner object
	Real		time;				//delta time for each clone
	Matrix	lastmat;		//last position
	Matrix	startmat;		//starting position
	LONG		alt_index;	//alternative index for particles, instancer etc with some effectors, e.g. step.
};

// Structure for passing cloned points around
struct MoData
{
	LONG									count;	//maximum number of particles
	GeDynamicArray<Dpoint>	mat;		//matrices
	GeDynamicArray<Ipoint>	data;		//other data
};

// Structure for passing modata around
struct GetMoDataMessage
{
	MoData *modata;
};

//-------------------
// structure to pass with execute effector message
struct Effector_PassData
{
	Effector_PassData ( void )
	{
		op = NULL;
		md = NULL;
		weight = 1.0f;
		thread = NULL;
	}
	BaseObject		*op;
	MoData				*md;
	Real					weight;
	BaseThread		*thread;
};

// structure to get pass with sample effector value
struct Effector_PassValueData
{
	Effector_PassValueData ( void )
	{
		value = 0.0f;
		pos = 0.0f;
	}
	Real		value;
	Vector	pos;
};

struct EffectorStrengths
{
	Vector	pos, scale, rot, col, other, other2, other3;
};

struct EffectorDataStruct
{
	Real		falloff_time;
	Vector	pos, scale, rot, col;								//position, scale, rotation, color
	Real		strength;														//effector strength
	Real		maxstrength;												//effector minimum strength
	Real		minstrength;												//effector minimum strength
	LONG		trans_mode;													//transform mode
	LONG		col_mode;														//color mode
	LONG		blend_mode;													//blending mode
	Real		strengths[BLEND_COUNT];							//ammount of strengths for each value, of in order, position, scale, rotation, color (anything else we want to affect)
};

struct EffectorDataParameters;

class EffectorData : public ObjectData
{
	public:
		EffectorDataParameters *edata;

		//-----------------------------------------------------
		//Inherited from ObjectData
		virtual Bool									Init(GeListNode *node);
		virtual void									Free(GeListNode *node);
		virtual Bool									GetDDescription(GeListNode *node, Description *description, LONG &flags);
		virtual Bool									Draw(BaseObject *op, LONG type, BaseDraw *bd, BaseDrawHelp *bh);
		virtual void									GetDimension(BaseObject *op, Vector *mp, Vector *rad);
		virtual Bool									AddToExecution(BaseObject *op, PriorityList *list);
		virtual LONG									Execute(BaseObject *op, BaseDocument *doc, BaseThread *bt, LONG priority, LONG flags);
		virtual Bool									ModifyObject(BaseObject	*mod,BaseDocument *doc,BaseObject *op,const Matrix &op_mg,const Matrix	&mod_mg,Real lod,LONG flags,BaseThread *thread);
		virtual Bool									Message(GeListNode *node, LONG type, void *t_data);
		virtual LONG									GetHandleCount(BaseObject *op);
		virtual Vector								GetHandle(BaseObject *op, LONG i);
		virtual void									SetHandle(BaseObject *op, LONG i, Vector p);
		virtual Bool									CopyTo(NodeData *dest,GeListNode *snode,GeListNode *dnode,LONG flags,AliasTrans *trn);
		virtual Bool									IsInstanceOf(const GeListNode *node, LONG type) const;

		//Internal versions of inherited routines
		virtual Bool									InitEffector(GeListNode *node);
		virtual void									FreeEffector(GeListNode *node);

		//-----------------------------------------------------
		//Effector Routines
		EffectorDataStruct*						GetEffectorData(void);
		C4D_Falloff*									GetFalloff(void);
		void													AddEffectorDependence(BaseObject *op);

		virtual LONG									GetEffectorFlags(void);
		virtual Bool									ModifyDDescription(GeListNode *node, Description *description, AtomArray *ar);

		virtual Bool									ExecuteEffector(BaseObject *op, BaseDocument *doc, BaseObject *gen, MoData *md, Real strength, BaseThread *thread);
		virtual void									InitPoints(BaseObject *op, BaseObject *gen, BaseDocument *doc, EffectorDataStruct *data, MoData *md, BaseThread *thread);
		virtual void									ModifyPoints(BaseObject *op, BaseObject *gen, BaseDocument *doc, EffectorDataStruct *data, MoData *md, BaseThread *thread);
		virtual void									FreePoints(void);

		//------------------------------------------------------
		//for random etc, where a value must be calculated even if it's not used
		virtual void									CalcPlacebo(BaseObject *op, BaseObject *gen, BaseDocument	*doc, EffectorDataStruct *data, LONG index, MoData *md, const Vector &globalpos, Real fall_weight);

		//modify data->strengths values accordingly in CalcPointValue
		virtual void									CalcPointValue(BaseObject	*op, BaseObject	*gen,	BaseDocument *doc, EffectorDataStruct *data, LONG index, MoData	*md, const Vector	&globalpos, Real fall_weight);

		//called separately as it may not be needed (and therefore sometimes might reduce number of calculations
		virtual Vector								CalcPointColor(BaseObject	*op, BaseObject	*gen, BaseDocument *doc, EffectorDataStruct *data, LONG index, MoData	*md, const Vector	&globalpos, Real fall_weight);
};

Bool RegisterEffectorPlugin(LONG id, const String &str, LONG info, DataAllocator *g, const String &description, BaseBitmap *icon, LONG disklevel);
Bool RegisterEffectorPlugin(LONG id, const String &str, LONG info, DataAllocator *g, const String &description, String icon, LONG disklevel);
Bool RegisterEffectorPlugin(LONG id, const String &str, LONG info, DataAllocator *g, const String &description, LONG disklevel);

#endif

