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

#ifndef __C4D_PARTICLESNEW_H
#define __C4D_PARTICLESNEW_H

////////////////////////////////
#define ID_THINKINGPARTICLES			1001428
#define ID_TP_PGROUP							1001381
#define ID_TP_PARTICLEGEOMETRY		1001414

#define ID_TP_VALUE_TYPE_PARTICLE	1001394
#define ID_TP_DATA_TYPE_PARTICLE	1001395
#define ID_TP_VALUE_TYPE_SHAPE		1001396
#define ID_TP_DATA_TYPE_SHAPE			1001397
#define ID_TP_VALUE_TYPE_GROUP		1001398
#define ID_TP_DATA_TYPE_GROUP			1001399
#define ID_TP_VALUE_TYPE_SPIN			1001433
#define ID_TP_DATA_TYPE_SPIN			1001434


#define ID_TP_OPCLASS							1001385
#define ID_TP_OPGROUP_CONDITION		1001386
#define ID_TP_OPGROUP_HELPER			1001387
#define ID_TP_OPGROUP_INITIATOR		1001388
#define ID_TP_OPGROUP_GENERATOR		1001389
#define ID_TP_OPGROUP_STANDARD		1001390
#define ID_TP_OPGROUP_DYNAMIC			1001391


#define ID_TP_OP_STORM						1001382
#define ID_TP_IN_SELFDYNAMIC			1001435
#define ID_TP_HP_PARTICLEDATA			1001403
#define ID_TP_OP_PARTICLEDATA			1001404
#define ID_TP_IN_INTERACT					1001405
#define ID_TP_IF_PARTICLEAGE			1001406
#define ID_TP_HP_SPINCONVERT			1001408
#define ID_TP_HP_PGROUP						1001409
#define ID_TP_HP_VELOCITYCONVERT	1001410
#define ID_TP_OP_DEFLECTOR				1001411
#define ID_TP_OP_POSFOLLOW				1001412
#define ID_TP_OP_OBJECTSHAPE			1001413
#define ID_TP_OP_SPIN							1001415
#define ID_TP_OP_ALIGNMENT				1001416
#define ID_TP_OP_PGROUP						1001417
#define ID_TP_OP_MASS							1001418
#define ID_TP_OP_SIZE							1001419
#define ID_TP_OP_SCALE						1001420
#define ID_TP_OP_FRICTION					1001421
#define ID_TP_OP_VELOCITY					1001422
#define ID_TP_OP_MOTIONINHERI			1001423
#define ID_TP_OP_BUBBLE						1001424
#define ID_TP_OP_DIE							1001425
#define ID_TP_OP_GRAVITY					1001426
#define ID_TP_OP_WIND							1001427
#define ID_TP_HP_TIMER						1001429
#define ID_TP_HP_CHRONOMETER			1001430
#define ID_TP_OP_FRAGMENT					1001431
#define ID_TP_OP_FREEZE						1001432
#define ID_TP_OP_REPULSEBOUNCE		1001436
#define ID_TP_OP_ROLLING					1001437
#define ID_TP_IF_LIGHT						1001438
#define ID_THINKINGCOMMAND				1001439
#define ID_TP_HP_SURFACEPOSITION	1001440
#define ID_TP_HP_VOLUMEPOSITION		1001441
#define ID_TP_OP_BORN							1001442
#define TP_SN_HOOK								1001443
#define ID_TP_OP_BLURP						1001444
#define ID_TP_OP_PARTICLEDRAW			1001445
#define ID_TP_OP_PARTICLEDRAWTOOL	1001446
#define ID_TP_OP_MATTERWAVES			1001447
////////////////////////////////

#include "ge_math.h"
#include "c4d_misc.h"
#include "c4d_library.h"
#include "c4d_string.h"
#include "c4d_baselist.h"
#include "c4d_nodedata.h"
#include "c4d_objectdata.h"
#include "c4d_graphview.h"
#include "c4d_baseobject.h"
#include "c4d_basedocument.h"
#include "lib_collider.h"

#define THINKINGPARTICLES_VERSION			1
#define THINKINGPARTICLES_PRIORITY		GRAPHVIEW_HOOK_PRIORITY - 100



class TP_PGroup;
class TP_ParticleNode;
class TP_MasterSystem;


#define TP_PGroupInfo	      	BaseContainer

#define TP_DataChannelInfo		BaseContainer
#define DATACHANNEL_INFO_CHAN	100
#define DATACHANNEL_INFO_NAME	101
#define DATACHANNEL_INFO_TYPE	102



class TP_PGroupArray : public c4d_misc::BaseArray<TP_PGroup*> 
{
public:
	TP_PGroupArray() {}

	// In the move constructor you can use std::move() to initialize class members. Extra care must be taken if you want to call
	// the move constructor of your base class. Instead of BaseClass(std::move(src)) you should call C4D_MISC_MOVE_BASE_CLASS(src, BaseClass).
	// For compiler with C++11 rvalue reference this is equivalent to BaseClass(std::move(src)), but for older compilers it makes
	// sure that std::move() is called with a reference to src's base class (otherwise the compiler would try to call the copy constructor).
  TP_PGroupArray(C4D_MISC_MOVE_TYPE(TP_PGroupArray) src) : C4D_MISC_MOVE_BASE_CLASS(src, c4d_misc::BaseArray<TP_PGroup*>)
	{
	}

	Bool CopyTo(TP_PGroupArray *dest) const 
	{ 
		return dest->CopyFrom(*this,false); 
	}

	TP_PGroup* GetIndex(LONG i) const 
	{ 
		if (i < 0 || i >= GetCount())
			return NULL; // unfortunately this case was allowed in old GeTempDynArrays and is heavily used

		return c4d_misc::BaseArray<TP_PGroup*>::operator[](i); 
	}
};

struct TP_Spin
{
	Vector axis;
	Real   speed;
};

// used with SetPGroupHierarchy()
enum TP_InsertMode
{
	TP_INSERT_NONE = 0,
	TP_INSERT_UNDERFIRST,
	TP_INSERT_UNDERLAST,
	TP_INSERT_BEFORE,
	TP_INSERT_AFTER
};
////////////////////////////////
// used with GetParticleGroups()
enum TP_GetPGroupMode
{
	TP_GETPGROUP_ALL = 0,
	TP_GETPGROUP_WITHPARTICLES,
	TP_GETPGROUP_SELECTED
};
////////////////////////////////



#define TP_Collision	LONG


class TP_BaseCollision {};

struct TP_CollisionInterface
{
	TP_BaseCollision *base;

	Bool (*CheckCollision)(TP_BaseCollision *this_ptr,TP_Collision collision, TP_MasterSystem *msys, LONG pid, Real t, Vector &pos, Vector &vel, TP_Spin &spin, Real dt, Real &ct);
};

#include <string.h>

struct TP_PShapeI
{
	LONG	owner_id;
	LONG  refcnt;

	TP_PShapeI(void) : owner_id(NOTOK),refcnt(0) { }

	virtual ~TP_PShapeI()
	{
	}
};

class TP_PShapePtr
{
		TP_PShapeI *ptr;
	public:
		TP_PShapePtr() { ptr=NULL; }
		TP_PShapePtr(const TP_PShapePtr &p)
		{
			ptr = p.ptr;
			if (ptr)
			{
				ptr->refcnt++;
			}
		}
		TP_PShapePtr(TP_PShapeI *p)
		{
			ptr = p;
			if (ptr)
			{
				ptr->refcnt++;
			}
		}
		Bool operator == (const TP_PShapePtr &p)
		{
			return ptr==p.ptr;
		}
		Bool operator != (const TP_PShapePtr &p)
		{
			return ptr!=p.ptr;
		}
		const TP_PShapePtr& operator = (const TP_PShapePtr &p)
		{
			if (ptr)
			{
				ptr->refcnt--;
				if (ptr->refcnt==0)
				{
					gDelete(ptr);
				}
			}
			ptr = p.ptr;
			if (ptr)
			{
				ptr->refcnt++;
			}
			return *this;
		}
		const TP_PShapePtr& operator = (TP_PShapeI *p)
		{
			*this = TP_PShapePtr(p);
			return *this;
		}
		Bool Content() const
		{
			return ptr!=NULL;
		}
		TP_PShapeI *Get() const
		{
			return ptr;
		}
		~TP_PShapePtr()
		{
			if (ptr)
			{
				ptr->refcnt--;
				if (ptr->refcnt==0)
				{
					gDelete(ptr);
				}
			}
		}
};


class TP_BaseShape {};

struct TP_PShapeInterface
{
	TP_BaseShape *base;

	TP_PShapePtr  (*GetShapeClone)(TP_BaseShape *this_ptr,const TP_PShapePtr &shape , TP_MasterSystem *msys, LONG pid, COPYFLAGS flags, AliasTrans *trn);
	TP_PShapePtr  (*GetShape)(TP_BaseShape *this_ptr,const TP_PShapePtr &shape , TP_MasterSystem *msys, LONG pid, LONG owner_id);
	BaseObject* (*GetShapeVirtualObjects)(TP_BaseShape *this_ptr,const TP_PShapePtr &shape , TP_MasterSystem *msys, LONG pid, BaseDocument *doc, HierarchyHelp *hh);
	Real        (*GetShapeScale)(TP_BaseShape *this_ptr,const TP_PShapePtr &shape , TP_MasterSystem *msys, LONG pid);
	void        (*FreeShape)(TP_BaseShape *this_ptr,TP_PShapePtr &shape , TP_MasterSystem *msys, LONG pid);
};



//CallBacks
struct TP_FreeParticle_CB
{
	void (*FreeParticle)(TP_FreeParticle_CB *cb, LONG pid);
};

struct TP_FreePShape_CB
{
	void (*FreePShape)(TP_FreePShape_CB *cb, LONG pid, const TP_PShapePtr &shape);
};
//

enum
{
	TP_MSG_PGROUP_PREREMOVE = 1000000,	//data *TP_PGroup
	TP_MSG_PGROUP_TREECHANGED,					//data NULL
	TP_MSG_DCHANNEL_PREREMOVE,					//data chan
	TP_MSG_DCHANNEL_CHANGED,						//data NULL
	TP_MSG_OBJECT_GETPARTICLES_EX,			//
	TP_MSG_GET_PSHAPEINTERFACE,					//data **TP_PShapeInterface
	TP_MSG_GET_COLLISIONINTERFACE,			//data **TP_CollisionInterface
	TP_MSG_OBJECT_GETPARTICLES					//data *TP_PGroupArray
};

struct TP_Msg
{
	LONG             msg;
	TP_MasterSystem *msys;
	void            *data;
};

struct TP_PGroupPreRemove
{
	TP_PGroup *pgroup;
	Bool       used;
};



struct C4D_TP_MASTERSYSTEM
{
	LONG (*AllocParticle   )(TP_MasterSystem *this_ptr);
	LONG (*AllocParticles  )(TP_MasterSystem *this_ptr,LONG num, LONG *ids);
	void (*FreeParticle    )(TP_MasterSystem *this_ptr,LONG pid);
	void (*FreeAllParticles)(TP_MasterSystem *this_ptr);

	TP_PGroup    *(*AllocParticleGroup)(TP_MasterSystem *this_ptr);
	void			(*FreeParticleGroup)(TP_MasterSystem *this_ptr,TP_PGroup *&group);
	Bool			(*SetPGroupHierarchy)(TP_MasterSystem *this_ptr,TP_PGroup *parent , TP_PGroup *group, TP_InsertMode mode);
	LONG			(*GetParticleGroupsEx)(TP_MasterSystem *this_ptr,TP_PGroup *ingroup, TP_PGroupArray *gtab, TP_GetPGroupMode mode, Bool subgroups);
	LONG			(*GetGroupParticleCount)(TP_MasterSystem *this_ptr,TP_PGroup *ingroup, Bool subgroups);
	BaseObject   *(*GetVirtualObjects)(TP_MasterSystem *this_ptr,TP_PGroup *ingroup, Bool inRender, Bool subgroups, HierarchyHelp *hh);
	TP_PGroupInfo*(*GetGroupInfo)(TP_MasterSystem *this_ptr,TP_PGroup     *group);
	TP_PGroup*    (*GetGroupFromInfo)(TP_MasterSystem *this_ptr,TP_PGroupInfo *info );

	LONG       (*NumParticles)(TP_MasterSystem *this_ptr);
	Bool       (*Alive)(TP_MasterSystem *this_ptr,LONG pid);
	Bool       (*IsBorn)(TP_MasterSystem *this_ptr,LONG pid);
	Bool       (*IsDie)(TP_MasterSystem *this_ptr,LONG pid);
	Bool       (*EntersGroup)(TP_MasterSystem *this_ptr,LONG pid);
	TP_PGroup* (*Group)(TP_MasterSystem *this_ptr,LONG pid);
	Vector     (*Position)(TP_MasterSystem *this_ptr,LONG pid);
	Vector     (*Velocity)(TP_MasterSystem *this_ptr,LONG pid);
	Real       (*Mass)(TP_MasterSystem *this_ptr,LONG pid);
	TP_Spin    (*Spin)(TP_MasterSystem *this_ptr,LONG pid);
	Real       (*Size)(TP_MasterSystem *this_ptr,LONG pid);
	Vector     (*Scale)(TP_MasterSystem *this_ptr,LONG pid);
	BaseTime   (*Age)(TP_MasterSystem *this_ptr,LONG pid);
	BaseTime   (*Life)(TP_MasterSystem *this_ptr,LONG pid);
	Matrix     (*Alignment)(TP_MasterSystem *this_ptr,LONG pid);
	LONG       (*Randomseed)(TP_MasterSystem *this_ptr,LONG pid);
	TP_PShapePtr (*Shape)(TP_MasterSystem *this_ptr,LONG pid);
	Matrix     (*Transform)(TP_MasterSystem *this_ptr,LONG pid);
	UWORD      (*Flags)(TP_MasterSystem *this_ptr,LONG pid);
	Real       (*DTFactor)(TP_MasterSystem *this_ptr,LONG pid);

	void (*SetPosition)(TP_MasterSystem *this_ptr,LONG pid, const Vector &p);
	void (*SetVelocity)(TP_MasterSystem *this_ptr,LONG pid, const Vector &p);
	void (*SetMass)(TP_MasterSystem *this_ptr,LONG pid, Real mass);
	void (*SetSpin)(TP_MasterSystem *this_ptr,LONG pid, TP_Spin &spin);
	void (*SetAge)(TP_MasterSystem *this_ptr,LONG pid, const BaseTime &age);
	void (*SetLife)(TP_MasterSystem *this_ptr,LONG pid, const BaseTime &life);
	void (*SetGroup)(TP_MasterSystem *this_ptr,LONG pid, TP_PGroup *group);
	void (*SetSize)(TP_MasterSystem *this_ptr,LONG pid, Real size );
	void (*SetScale)(TP_MasterSystem *this_ptr,LONG pid, const Vector &scale);
	void (*SetAlignment)(TP_MasterSystem *this_ptr,LONG pid, const Matrix &align);
	void (*SetRandomseed)(TP_MasterSystem *this_ptr,LONG pid, LONG seed );
	void (*SetShape)(TP_MasterSystem *this_ptr,LONG pid, const TP_PShapePtr &shape, Bool deleteold);
	void (*SetCollision)(TP_MasterSystem *this_ptr,LONG pid, TP_Collision collision);
	void (*SetDTFactor)(TP_MasterSystem *this_ptr,LONG pid, Real dt    );


	//Particle Data Channels
  Bool			(*AddDataChannel)(TP_MasterSystem *this_ptr,GvDataID type, const String& str);
	Bool		(*RemoveDataChannel)(TP_MasterSystem *this_ptr,LONG chan);
	LONG		(*NumDataChannels)(TP_MasterSystem *this_ptr );
	GvDataID	(*DataChannelType)(TP_MasterSystem *this_ptr,LONG chan);
	String		(*DataChannelName)(TP_MasterSystem *this_ptr,LONG chan);
	LONG		(*DataChannelUniqueID)(TP_MasterSystem *this_ptr,LONG chan);
	LONG		(*DataChannelID)(TP_MasterSystem *this_ptr,LONG unique_id);

	Bool (*SetData)(TP_MasterSystem *this_ptr,LONG pid, LONG chan, void *data, GvValueID type);
	Bool (*GetData)(TP_MasterSystem *this_ptr,LONG pid, LONG chan, void *data, GvValueID type);
	Bool (*SetDataFromPort)(TP_MasterSystem *this_ptr,LONG pid, LONG chan, GvPort *p, GvRun *r);
	Bool (*SetDataToPort)(TP_MasterSystem *this_ptr,LONG pid, LONG chan, GvPort *p, GvRun *r);

	TP_DataChannelInfo *(*GetDataChannelInfo)(TP_MasterSystem *this_ptr,LONG chan);
	LONG                (*GetDataChannelFromInfo)(TP_MasterSystem *this_ptr,TP_DataChannelInfo *info);
	///

	//Call Backs
	void (*Reg_FreeParticle_CB)(TP_MasterSystem *this_ptr,TP_FreeParticle_CB *cb);
	void (*UReg_FreeParticle_CB)(TP_MasterSystem *this_ptr,TP_FreeParticle_CB *cb);
	void (*Reg_FreePShape_CB)(TP_MasterSystem *this_ptr,TP_FreePShape_CB   *cb);
	void (*UReg_FreePShape_CB)(TP_MasterSystem *this_ptr,TP_FreePShape_CB   *cb);
	//

	//Operator Link Table
	LONG            (*GetOperatorID)(TP_MasterSystem *this_ptr,GvNode *op);
	GvOperatorData *(*GetOperator)(TP_MasterSystem *this_ptr,LONG    id);

	ULONG            (*GetDirty)(TP_MasterSystem *this_ptr);
	void             (*SetDirty)(TP_MasterSystem *this_ptr);

	// Collision
	Bool (*CheckCollision)(TP_MasterSystem *this_ptr,TP_Collision collision, LONG pid, Real t, Vector &pos, Vector &vel, TP_Spin &spin, Real dt, Real &ct);

	//Particle Shape
	TP_PShapePtr (*GetShapeClone)(TP_MasterSystem *this_ptr,const TP_PShapePtr &shape , LONG pid, COPYFLAGS flags, AliasTrans *trn);
	TP_PShapePtr (*GetShape)(TP_MasterSystem *this_ptr,const TP_PShapePtr &shape , LONG pid, LONG owner_id);
	BaseObject* (*GetShapeVirtualObjects)(TP_MasterSystem *this_ptr,const TP_PShapePtr &shape , LONG pid, BaseDocument *doc, HierarchyHelp *hh);
	Real        (*GetShapeScale)(TP_MasterSystem *this_ptr,const TP_PShapePtr &shape , LONG pid);
	void        (*FreeShape)(TP_MasterSystem *this_ptr,TP_PShapePtr &shape, LONG pid);

	//ColliderCache
	GeColliderCache *(*ColliderCache)(TP_MasterSystem *this_ptr,LONG pid);

	LONG		(*GetParticleGroups)(TP_MasterSystem *this_ptr,TP_PGroup *ingroup, TP_PGroupArray *gtab, TP_GetPGroupMode mode, Bool subgroups);
};

struct C4D_TP_PGROUP
{
	LONG             (*GetLevel)(TP_PGroup *this_ptr);
	TP_ParticleNode *(*GetFirstNode)(TP_PGroup *this_ptr);
	TP_ParticleNode *(*GetLastNode )(TP_PGroup *this_ptr);
	LONG             (*NumParticles)(TP_PGroup *this_ptr);
	Bool             (*IsSubGroup  )(TP_PGroup *this_ptr,TP_PGroup *group);
	LONG             (*GetGroupID  )(TP_PGroup *this_ptr);
	const String     (*GetTitle)(TP_PGroup *this_ptr);
	void             (*SetTitle)(TP_PGroup *this_ptr,const String &title);
	void             (*SetViewType)(TP_PGroup *this_ptr,LONG type);
	LONG             (*GetViewType)(TP_PGroup *this_ptr);
	void             (*SetShowObjects)(TP_PGroup *this_ptr,Bool show);
	Bool             (*GetShowObjects)(TP_PGroup *this_ptr);
	void             (*SetColor)(TP_PGroup *this_ptr,Vector &col);
	Vector           (*GetColor)(TP_PGroup *this_ptr);
	Bool             (*EditSettings)(TP_PGroup *this_ptr);
	Bool             (*IsSelected)(TP_PGroup *this_ptr);
	Bool             (*IsOpened)(TP_PGroup *this_ptr);
	void             (*Select)(TP_PGroup *this_ptr,LONG mode);
	void             (*Open)(TP_PGroup *this_ptr,Bool onoff);
};

struct C4D_TP_PARTICLENODE
{
	LONG             (*GetParticleID)(TP_ParticleNode *this_ptr );
	TP_ParticleNode *(*GetNext      )(TP_ParticleNode *this_ptr );
	TP_ParticleNode *(*GetPrev      )(TP_ParticleNode *this_ptr );
};


struct C4DLibrary_TPOS : public C4DLibrary
{
	C4D_TP_MASTERSYSTEM   *MSYS;
	C4D_TP_PGROUP					*GROUP;
	C4D_TP_PARTICLENODE   *PART;
};

extern C4DLibrary_TPOS *TPOS;


//#define TpCall(fnc) (this->*TPOS->MSYS->fnc)
//#define PartCall(fnc) (this->*TPOS->PART->fnc)
//#define PGroupCall(fnc) (this->*TPOS->GROUP->fnc)
#define TpCall(fnc, ...)	TPOS->MSYS->fnc(this,##__VA_ARGS__)
#define PartCall(fnc, ...)	TPOS->PART->fnc(this,##__VA_ARGS__)
#define PGroupCall(fnc, ...)TPOS->GROUP->fnc(this,##__VA_ARGS__)



class TP_MasterSystem : public BaseSceneHook
{
private:
	TP_MasterSystem();
	~TP_MasterSystem();
public:
	LONG AllocParticle   (void)               { return TpCall(AllocParticle); }
	LONG AllocParticles  (LONG num, LONG *ids){ return TpCall(AllocParticles,num, ids); }
	void FreeParticle    (LONG pid)           { TpCall(FreeParticle,pid); }
	void FreeAllParticles(void)               { TpCall(FreeAllParticles); }

	TP_PGroup     *AllocParticleGroup		(void){ return TpCall(AllocParticleGroup); }
	void				   FreeParticleGroup			(TP_PGroup *&group){ TpCall(FreeParticleGroup,group); }
	Bool				   SetPGroupHierarchy		(TP_PGroup *parent , TP_PGroup *group, TP_InsertMode mode){ return TpCall(SetPGroupHierarchy,parent, group, mode); }
	LONG				   GetParticleGroups	    (TP_PGroup *ingroup, TP_PGroupArray *gtab, TP_GetPGroupMode mode, Bool subgroups = TRUE){ return TpCall(GetParticleGroups,ingroup, gtab, mode, subgroups); }
	LONG				   GetGroupParticleCount	(TP_PGroup *ingroup, Bool subgroups = TRUE){ return TpCall(GetGroupParticleCount,ingroup, subgroups); }
	BaseObject    *GetVirtualObjects     (TP_PGroup *ingroup, Bool inRender = TRUE, Bool subgroups = TRUE, HierarchyHelp *hh = NULL){ return TpCall(GetVirtualObjects,ingroup, inRender, subgroups, hh); }
	TP_PGroupInfo *GetGroupInfo    (TP_PGroup     *group){ return TpCall(GetGroupInfo,group);    }
	TP_PGroup     *GetGroupFromInfo(TP_PGroupInfo *info ){ return TpCall(GetGroupFromInfo,info); }


	LONG       NumParticles(void)    { return TpCall(NumParticles); }
	Bool       Alive       (LONG pid){ return TpCall(Alive,pid); }
	Bool       IsBorn      (LONG pid){ return TpCall(IsBorn,pid); }
	Bool       IsDie       (LONG pid){ return TpCall(IsDie,pid); }
	Bool       EntersGroup (LONG pid){ return TpCall(EntersGroup,pid); }
	TP_PGroup *Group       (LONG pid){ return TpCall(Group,pid); }
	Vector     Position    (LONG pid){ return TpCall(Position,pid); }
	Vector     Velocity    (LONG pid){ return TpCall(Velocity,pid); }
	Real       Mass        (LONG pid){ return TpCall(Mass,pid); }
	TP_Spin    Spin        (LONG pid){ return TpCall(Spin,pid); }
	Real       Size        (LONG pid){ return TpCall(Size,pid); }
	Vector     Scale       (LONG pid){ return TpCall(Scale,pid); }
	BaseTime   Age         (LONG pid){ return TpCall(Age,pid); }
	BaseTime   Life        (LONG pid){ return TpCall(Life,pid); }
	Matrix     Alignment   (LONG pid){ return TpCall(Alignment,pid); }
	LONG       Randomseed  (LONG pid){ return TpCall(Randomseed,pid); }
	TP_PShapePtr Shape      (LONG pid){ return TpCall(Shape,pid); }
	Matrix     Transform   (LONG pid){ return TpCall(Transform,pid); }
	UWORD      Flags       (LONG pid){ return TpCall(Flags,pid); }
	Real       DTFactor    (LONG pid){ return TpCall(DTFactor,pid); }



	void SetPosition	(LONG pid, const Vector &p){ TpCall(SetPosition,pid, p); }
	void SetVelocity	(LONG pid, const Vector &p){ TpCall(SetVelocity,pid, p); }
	void SetMass			(LONG pid, Real mass){ TpCall(SetMass,pid, mass); }
	void SetSpin			(LONG pid, TP_Spin &spin){ TpCall(SetSpin,pid, spin); }
	void SetAge				(LONG pid, const BaseTime &age){ TpCall(SetAge,pid, age); }
	void SetLife			(LONG pid, const BaseTime &life){ TpCall(SetLife,pid, life); }
	void SetGroup			(LONG pid, TP_PGroup *group){ TpCall(SetGroup,pid, group); }
	void SetSize			(LONG pid, Real size ){ TpCall(SetSize,pid, size); }
	void SetScale			(LONG pid, const Vector &scale){ TpCall(SetScale,pid, scale); }
	void SetAlignment	(LONG pid, const Matrix &align){ TpCall(SetAlignment,pid, align); }
	void SetRandomseed(LONG pid, LONG seed ){ TpCall(SetRandomseed,pid, seed); }
	void SetShape			(LONG pid, const TP_PShapePtr &shape, Bool deleteold = TRUE){ TpCall(SetShape,pid, shape, deleteold); }
	void SetCollision	(LONG pid, TP_Collision collision){ TpCall(SetCollision,pid, collision); }
	void SetDTFactor	(LONG pid, Real dt    ){ TpCall(SetDTFactor,pid, dt); }


	//Particle Data Channels
  Bool			AddDataChannel			(GvDataID type, const String& str){ return TpCall(AddDataChannel,type, str); }
	Bool			RemoveDataChannel		(LONG chan){ return TpCall(RemoveDataChannel,chan); }
	LONG			NumDataChannels			(void){ return TpCall(NumDataChannels); }
	GvDataID	DataChannelType			(LONG chan){ return TpCall(DataChannelType,chan); }
	String 		DataChannelName			(LONG chan){ return TpCall(DataChannelName,chan); }
	LONG			DataChannelUniqueID	(LONG chan){ return TpCall(DataChannelUniqueID,chan); }
	LONG			DataChannelID				(LONG unique_id){ return TpCall(DataChannelID,unique_id); }

	Bool SetData(LONG pid, LONG chan, void *data, GvValueID type) { return TpCall(SetData,pid, chan, data, type); }
	Bool GetData(LONG pid, LONG chan, void *data, GvValueID type) { return TpCall(GetData,pid, chan, data, type); }
	Bool SetDataFromPort(LONG pid, LONG chan, GvPort *p, GvRun *r){ return TpCall(SetDataFromPort,pid, chan, p, r); }
	Bool SetDataToPort  (LONG pid, LONG chan, GvPort *p, GvRun *r){ return TpCall(SetDataToPort,pid, chan, p, r);   }
	TP_DataChannelInfo *GetDataChannelInfo    (LONG chan)         { return TpCall(GetDataChannelInfo,chan);   }
	LONG                GetDataChannelFromInfo(TP_DataChannelInfo *info){ return TpCall(GetDataChannelFromInfo,info);   }
	///


	//Call Backs
	void Reg_FreeParticle_CB (TP_FreeParticle_CB *cb){ TpCall(Reg_FreeParticle_CB,cb);  }
	void UReg_FreeParticle_CB(TP_FreeParticle_CB *cb){ TpCall(UReg_FreeParticle_CB,cb); }
	void Reg_DeletePShape_CB (TP_FreePShape_CB   *cb){ TpCall(Reg_FreePShape_CB,cb);  }
	void UReg_DeletePShape_CB(TP_FreePShape_CB   *cb){ TpCall(UReg_FreePShape_CB,cb); }
	//

	//Operator Link Table
	LONG            GetOperatorID(GvNode *op){ return TpCall(GetOperatorID,op); }
	GvOperatorData *GetOperator  (LONG    id){ return TpCall(GetOperator,id);   }

	ULONG            GetDirty(void){ return TpCall(GetDirty); }
	void             SetDirty(void){ TpCall(SetDirty); }

	// Collision
	Bool CheckCollision(TP_Collision collision, LONG pid, Real t, Vector &pos, Vector &vel, TP_Spin &spin, Real dt, Real &ct){ return TpCall(CheckCollision,collision, pid, t, pos, vel, spin, dt, ct); }

	//Particle Shape
	TP_PShapePtr GetShapeClone        (const TP_PShapePtr &shape , LONG pid, COPYFLAGS flags, AliasTrans *trn){ return TpCall(GetShapeClone,shape, pid, flags, trn); }
	TP_PShapePtr GetShape             (const TP_PShapePtr &shape , LONG pid, LONG owner_id){ return TpCall(GetShape,shape, pid, owner_id); }
	BaseObject* GetShapeVirtualObjects(const TP_PShapePtr &shape , LONG pid, BaseDocument *doc, HierarchyHelp *hh){ return TpCall(GetShapeVirtualObjects,shape, pid, doc, hh); }
	Real        GetShapeScale         (const TP_PShapePtr &shape , LONG pid){ return TpCall(GetShapeScale,shape, pid); }
	void        FreeShape             (TP_PShapePtr &shape, LONG pid){ TpCall(FreeShape,shape, pid); }

	// ColliderCache
	GeColliderCache* ColliderCache(LONG pid){ return TpCall(ColliderCache,pid); }
};

//#define PartCall(fnc) (this->*TPOS->PART->fnc)


class TP_ParticleNode
{
public:
	LONG             GetParticleID(void){ return PartCall(GetParticleID); }
	TP_ParticleNode *GetNext      (void){ return PartCall(GetNext);       }
	TP_ParticleNode *GetPrev      (void){ return PartCall(GetPrev);       }
};


//#define PGroupCall(fnc) (this->*TPOS->GROUP->fnc)

class TP_PGroup : public BaseList2D
{
	private:
		TP_PGroup();
		~TP_PGroup();
	public:
		LONG             GetLevel(void)                  { return PGroupCall(GetLevel);        }
		TP_ParticleNode *GetFirstNode(void)              { return PGroupCall(GetFirstNode);    }
		TP_ParticleNode *GetLastNode(void)	             { return PGroupCall(GetLastNode);     }
		LONG             NumParticles(void)              { return PGroupCall(NumParticles);    }
		Bool             IsSubGroup(TP_PGroup *group)    { return PGroupCall(IsSubGroup,group); }
		LONG             GetGroupID(void)                { return PGroupCall(GetGroupID);      }
		const String     GetTitle(void)                  { return PGroupCall(GetTitle);        }
		void             SetTitle(const String &title)   { PGroupCall(SetTitle,title);          }
		void             SetViewType(LONG type)          { PGroupCall(SetViewType,type);        }
		LONG             GetViewType(void)               { return PGroupCall(GetViewType);     }
		void             SetShowObjects(Bool show)       { PGroupCall(SetShowObjects,show);     }
		Bool             GetShowObjects(void)            { return PGroupCall(GetShowObjects);  }
		void             SetColor(Vector &col)           { PGroupCall(SetColor,col);            }
		Vector           GetColor(void)                  { return PGroupCall(GetColor);        }
		Bool             EditSettings(void)              { return PGroupCall(EditSettings);    }
		Bool             IsSelected(void)								 { return PGroupCall(IsSelected);      }
		Bool             IsOpened(void)									 { return PGroupCall(IsOpened);        }
		void             Select(LONG mode )							 { PGroupCall(Select,mode);             }
		void             Open(Bool onoff)								 { PGroupCall(Open,onoff);              }
};

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

inline Bool InitThinkingParticles(void)
{
	return NULL != CheckLib(ID_THINKINGPARTICLES, 0, (C4DLibrary**)&TPOS);
}

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

#endif //__C4D_PARTICLES_H

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