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

#include "c4d_baseeffectorplugin.h"

EffectorDataLib	*efflib_cache;
MoDataLib				*modlib_cache;


static EffectorDataLib *CheckEffectorLib(LONG offset)
{
	return (EffectorDataLib*)CheckLib(BASEEFFECTORLIB_ID, offset, (C4DLibrary**)&efflib_cache);
}

static MoDataLib *CheckMoDataLib(LONG offset)
{
	return (MoDataLib*)CheckLib(MODATALIB_ID, offset, (C4DLibrary**)&modlib_cache);
}

Bool EffectorData::InitEffector(GeListNode *node) { return TRUE; }
void EffectorData::FreeEffector(GeListNode *node) { }
Bool EffectorData::AddToExecution(BaseObject *op, PriorityList *list)	{ list->Add(op, EXECUTIONPRIORITY_EXPRESSION, EXECUTIONFLAGS_0); return TRUE; }
Bool EffectorData::IsInstanceOf(const GeListNode *node,LONG type) const { return type==Obaseeffector; }

Bool EffectorData::Init(GeListNode *node)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Init));
	if (!elib || !elib->Effector_Init) return FALSE;

	if (!elib->Effector_Init(node)) return FALSE;

	return InitEffector(node);
}

void EffectorData::Free(GeListNode *node)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Free));
	if (!elib || !elib->Effector_Free) return;

	elib->Effector_Free(node);

	FreeEffector(node);
}

LONG EffectorData::GetHandleCount(BaseObject *op)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetHandleCount));
	if (!elib || !elib->Effector_GetHandleCount) return 0;

	return elib->Effector_GetHandleCount(op);
}

void EffectorData::GetHandle(BaseObject *op, LONG i, HandleInfo &info)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetHandle));
	if (!elib || !elib->Effector_GetHandle) return;

	elib->Effector_GetHandle(op,i,info);
}

void EffectorData::SetHandle(BaseObject *op, LONG i, Vector p, const HandleInfo &info)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_SetHandle));
	if (!elib || !elib->Effector_SetHandle) return;

	elib->Effector_SetHandle(op,i,p,info);
}

Bool EffectorData::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetDDescription));
	if (!elib || !elib->Effector_GetDDescription) return FALSE;

	Bool res=elib->Effector_GetDDescription(node,description,flags);

	if (!res) return FALSE;

	return TRUE;
}

EXECUTIONRESULT EffectorData::Execute(BaseObject *op, BaseDocument *doc, BaseThread *bt, LONG priority, EXECUTIONFLAGS flags)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Execute));
	if (!elib || !elib->Effector_Execute) return EXECUTIONRESULT_OUTOFMEMORY;

	return elib->Effector_Execute(op,doc,bt,priority,flags);
}

Bool EffectorData::ExecuteEffector(BaseObject *op, BaseDocument *doc, BaseObject *gen, MoData *md, Real strength, BaseThread *thread)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_ExecuteEffector));
	if (!elib || !elib->Effector_ExecuteEffector) return FALSE;

	return elib->Effector_ExecuteEffector(op,doc,gen,md,strength,thread);
}

void EffectorData::ModifyPoints(BaseObject *op, BaseObject *gen, BaseDocument *doc, EffectorDataStruct *data, MoData *md, BaseThread *thread)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_ModifyPoints));
	if (!elib || !elib->Effector_ModifyPoints) return;

	elib->Effector_ModifyPoints(op,gen,doc,data,md,thread);
}

Bool EffectorData::ModifyObject(BaseObject *mod, BaseDocument *doc, BaseObject *op, const Matrix &op_mg, const Matrix &mod_mg, Real lod, LONG flags, BaseThread *thread)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_ModifyObject));
	if (!elib || !elib->Effector_ModifyObject) return FALSE;

	return elib->Effector_ModifyObject(mod,doc,op,op_mg,mod_mg,lod,flags,thread);
}

Bool EffectorData::Message(GeListNode *node, LONG type, void *t_data)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Message));
	if (!elib || !elib->Effector_Message) return FALSE;

	Bool res=elib->Effector_Message(node,type,t_data);

	if (!res) return FALSE;

	return ObjectData::Message(node,type,t_data);
}

void EffectorData::GetDimension(BaseObject *op, Vector *mp, Vector *rad)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetDimension));
	if (!elib || !elib->Effector_GetDimension) return;

	elib->Effector_GetDimension(op,mp,rad);
}

DRAWRESULT EffectorData::Draw(BaseObject *op, DRAWPASS type, BaseDraw *bd, BaseDrawHelp *bh)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Draw));
	if (!elib || !elib->Effector_Draw)
		return DRAWRESULT_ERROR;

	Bool res=elib->Effector_Draw(op,type,bd,bh);

	if (!res)
		return DRAWRESULT_ERROR;

	return ObjectData::Draw(op,type,bd,bh);
}

Bool EffectorData::CopyTo(NodeData *dest,GeListNode *snode,GeListNode *dnode,COPYFLAGS flags,AliasTrans *trn)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_CopyTo));
	if (!elib || !elib->Effector_CopyTo) return FALSE;

	if (!elib->Effector_CopyTo(dest,snode,dnode,flags,trn)) return FALSE;

	return ObjectData::CopyTo(dest,snode,dnode,flags,trn);
}

void EffectorData::AddEffectorDependence(BaseObject *op)
{
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_AddEffectorDependence));
	if (!elib || !elib->Effector_AddEffectorDependence) return;

	elib->Effector_AddEffectorDependence(this->Get(),op);
}

EffectorDataStruct* EffectorData::GetEffectorData(void)
{ 
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetEffectorData));
	if (!elib || !elib->Effector_GetEffectorData) return NULL;

	return elib->Effector_GetEffectorData(this->Get());
}

C4D_Falloff* EffectorData::GetFalloff(void) 
{ 
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_GetFalloff));
	if (!elib || !elib->Effector_GetFalloff) return NULL;

	return elib->Effector_GetFalloff(this->Get());
}

void EffectorData::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
void EffectorData::CalcPointValue(BaseObject	*op, BaseObject	*gen, BaseDocument *doc, EffectorDataStruct *data, LONG index, MoData *md, const Vector &globalpos, Real fall_weight) 
{ 
}

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

LONG EffectorData::GetEffectorFlags(void) 
{	
	return EFFECTORFLAGS_HASFALLOFF; 
}

Bool EffectorData::ModifyDDescription(GeListNode *node, Description *description, AtomArray *ar) 
{ 
	return TRUE; 
}

void EffectorData::InitPoints(BaseObject *op, BaseObject *gen, BaseDocument *doc, EffectorDataStruct *data, MoData *md, BaseThread *thread) 
{ 
}

void EffectorData::FreePoints(void)	
{ 
}


//---------------------------------------
//MoData

ULONG MoData::GetDirty(DIRTYFLAGS mask)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetDirty));
	if (!mlib || !mlib->GetDirty) return 0;

	return (((iMoData*)this)->*(mlib->GetDirty))(mask);
}

void MoData::SetDirty(DIRTYFLAGS mask)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetDirty));
	if (!mlib || !mlib->SetDirty) return;

	(((iMoData*)this)->*(mlib->SetDirty))(mask);
}

Bool MoData::SetWithEx(const MoDataEx &md)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetWithEx));
	if (!mlib || !mlib->SetWithEx) return FALSE;

	return (((iMoData*)this)->*(mlib->SetWithEx))(md);
}

void MoData::Clear(Bool reset)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, Clear));
	if (!mlib || !mlib->Clear) return;

	(((iMoData*)this)->*(mlib->Clear))(reset);
}

Bool MoData::Read(HyperFile *hf)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, Read));
	if (!mlib || !mlib->Read) return FALSE;

	return (((iMoData*)this)->*(mlib->Read))(hf);
}

Bool MoData::Write(HyperFile *hf)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, Write));
	if (!mlib || !mlib->Write) return FALSE;

	return (((iMoData*)this)->*(mlib->Write))(hf);
}

VLONG MoData::GetMemorySize(void)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetMemorySize));
	if (!mlib || !mlib->GetMemorySize) return 0;

	return (((iMoData*)this)->*(mlib->GetMemorySize))();
}

Bool MoData::SetCount(VLONG cnt)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetCount));
	if (!mlib || !mlib->SetCount) return FALSE;

	return (((iMoData*)this)->*(mlib->SetCount))(cnt);
}

VLONG MoData::GetCount(void)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetCount));
	if (!mlib || !mlib->GetCount) return 0;

	return (((iMoData*)this)->*(mlib->GetCount))();
}

LONG MoData::GetArrayCount(void)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArrayCount));
	if (!mlib || !mlib->GetArrayCount) return 0;

	return (((iMoData*)this)->*(mlib->GetArrayCount))();
}

DescID MoData::GetArrayDescID(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArrayDescID));
	if (!mlib || !mlib->GetArrayDescID) return DescID();

	return (((iMoData*)this)->*(mlib->GetArrayDescID))(index);
}

LONG MoData::GetArrayID(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArrayID));
	if (!mlib || !mlib->GetArrayID) return 0;

	return (((iMoData*)this)->*(mlib->GetArrayID))(index);
}

LONG MoData::GetArrayIndexType(LONG index)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArrayIndexType));
	if (!mlib || !mlib->GetArrayIndexType) return 0;

	return (((iMoData*)this)->*(mlib->GetArrayIndexType))(index);
}

LONG MoData::GetArrayType(LONG id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArrayType));
	if (!mlib || !mlib->GetArrayType) return 0;

	return (((iMoData*)this)->*(mlib->GetArrayType))(id);
}

VLONG MoData::GetArrayIndex(const DescID &id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArrayIndex1));
	if (!mlib || !mlib->GetArrayIndex1) return 0;

	return (((iMoData*)this)->*(mlib->GetArrayIndex1))(id);
}

VLONG MoData::GetArrayIndex(LONG id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArrayIndex2));
	if (!mlib || !mlib->GetArrayIndex2) return 0;

	return (((iMoData*)this)->*(mlib->GetArrayIndex2))(id);
}

BaseContainer* MoData::GetDataInstance(const DescID &id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetDataInstance1));
	if (!mlib || !mlib->GetDataInstance1) return NULL;

	return (((iMoData*)this)->*(mlib->GetDataInstance1))(id);
}

BaseContainer* MoData::GetDataInstance(LONG id /*= NOTOK*/)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetDataInstance2));
	if (!mlib || !mlib->GetDataInstance2) return NULL;

	return (((iMoData*)this)->*(mlib->GetDataInstance2))(id);
}

BaseContainer* MoData::GetDataIndexInstance(LONG index)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetDataIndexInstance));
	if (!mlib || !mlib->GetDataIndexInstance) return NULL;

	return (((iMoData*)this)->*(mlib->GetDataIndexInstance))(index);
}

BaseContainer MoData::GetData(LONG id /*= NOTOK*/)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetData));
	if (!mlib || !mlib->GetData) return BaseContainer();

	return (((iMoData*)this)->*(mlib->GetData))(id);
}

void MoData::SetData(const BaseContainer &bc, LONG id /*= NOTOK*/)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetData));
	if (!mlib || !mlib->SetData) return;

	(((iMoData*)this)->*(mlib->SetData))(bc, id);
}

static AutoLock autolock_dummy;

AutoLock &MoData::GetAutoLock(void)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetAutoLock));
	if (!mlib || !mlib->GetAutoLock) return autolock_dummy;

	return (((iMoData*)this)->*(mlib->GetAutoLock))();
}

LONG MoData::AddArray(const DescID &id, String name, LONG default_flags)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, AddArray1));
	if (!mlib || !mlib->AddArray1) return 0;

	return (((iMoData*)this)->*(mlib->AddArray1))(id, name, default_flags);
}

LONG MoData::AddArray(LONG id, LONG type, String name, LONG default_flags)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, AddArray2));
	if (!mlib || !mlib->AddArray2) return 0;

	return (((iMoData*)this)->*(mlib->AddArray2))(id, type, name, default_flags);
}

Bool MoData::RemoveArray(const DescID &id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, RemoveArray1));
	if (!mlib || !mlib->RemoveArray1) return FALSE;

	return (((iMoData*)this)->*(mlib->RemoveArray1))(id);
}

Bool MoData::RemoveArray(LONG id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, RemoveArray2));
	if (!mlib || !mlib->RemoveArray2) return FALSE;

	return (((iMoData*)this)->*(mlib->RemoveArray2))(id);
}

LONG MoData::GetFlags(const DescID &id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetFlags1));
	if (!mlib || !mlib->GetFlags1) return 0;

	return (((iMoData*)this)->*(mlib->GetFlags1))(id);
}

LONG MoData::GetFlags(LONG id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetFlags2));
	if (!mlib || !mlib->GetFlags2) return 0;

	return (((iMoData*)this)->*(mlib->GetFlags2))(id);
}

LONG MoData::GetIndexFlags(LONG index)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetIndexFlags));
	if (!mlib || !mlib->GetIndexFlags) return 0;

	return (((iMoData*)this)->*(mlib->GetIndexFlags))(index);
}

void MoData::SetFlags(const DescID &id, LONG flags)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetFlags1));
	if (!mlib || !mlib->SetFlags1) return;

	(((iMoData*)this)->*(mlib->SetFlags1))(id, flags);
}

void MoData::SetFlags(LONG id, LONG flags)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetFlags2));
	if (!mlib || !mlib->SetFlags2) return;

	(((iMoData*)this)->*(mlib->SetFlags2))(id, flags);
}

void MoData::SetIndexFlags(LONG index, LONG flags)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetIndexFlags));
	if (!mlib || !mlib->SetIndexFlags) return;

	(((iMoData*)this)->*(mlib->SetIndexFlags))(index, flags);
}

void MoData::SetFlag(const DescID &id, LONG flag)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetFlag1));
	if (!mlib || !mlib->SetFlag1) return;

	(((iMoData*)this)->*(mlib->SetFlag1))(id, flag);
}

void MoData::SetFlag(LONG id, LONG flag)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetFlag2));
	if (!mlib || !mlib->SetFlag2) return;

	(((iMoData*)this)->*(mlib->SetFlag2))(id, flag);
}

void MoData::SetIndexFlag(LONG index, LONG flag)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetIndexFlag));
	if (!mlib || !mlib->SetIndexFlag) return;

	(((iMoData*)this)->*(mlib->SetIndexFlag))(index, flag);
}

void MoData::DelFlag(const DescID &id, LONG flag)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, DelFlag1));
	if (!mlib || !mlib->DelFlag1) return;

	(((iMoData*)this)->*(mlib->DelFlag1))(id, flag);
}

void MoData::DelFlag(LONG id, LONG flag)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, DelFlag2));
	if (!mlib || !mlib->DelFlag2) return;

	(((iMoData*)this)->*(mlib->DelFlag2))(id, flag);
}

void MoData::DelIndexFlag(LONG index, LONG flag)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, DelIndexFlag));
	if (!mlib || !mlib->DelIndexFlag) return;

	(((iMoData*)this)->*(mlib->DelIndexFlag))(index, flag);
}

void MoData::SetName(const DescID &id, const String &name)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetName1));
	if (!mlib || !mlib->SetName1) return;

	(((iMoData*)this)->*(mlib->SetName1))(id, name);
}

void MoData::SetName(LONG id, const String &name)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetName2));
	if (!mlib || !mlib->SetName2) return;

	(((iMoData*)this)->*(mlib->SetName2))(id, name);
}

void MoData::SetIndexName(LONG index, const String &name)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetIndexName));
	if (!mlib || !mlib->SetIndexName) return;

	(((iMoData*)this)->*(mlib->SetIndexName))(index, name);
}

String MoData::GetName(const DescID &id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetName1));
	if (!mlib || !mlib->GetName1) return "";

	return (((iMoData*)this)->*(mlib->GetName1))(id);
}

String MoData::GetName(LONG id)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetName2));
	if (!mlib || !mlib->GetName2) return "";

	return (((iMoData*)this)->*(mlib->GetName2))(id);
}

String MoData::GetIndexName(LONG index)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetIndexName));
	if (!mlib || !mlib->GetIndexName) return "";

	return (((iMoData*)this)->*(mlib->GetIndexName))(index);
}

void* MoData::GetArray(const DescID &id) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArray1));
	if (!mlib || !mlib->GetArray1) return NULL;

	return (((iMoData*)this)->*(mlib->GetArray1))(id);
}

MDArray<CHAR> MoData::GetCharArray(const DescID &id, CHAR default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetCharArray1));
	if (!mlib || !mlib->GetCharArray1) return MDArray<CHAR>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetCharArray1))(id, default_value);
}

MDArray<UCHAR> MoData::GetUCharArray(const DescID &id, UCHAR default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetUCharArray1));
	if (!mlib || !mlib->GetUCharArray1) return MDArray<UCHAR>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetUCharArray1))(id, default_value);
}

MDArray<LONG> MoData::GetLongArray(const DescID &id, LONG default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetLongArray1));
	if (!mlib || !mlib->GetLongArray1) return MDArray<LONG>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetLongArray1))(id, default_value);
}

MDArray<ULONG> MoData::GetULongArray(const DescID &id, ULONG default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetULongArray1));
	if (!mlib || !mlib->GetULongArray1) return MDArray<ULONG>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetULongArray1))(id, default_value);
}

MDArray<Bool> MoData::GetBoolArray(const DescID &id, Bool default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetBoolArray1));
	if (!mlib || !mlib->GetBoolArray1) return MDArray<Bool>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetBoolArray1))(id, default_value);
}

MDArray<LLONG> MoData::GetLLongArray(const DescID &id, LLONG default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetLLongArray1));
	if (!mlib || !mlib->GetLLongArray1) return MDArray<LLONG>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetLLongArray1))(id, default_value);
}

MDArray<Real> MoData::GetRealArray(const DescID &id, Real default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetRealArray1));
	if (!mlib || !mlib->GetRealArray1) return MDArray<Real>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetRealArray1))(id, default_value);
}

MDArray<Matrix> MoData::GetMatrixArray(const DescID &id, Matrix default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetMatrixArray1));
	if (!mlib || !mlib->GetMatrixArray1) return MDArray<Matrix>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetMatrixArray1))(id, default_value);
}

MDArray<Vector> MoData::GetVectorArray(const DescID &id, Vector default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetVectorArray1));
	if (!mlib || !mlib->GetVectorArray1) return MDArray<Vector>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetVectorArray1))(id, default_value);
}

void* MoData::GetArray(LONG id, MD_TYPE type) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetArray2));
	if (!mlib || !mlib->GetArray2) return NULL;

	return (((iMoData*)this)->*(mlib->GetArray2))(id, type);
}

MDArray<CHAR> MoData::GetCharArray(LONG id, CHAR default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetCharArray2));
	if (!mlib || !mlib->GetCharArray2) return MDArray<CHAR>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetCharArray2))(id, default_value);
}

MDArray<UCHAR> MoData::GetUCharArray(LONG id, UCHAR default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetUCharArray2));
	if (!mlib || !mlib->GetUCharArray2) return MDArray<UCHAR>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetUCharArray2))(id, default_value);
}

MDArray<LONG> MoData::GetLongArray(LONG id, LONG default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetLongArray2));
	if (!mlib || !mlib->GetLongArray2) return MDArray<LONG>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetLongArray2))(id, default_value);
}

MDArray<ULONG> MoData::GetULongArray(LONG id, ULONG default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetULongArray2));
	if (!mlib || !mlib->GetULongArray2) return MDArray<ULONG>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetULongArray2))(id, default_value);
}

MDArray<Bool> MoData::GetBoolArray(LONG id, Bool default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetBoolArray2));
	if (!mlib || !mlib->GetBoolArray2) return MDArray<Bool>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetBoolArray2))(id, default_value);
}

MDArray<LLONG> MoData::GetLLongArray(LONG id, LLONG default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetLLongArray2));
	if (!mlib || !mlib->GetLLongArray2) return MDArray<LLONG>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetLLongArray2))(id, default_value);
}

MDArray<Real> MoData::GetRealArray(LONG id, Real default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetRealArray2));
	if (!mlib || !mlib->GetRealArray2) return MDArray<Real>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetRealArray2))(id, default_value);
}

MDArray<Matrix> MoData::GetMatrixArray(LONG id, Matrix default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetMatrixArray2));
	if (!mlib || !mlib->GetMatrixArray2) return MDArray<Matrix>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetMatrixArray2))(id, default_value);
}

MDArray<Vector> MoData::GetVectorArray(LONG id, Vector default_value) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetVectorArray2));
	if (!mlib || !mlib->GetVectorArray2) return MDArray<Vector>(NULL, 0, default_value);

	return (((iMoData*)this)->*(mlib->GetVectorArray2))(id, default_value);
}

void* MoData::GetIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetIndexArray));
	if (!mlib || !mlib->GetIndexArray) return NULL;

	return (((iMoData*)this)->*(mlib->GetIndexArray))(index);
}

MDArray<CHAR> MoData::GetCharIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetCharIndexArray));
	if (!mlib || !mlib->GetCharIndexArray) return MDArray<CHAR>(NULL, 0, CHAR(0));

	return (((iMoData*)this)->*(mlib->GetCharIndexArray))(index);
}

MDArray<UCHAR> MoData::GetUCharIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetUCharIndexArray));
	if (!mlib || !mlib->GetUCharIndexArray) return MDArray<UCHAR>(NULL, 0, UCHAR(0));

	return (((iMoData*)this)->*(mlib->GetUCharIndexArray))(index);
}

MDArray<LONG> MoData::GetLongIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetLongIndexArray));
	if (!mlib || !mlib->GetLongIndexArray) return MDArray<LONG>(NULL, 0, LONG(0));

	return (((iMoData*)this)->*(mlib->GetLongIndexArray))(index);
}

MDArray<ULONG> MoData::GetULongIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetULongIndexArray));
	if (!mlib || !mlib->GetULongIndexArray) return MDArray<ULONG>(NULL, 0, ULONG(0));

	return (((iMoData*)this)->*(mlib->GetULongIndexArray))(index);
}

MDArray<Bool> MoData::GetBoolIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetBoolIndexArray));
	if (!mlib || !mlib->GetBoolIndexArray) return MDArray<Bool>(NULL, 0, FALSE);

	return (((iMoData*)this)->*(mlib->GetBoolIndexArray))(index);
}

MDArray<LLONG> MoData::GetLLongIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetLLongIndexArray));
	if (!mlib || !mlib->GetLLongIndexArray) return MDArray<LLONG>(NULL, 0, LLONG(0));

	return (((iMoData*)this)->*(mlib->GetLLongIndexArray))(index);
}

MDArray<Real> MoData::GetRealIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetRealIndexArray));
	if (!mlib || !mlib->GetRealIndexArray) return MDArray<Real>(NULL, 0, 0.0);

	return (((iMoData*)this)->*(mlib->GetRealIndexArray))(index);
}

MDArray<Matrix> MoData::GetMatrixIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetMatrixIndexArray));
	if (!mlib || !mlib->GetMatrixIndexArray) return MDArray<Matrix>(NULL, 0, Matrix());

	return (((iMoData*)this)->*(mlib->GetMatrixIndexArray))(index);
}

MDArray<Vector> MoData::GetVectorIndexArray(LONG index) const
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetVectorIndexArray));
	if (!mlib || !mlib->GetVectorIndexArray) return MDArray<Vector>(NULL, 0, Vector(0.0));

	return (((iMoData*)this)->*(mlib->GetVectorIndexArray))(index);
}

Bool MoData::CopyTo(MoData *dest, Bool merge_data, VLONG max_count)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, CopyTo));
	if (!mlib || !mlib->CopyTo) return FALSE;

	iMoData *d = (iMoData*)dest;

	return (((iMoData*)this)->*(mlib->CopyTo))(d, merge_data, max_count);
}

Bool MoData::MergeData(MoData *source, Real percent)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, MergeData));
	if (!mlib || !mlib->MergeData) return FALSE;

	iMoData *s =(iMoData*)source;
	return (((iMoData*)this)->*(mlib->MergeData))(s, percent);
}

void MoData::Flush(void)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, Flush));
	if (!mlib || !mlib->Flush) return;

	(((iMoData*)this)->*(mlib->Flush))();
}

void MoData::SetOffset(VLONG offset)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetOffset));
	if (!mlib || !mlib->SetOffset) return;

	(((iMoData*)this)->*(mlib->SetOffset))(offset);
}

void MoData::SetLimit(VLONG limit)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, SetLimit));
	if (!mlib || !mlib->SetLimit) return;

	(((iMoData*)this)->*(mlib->SetLimit))(limit);
}

MoData* MoData::Alloc(void)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, Alloc));
	if (!mlib || !mlib->Alloc) return NULL;

	return (MoData*)mlib->Alloc();
}

void MoData::Free(MoData *&d)
{
	MoDataLib *mlib = CheckMoDataLib(LIBOFFSET(MoDataLib, GetCount));
	if (!mlib || !mlib->GetCount) return;

	iMoData *tmp = (iMoData*)d;
	mlib->Free(tmp);
	d = NULL;
}


//---------------------------------------
//Registration

static void FillEffectorPlugin(EFFECTORPLUGIN *np, DataAllocator *npalloc, LONG info, LONG disklevel, BaseBitmap *icon)
{
	FillNodePlugin(np,info,npalloc,icon,disklevel,NULL);

	np->command_icon					= icon;
	np->GetDimension					= &ObjectData::GetDimension;
	np->Draw									= &ObjectData::Draw;
	np->DetectHandle					= &ObjectData::DetectHandle;
	np->MoveHandle						= &ObjectData::MoveHandle; 
	np->Execute								= &ObjectData::Execute;
	np->AddToExecution				= &ObjectData::AddToExecution;
	np->GetModelingAxis				= &ObjectData::GetModelingAxis;

	np->GetEffectorData				= &EffectorData::GetEffectorData;
	np->GetFalloff						= &EffectorData::GetFalloff;
	np->AddEffectorDependence = &EffectorData::AddEffectorDependence;
	np->GetEffectorFlags			= &EffectorData::GetEffectorFlags;
	np->ModifyDDescription		= &EffectorData::ModifyDDescription;
	np->ExecuteEffector				= &EffectorData::ExecuteEffector;
	np->InitPoints						= &EffectorData::InitPoints;
	np->ModifyPoints					= &EffectorData::ModifyPoints;
	np->FreePoints						= &EffectorData::FreePoints;
	np->CalcPlacebo						= &EffectorData::CalcPlacebo;
	np->CalcPointValue				= &EffectorData::CalcPointValue;
	np->CalcPointColor				= &EffectorData::CalcPointColor;

	np->InitEffector					= &EffectorData::InitEffector;
	np->FreeEffector					= &EffectorData::FreeEffector;
}

Bool RegisterEffectorPlugin(LONG id, const String &str, LONG objectinfo, DataAllocator *npalloc, const String &description, BaseBitmap *icon, LONG disklevel)
{
	// only allow registration if MoGfx is present
	EffectorDataLib *elib = CheckEffectorLib(LIBOFFSET(EffectorDataLib, Effector_Init));
	if (!elib) return FALSE;	

	if (description.Content() && !RegisterDescription(id,description)) return FALSE;

	objectinfo |= OBJECT_MODIFIER;
	objectinfo |= OBJECT_CAMERADEPENDENT;

	EFFECTORPLUGIN np;
	ClearMem(&np,sizeof(np));
	FillEffectorPlugin(&np,npalloc,objectinfo,disklevel,icon);

	np.CheckDirty		= &ObjectData::CheckDirty;
	np.ModifyObject	= &ObjectData::ModifyObject;

	if (objectinfo&OBJECT_PARTICLEMODIFIER)
		np.ModifyParticles = &ObjectData::ModifyParticles;
	
	if (objectinfo&OBJECT_ISSPLINE) 
		np.GetContour = &ObjectData::GetContour;
	
	if (objectinfo&OBJECT_GENERATOR) 
		np.GetVirtualObjects = &ObjectData::GetVirtualObjects;

	return GeRegisterPlugin(PLUGINTYPE_OBJECT,id,str,&np,sizeof(np));
}
