The Maxon SDK Team is currently short staffed due to the winter holidays. No forum support is being provided between 15/12/2025 and 5/1/2026. For details see Maxon SDK 2025 Winter Holidays.
  • Deformer update and Fields

    c++ r20 windows macos
    2
    0 Votes
    2 Posts
    800 Views
    ValkaariV
    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); }
  • Adding Bitmap Button to ListView

    c++ r20 sdk
    5
    1
    0 Votes
    5 Posts
    973 Views
    O
    Thank you @m_adam It works fine
  • Run Plugin Last

    python r19
    3
    1
    0 Votes
    3 Posts
    808 Views
    A
    @m_adam Hi Maxime, It works like a treat! I've ended up changing the UI to a treeView and it's still working great. Thank you very much! Andre
  • TreeView Add Data

    6
    0 Votes
    6 Posts
    1k Views
    O
    I passed on the listview for now. I still have to look in more details for the TreeView. Thank you.
  • Seperators in GetSubContainer

    python windows r20
    2
    1
    0 Votes
    2 Posts
    509 Views
    M
    Hi @Boony2000 In a GetSubContainer, to insert a separator use InsData(0, "") The ID used should always be 0. As described in ShowPopupDialog Example. Which give us def GetSubContainer(self, doc, submenu) : menuItems = [["name1"], ["name2", "hasIcon"], ["name3"]] for i, data in enumerate(menuItems) : if len(data) > 1: submenu.SetString(i+1000, data[0] + "&i" + str(c4d.IDM_KEY_NEXT) + "&") submenu.InsData(0, "") else: submenu.SetString(i+1000, data[0]) return True Cheers, Maxime.
  • FILENAME attribute extension filter

    c++
    5
    0 Votes
    5 Posts
    1k Views
    rsodreR
    @s_bach Ok, I can revert the values to the base container. That solves my issue, thanks!
  • Filling vertex_color for SceneHook

    2
    0 Votes
    2 Posts
    465 Views
    a_blockA
    Hi, GeAllocTypeNC() was already removed from the API with version R15 (see API Change List in R15 and maybe more interesting for you Transition to Cinema 4D R15 API). You are already on the right track using NewMem(), now in R20, there's an additional change, which bites you here: The error handling. This indeed is quite an important topic and (of course no bragging involved at all) a really nice feature in the new MAXON API. But it's also the one thing that causes most needed changes for R20. The point is, here at MAXON we do not take error checking lightly. Actually quite the opposite, we enforce error handling where ever we can and our internal developers have no chance to get away without. So, before I provide the solution, here the recommendation to take the time to read the manuals about the Error System. Additionally I recommend the manuals about classic API Entity Creation and Destruction and its MAXON API sibling about Memory Allocation. The additional means you get provided with in the new MAXON API can really make your life easier. I apologize for writing so much before coming to your actual issue. In the end NewMemClear() now returns an Error Result, which basically encapsulates the actual return value and needs to be evaluated in order to get the actual return value. No worries, this is done in a highly optimized form, so it should not impede your code's performance in any way. If you take a look at our SDK examples, you will find quite a few places, where error handling in conjunction with NewMem is demonstrated in various ways. Cheers, Andreas
  • BaseContainer bc = NULL;

    c++ r20
    3
    0 Votes
    3 Posts
    575 Views
    R
    Thank you Andres. I'm going with the boolean variable to flag if a BaseContainer contains something or not.
  • Quicktab Radio Buttons

    2
    0 Votes
    2 Posts
    783 Views
    merkvilsonM
    Seems like this is a way to go. LONG TEST_BUTTONS {CUSTOMGUI QUICKTABRADIO; CYCLE{ TEST_1; TEST_2; TEST_3; }FIT_H;} Previously my mistake was that I was writing CUSTOMGUI QUICKTABRADIOBUTTON instead of CUSTOMGUI QUICKTABRADIO
  • Non blocking modal

    c++
    3
    0 Votes
    3 Posts
    729 Views
    rsodreR
    @m_adam I think that will not be possible for what I want to do. I ended up catching BFM_LOSTFOCUS in the dialog, canceling the process.
  • INCLUDE user-defined res files

    python
    3
    0 Votes
    3 Posts
    936 Views
    a_blockA
    Hi, no, you are not! Really there are no stupid questions and please do not delete such posts. Especially not, if you already invested time in posting the correct answer. We'd rather see this as knowledge others might benefit from in the future. Cheers, Andreas
  • Using maxon::BaseList with a TreeView?

    2
    0 Votes
    2 Posts
    576 Views
    M
    Hi @Kuroyume0161, first of all, welcome back in the plugincafe community, I'm glad to see you here! Unfortunately, this is not possible to use directly a BaseList with a TreeView and as you already figured it out, you have to maintain this list yourself. While it's very nice that a TreeView offer this abstraction level, and allows to make a list from any kind of data, it has the overhead to builds this TreeView layer. Cheers, Maxime.
  • Adding icon to submenu

    python windows r20
    7
    1
    0 Votes
    7 Posts
    1k Views
    B
    Thanks, Maxime! I will use that in the meantime. Edit: Why can't I flag your posts as the correct answer? I can only flag my own.
  • getline not working

    6
    0 Votes
    6 Posts
    1k Views
    R
    It is so weird that it worked in versions pre R20. Well, I will have to find a new solution, then.
  • GetCache() bug

    python
    4
    0 Votes
    4 Posts
    958 Views
    M
    Hi @merkvilson, this feedback has been communicated to our development team. Cheers, Maxime.
  • Checkmark in submenu list when using GetSubContainer

    python r20
    4
    2
    0 Votes
    4 Posts
    820 Views
    a_blockA
    Yes, that's appropriate. Thanks
  • Undefined symbols for architecture x86_64

    9
    0 Votes
    9 Posts
    3k Views
    R
    This is really weird but after getting this error (and everything all being Ok), the way that I found to get rid of this error is to delete the xcodeproj, the props, the vcxproj and the vcxproj.filters files from the project folder, leaving just the projectdefinition.txt file there, and running the Project Tool again. Then, opening the newly created xcodeproj file, I no longer get this error and it compiles fine.
  • Use of undeclared identifier 'g_resource'

    8
    0 Votes
    8 Posts
    2k Views
    R
    Good news. And... more good news. The best news are that, after creating a Debug version and running Cinema 4D R20 from XCode, all of a sudden, the plugin started working!!! I then created a simple build (not a Debug one) and it is still working fine The other good news is that I now know how to create a Debug version
  • GeDialog in a Python Script: error without exception set?

    python r20
    6
    0 Votes
    6 Posts
    1k Views
    fwilleke80F
    Hi Maxime, now that's interesting. You code runs perfectly fine. If I copy & paste your dialog code into my script, it still works, though your dialog is seemingly similar to mine. So, I have no idea what fixed it, but it did. Maybe some excess trailing spaces somewhere? Weird... but thank you for doing your magic If I ever find out what was happening here, I'll post here. Cheers, Frank
  • Current document in Team Render

    c++
    3
    0 Votes
    3 Posts
    882 Views
    V
    @r_gigante It was about updating an object during the render process but I used a different aproach just by sending the object's doc to that function so I think it could be solved already.