using the CheckDirty function seem to be the solution.

void Spherify::CheckDirty(BaseObject* op, BaseDocument* doc) { if (falloff) { BaseContainer *data = op->GetDataInstance(); Int32 dirty = falloff->GetDirty(doc, data); if (dirty == lastFalloffDirtyCheck) return; op->SetDirty(DIRTYFLAGS::DATA); lastFalloffDirtyCheck = dirty; } }

the full code for the spherify deformer :

// deformer object example #include "c4d.h" #include "c4d_symbols.h" #include "main.h" #include "ospherifydeformer.h" #include "c4d_falloffdata.h" #define HANDLE_CNT 2 class Spherify : public ObjectData { public: virtual Bool Init(GeListNode* node); virtual Bool Message (GeListNode* node, Int32 type, void* data); virtual void GetDimension (BaseObject* op, Vector* mp, Vector* rad); virtual DRAWRESULT Draw (BaseObject* op, DRAWPASS type, BaseDraw* bd, BaseDrawHelp* bh); virtual void GetHandle (BaseObject* op, Int32 i, HandleInfo& info); virtual Int32 DetectHandle (BaseObject* op, BaseDraw* bd, Int32 x, Int32 y, QUALIFIER qualifier); virtual Bool MoveHandle (BaseObject* op, BaseObject* undo, const Vector& mouse_pos, Int32 hit_id, QUALIFIER qualifier, BaseDraw* bd); virtual Bool ModifyObject (BaseObject* op, BaseDocument* doc, BaseObject* mod, const Matrix& op_mg, const Matrix& mod_mg, Float lod, Int32 flags, BaseThread* thread); AutoAlloc<C4D_Falloff> falloff; Int32 lastFalloffDirtyCheck; virtual Int32 GetHandleCount(BaseObject *op); virtual void SetHandle(BaseObject *op, Int32 i, Vector p, const HandleInfo &info); virtual Bool CopyTo(NodeData *dest, GeListNode *snode, GeListNode *dnode, COPYFLAGS flags, AliasTrans *trn); virtual Bool GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags); virtual Bool AddToExecution(BaseObject *op, PriorityList *list); virtual EXECUTIONRESULT Execute(BaseObject *op, BaseDocument *doc, BaseThread *bt, Int32 priority, EXECUTIONFLAGS flags); virtual void CheckDirty(BaseObject* op, BaseDocument* doc); static NodeData* Alloc() { return NewObjClear(Spherify); } }; Int32 Spherify::GetHandleCount(BaseObject *op) { BaseContainer *bc = op->GetDataInstance(); if (!bc) return 0; if (falloff) return falloff->GetHandleCount(bc) + HANDLE_CNT; return 0; } void Spherify::SetHandle(BaseObject *op, Int32 i, Vector p, const HandleInfo &info) { BaseContainer *bc = op->GetDataInstance(); if (!bc) return; if (falloff) falloff->SetHandle(i, p, bc, info); } Bool Spherify::CopyTo(NodeData *dest, GeListNode *snode, GeListNode *dnode, COPYFLAGS flags, AliasTrans *trn) { Spherify *df = (Spherify*)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 Spherify::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags) { BaseObject *op = (BaseObject*)node; if (!op) return false; BaseContainer *data = op->GetDataInstance(); if (!data) return false; if (!description->LoadDescription(op->GetType())) return false; //--------------------------------- // Add the falloff interface if (falloff) { if (!falloff->SetMode(FIELDS, data)) // The falloff parameters have to have been setup before it can be added to the description, this like makes sure of that return false; if (!falloff->AddFalloffToDescription(description, data, DESCFLAGS_DESC::NONE)) return false; } flags |= DESCFLAGS_DESC::LOADED; return true; } void Spherify::CheckDirty(BaseObject* op, BaseDocument* doc) { if (falloff) { BaseContainer *data = op->GetDataInstance(); Int32 dirty = falloff->GetDirty(doc, data); if (dirty == lastFalloffDirtyCheck) return; op->SetDirty(DIRTYFLAGS::DATA); lastFalloffDirtyCheck = dirty; } } Bool Spherify::AddToExecution(BaseObject *op, PriorityList *list) { list->Add(op, EXECUTIONPRIORITY_INITIAL, EXECUTIONFLAGS::NONE); return TRUE; } EXECUTIONRESULT Spherify::Execute(BaseObject *op, BaseDocument *doc, BaseThread *bt, Int32 priority, EXECUTIONFLAGS flags) { BaseContainer *data = op->GetDataInstance(); if (!data) return EXECUTIONRESULT::USERBREAK; if (falloff) if (!falloff->InitFalloff(data, doc, op)) return EXECUTIONRESULT::OUTOFMEMORY; return EXECUTIONRESULT::OK; } Bool Spherify::Message(GeListNode* node, Int32 type, void* data) { if (type == MSG_MENUPREPARE) { ((BaseObject*)node)->SetDeformMode(true); } return true; } Bool Spherify::ModifyObject(BaseObject* mod, BaseDocument* doc, BaseObject* op, const Matrix& op_mg, const Matrix& mod_mg, Float lod, Int32 flags, BaseThread* thread) { BaseContainer* data = mod->GetDataInstance(); Vector p, *padr = nullptr; Matrix m, im; Int32 i, pcnt; Float rad = data->GetFloat(SPHERIFYDEFORMER_RADIUS), strength = data->GetFloat(SPHERIFYDEFORMER_STRENGTH); Float s; Float32* weight = nullptr; if (!op->IsInstanceOf(Opoint)) return true; padr = ToPoint(op)->GetPointW(); pcnt = ToPoint(op)->GetPointCount(); if (!pcnt) return true; FieldInput inputs(padr, pcnt, op_mg); Bool outputsOK = falloff->PreSample(doc, mod, inputs, FIELDSAMPLE_FLAG::VALUE); Float fallOffSampleValue(1.0); weight = ToPoint(op)->CalcVertexMap(mod); m = (~mod_mg) * op_mg; // op -> world -> modifier im = ~m; for (i = 0; i < pcnt; i++) { if (thread && !(i & 63) && thread->TestBreak()) break; p = m * padr[i]; s = strength; if (weight) s *= weight[i]; if (outputsOK) falloff->Sample(p, &fallOffSampleValue, true, 0.0, nullptr, i); s *= fallOffSampleValue; p = s * (!p * rad) + (1.0 - s) * p; padr[i] = im * p; } DeleteMem(weight); op->Message(MSG_UPDATE); return true; } void Spherify::GetDimension(BaseObject* op, Vector* mp, Vector* rad) { BaseContainer* data = op->GetDataInstance(); *mp = Vector(0.0); *rad = Vector(data->GetFloat(SPHERIFYDEFORMER_RADIUS)); } DRAWRESULT Spherify::Draw(BaseObject* op, DRAWPASS drawpass, BaseDraw* bd, BaseDrawHelp* bh) { if (!op->GetDeformMode()) return DRAWRESULT::SKIP; BaseContainer *bc = op->GetDataInstance(); if (!bc) return DRAWRESULT::FAILURE; if (falloff) falloff->Draw(bd, bh, drawpass, bc); if (drawpass == DRAWPASS::OBJECT) { BaseContainer* data = op->GetDataInstance(); Float rad = data->GetFloat(SPHERIFYDEFORMER_RADIUS); Matrix m = bh->GetMg(); m.sqmat *= rad; bd->SetMatrix_Matrix(nullptr, Matrix()); bd->SetPen(bd->GetObjectColor(bh, op)); bd->DrawCircle(m); maxon::Swap(m.sqmat.v2, m.sqmat.v3); bd->DrawCircle(m); maxon::Swap(m.sqmat.v1, m.sqmat.v3); bd->DrawCircle(m); } else if (drawpass == DRAWPASS::HANDLES) { Int32 i; Int32 hitid = op->GetHighlightHandle(bd); HandleInfo info; bd->SetPen(GetViewColor(VIEWCOLOR_ACTIVEPOINT)); bd->SetMatrix_Matrix(op, bh->GetMg()); for (i = 0; i < HANDLE_CNT; i++) { GetHandle(op, i, info); if (hitid == i) bd->SetPen(GetViewColor(VIEWCOLOR_SELECTION_PREVIEW)); else bd->SetPen(GetViewColor(VIEWCOLOR_ACTIVEPOINT)); bd->DrawHandle(info.position, DRAWHANDLE::BIG, 0); } GetHandle(op, 1, info); bd->SetPen(GetViewColor(VIEWCOLOR_ACTIVEPOINT)); bd->DrawLine(info.position, Vector(0.0), 0); } return DRAWRESULT::OK; } void Spherify::GetHandle(BaseObject* op, Int32 i, HandleInfo& info) { BaseContainer* data = op->GetDataInstance(); if (!data) return; if (falloff) falloff->GetHandle(i, data, info); switch (i) { case 0: info.position.x = data->GetFloat(SPHERIFYDEFORMER_RADIUS); info.direction.x = 1.0; info.type = HANDLECONSTRAINTTYPE::LINEAR; break; case 1: info.position.x = data->GetFloat(SPHERIFYDEFORMER_STRENGTH) * 1000.0; info.direction.x = 1.0; info.type = HANDLECONSTRAINTTYPE::LINEAR; break; default: break; } } Int32 Spherify::DetectHandle(BaseObject* op, BaseDraw* bd, Int32 x, Int32 y, QUALIFIER qualifier) { if (qualifier & QUALIFIER::CTRL) return NOTOK; HandleInfo info; Matrix mg = op->GetMg(); Int32 i, ret = NOTOK; Vector p; for (i = 0; i < HANDLE_CNT; i++) { GetHandle(op, i, info); if (bd->PointInRange(mg * info.position, x, y)) { ret = i; if (!(qualifier & QUALIFIER::SHIFT)) break; } } return ret; } Bool Spherify::MoveHandle(BaseObject* op, BaseObject* undo, const Vector& mouse_pos, Int32 hit_id, QUALIFIER qualifier, BaseDraw* bd) { BaseContainer* dst = op->GetDataInstance(); HandleInfo info; Float val = mouse_pos.x; GetHandle(op, hit_id, info); if (bd) { Matrix mg = op->GetUpMg() * undo->GetMl(); Vector pos = bd->ProjectPointOnLine(mg * info.position, mg.sqmat * info.direction, mouse_pos.x, mouse_pos.y); val = Dot(~mg * pos, info.direction); } switch (hit_id) { case 0: dst->SetFloat(SPHERIFYDEFORMER_RADIUS, ClampValue(val, 0.0_f, (Float) MAXRANGE)); break; case 1: dst->SetFloat(SPHERIFYDEFORMER_STRENGTH, Clamp01(val * 0.001)); break; default: break; } return true; } Bool Spherify::Init(GeListNode* node) { BaseObject* op = (BaseObject*)node; BaseContainer* data = op->GetDataInstance(); data->SetFloat(SPHERIFYDEFORMER_RADIUS, 200.0); data->SetFloat(SPHERIFYDEFORMER_STRENGTH, 0.5); if (falloff) { if (!falloff->InitFalloff(nullptr, nullptr, op)) return false; lastFalloffDirtyCheck = -1; } return true; } // be sure to use a unique ID obtained from www.plugincafe.com #define ID_SPHERIFYOBJECT 1001158 Bool RegisterSpherify() { return RegisterObjectPlugin(ID_SPHERIFYOBJECT, GeLoadString(IDS_SPHERIZE), OBJECT_MODIFIER | OBJECT_CALL_ADDEXECUTION, Spherify::Alloc, "Ospherifydeformer"_s, AutoBitmap("spherify.tif"_s), 0); }