Deformer update and Fields



  • hello,

    i'm creating a deformer and i want to add the new falloff / fields option.
    everything seem to work fine but the deformer doesn't update when i move / modify a linear field or any field i've added.
    (the function modifyObject() isn't called)

    If i change frame or force the update with the a key, it does work.



  • 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);
    }