**THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED**

*On 21/05/2007 at 23:59, ***xxxxxxxx** wrote:

Maxon devs finally showed us how to do it:

```
Here's an example of the falloff in action in a normal object, taken from the morphdeformer object.
//Header file
#include "c4d.h"
#include "c4d_falloffdata.h"
class MorphDeformer : public ObjectData
{
private:
AutoAlloc<C4D_Falloff>falloff;
public:
virtual Bool Init(GeListNode *node);
virtual Bool Draw(PluginObject *op, LONG drawpass, BaseDraw *bd, BaseDrawHelp *bh);
virtual LONG GetHandleCount(PluginObject *op);
virtual Vector GetHandle(PluginObject *op, LONG i);
virtual void SetHandle(PluginObject *op, LONG i, Vector p);
virtual Bool GetDDescription(GeListNode *node,Description *description,LONG &flags;);
virtual LONG Execute(PluginObject *op,BaseDocument *doc,BaseThread *bt,LONG priority,LONG flags);
virtual Bool AddToExecution(PluginObject *op, PriorityList *list) { list->Add(op, EXECUTION_GENERATOR, -100); return TRUE; }
virtual Bool CopyTo(NodeData *dest, GeListNode *snode, GeListNode *dnode, LONG flags, AliasTrans *trn);
virtual Bool ModifyObject(PluginObject *mod, BaseDocument *doc, BaseObject *op, const Matrix &op;_mg, const Matrix &mod;_mg, Real lod, LONG flags, BaseThread *thread);
static NodeData* Alloc(void) { return gNew MorphDeformer; }
};
//C++ file
#include "morphdeformer.h"
#include "ge_dynamicarray.h"
Bool MorphDeformer::Init(GeListNode *node)
{
if (!node || !falloff) return FALSE;
PluginObject *op = (PluginObject* )node;
BaseContainer *bc = op->GetDataInstance();
if (!bc) return FALSE;
bc->SetReal(MORPHDEFORMER_STRENGTH, 1.0f);
if (!falloff->InitFalloff(bc,NULL,op)) return FALSE;
return TRUE;
}
Bool MorphDeformer::Draw(PluginObject *op, LONG drawpass, BaseDraw *bd, BaseDrawHelp *bh)
{
if (!op->GetDeformMode()) return TRUE;
BaseContainer *bc = op->GetDataInstance();
if (!bc) return FALSE;
if (falloff) falloff->Draw(bd, bh, drawpass, bc);
return ObjectData::Draw(op, drawpass, bd, bh);
}
LONG MorphDeformer::GetHandleCount(PluginObject *op)
{
BaseContainer *bc = op->GetDataInstance();
if (!bc) return 0;
if (falloff) return falloff->GetHandleCount(bc);
return 0;
}
Vector MorphDeformer::GetHandle(PluginObject *op, LONG i)
{
BaseContainer *bc = op->GetDataInstance();
if (!bc) return 0.0;
if (falloff) return falloff->GetHandle(i,bc);
return 0.0;
}
void MorphDeformer::SetHandle(PluginObject *op, LONG i, Vector p)
{
BaseContainer *bc = op->GetDataInstance();
if (!bc) return;
if (falloff) falloff->SetHandle(i,p,bc);
}
LONG MorphDeformer::Execute(PluginObject *op,BaseDocument *doc,BaseThread *bt,LONG priority,LONG flags)
{
BaseContainer *bc = op->GetDataInstance();
if (!bc) return FALSE;
if (falloff)
if (!falloff->InitFalloff(bc,doc,op)) return EXECUTION_RESULT_MEMORYERROR;
return EXECUTION_RESULT_OK;
}
Bool MorphDeformer::GetDDescription(GeListNode *node,Description *description,LONG &flags;)
{
BaseObject *op = (BaseObject* ) node;
if (!op) return FALSE;
BaseContainer *bc = op->GetDataInstance();
if (!bc) return FALSE;
if (!description->LoadDescription(op->GetType())) return FALSE;
//---------------------------------
//Add the falloff interface
if (falloff)
{
if (!falloff->SetMode(bc->GetLong(FALLOFF_MODE,FALLOFF_MODE_INFINITE),bc)) return FALSE; //The falloff parameters have to have been setup before it can be added to the description, this like makes sure of that
if (!falloff->AddFalloffToDescription(description,bc)) return FALSE;
}
flags |= DESCFLAGS_DESC_LOADED;
return TRUE;
}
Bool MorphDeformer::CopyTo(NodeData *dest, GeListNode *snode, GeListNode *dnode, LONG flags, AliasTrans *trn)
{
MorphDeformer *df = (MorphDeformer* ) dest;
if (!df) return FALSE;
if (falloff && df->falloff)
if (!falloff->CopyTo(df->falloff)) return FALSE;
return ObjectData::CopyTo(dest,snode,dnode,flags,trn);
}
Bool MorphDeformer::ModifyObject(PluginObject *mod, BaseDocument *doc, BaseObject *op, const Matrix &op;_mg, const Matrix &mod;_mg, Real lod, LONG flags, BaseThread *thread)
{
if (!op->IsInstanceOf(Opoint) || !falloff) return TRUE;
BaseContainer *bc = mod->GetDataInstance(), *bbc = NULL;
if (!bc) return TRUE;
Vector *padr = ToPoint(op)->GetPointW(); //Assuming we will be writing to the points in op here, otherwise use const and GetPointR for speed
LONG pcnt = ToPoint(op)->GetPointCount(),
i = 0;
if (!padr || pcnt == 0) return TRUE;
Real res = 0.0,
strength = bc->GetReal(MORPHDEFORMER_STRENGTH);
GeDynamicArray<Real>fall(pcnt);
if (!fall) return FALSE; //Memory error
Real *weight = ToPoint(op)->CalcVertexMap(mod);
if (weight) //Always test that weight exists before using it
{
for (i = 0; i < pcnt && (!thread || !thread->TestBreak()); i++)
{
Vector pp =padr _* op_mg;/*Position to sample in world space*/
falloff->Sample(pp, &res;); //Init has to have been called before using this, here it's done in the "execute" routine for speed, though it takes next to zero time to actually run init as all it's doing is setting a few variables from the objects container.
fall _= res * weight _* strength;
}
}
else
{
for (i = 0; i < pcnt && (!thread || !thread->TestBreak()); i++)
{
Vector pp =padr _* op_mg;/*Position to sample in world space*/
falloff->Sample(pp, &res;);
fall _= res * strength;
}
}
GeFree(weight);
//Do something using the resulting fall array to the points in op
/*..................
.....................*/
op->Message(MSG_UPDATE);
return TRUE;
}
you will also need to check the dirty status for the source mode.
void mydeformer::CheckDirty(PluginObject *op, BaseDocument *doc)
{
if (falloff)
{
BaseContainer *bc = op->GetDataInstance()
if (!bc) return;
LONG dirty = falloff->GetDirty(bc);
if (dirty==lastdirty) return;
op->SetDirty(DIRTY_DATA);
lastdirty = dirty;
}
}
```