• Get PluginID from within CommandData plugin

    Cinema 4D SDK python r20 windows
    4
    0 Votes
    4 Posts
    1k Views
    B
    I am trying to register multiple plugins that are instances of the same class, but do slightly different stuff (in this case construct different menus). I am getting some external data that I would like to put in a dictionary with the plugin ID as keys. I could then get the correct data set for each plugin by comparing the pluginID from e.g. within execute with the pluginIDs in the dictionary. But for that I would need a way to retrieve the pluginID of the class instance whose execute function was called. Edit: I figured out a way. I can pass the pluginID when initializing the plugin in the register function and save it as a class member in __init__
  • Optimize Collision Detection

    Cinema 4D SDK c++ r20 sdk
    4
    0 Votes
    4 Posts
    1k Views
    J
    Hello, Thanks for the responses. I thought that this might be the case and just wanted to clarify it before moving forward. John Thomas
  • Do Cinema 4D and c4dpy use different lists of plugins?

    Cinema 4D SDK
    4
    0 Votes
    4 Posts
    1k Views
    M
    This issue is now fixed in R21. Cheers, Maxime.
  • Parameters for commandData Plugin

    Cinema 4D SDK python r20 windows
    3
    0 Votes
    3 Posts
    644 Views
    B
    Hi Sebastian! Thanks for your answer. I was looking for something a little more flexible than registering multiple plugins, but I guess GetSubContainer will have to do
  • 0 Votes
    3 Posts
    855 Views
    P
    Hello. Thank you very much for your clarification on this. I have a button in MaterialData that saves the material in a specific format in the disk. I doesn't change anything in the material but the MSG_UPDATE is sent anyway. So, since I don't want to run the MSG_UPDATE handler, I have to set a flag to true in order to skip it. Thank you.
  • MAXON Data Type and explicit constructors

    Cinema 4D SDK c++ r20 windows
    7
    0 Votes
    7 Posts
    2k Views
    M
    Thanks Riccardo! Now I understand - thanks to your side note. And of course I understand, that this goes hand in hand with your guidelines. Cheers, Robert
  • Check vertex changes on a VertexMapTag

    Cinema 4D SDK c++ r20
    3
    0 Votes
    3 Posts
    683 Views
    rsodreR
    @r_gigante thanks for explaining this workflow, and how the vertex tag is implemented. For my case, I discovered it's easier and safer to listen to the tag's object (when I update the tag it will invalidate a dependency list it's in), then sum all the values to detect changes, for either vertex map and color. This works well for undos too, because if I make several paintings in a row and start undoing one by one, the DIRTYFLAGS_DATA and HDIRTYFLAGS_TAG are not very reliable. They come down on the first undo, but stay with the same value on subsequent undos. R.
  • CommandData plugin with a res dialog

    Cinema 4D SDK python r20
    11
    0 Votes
    11 Posts
    2k Views
    S
    Hello, yes, you can use resource files to define the dialog layout. Or combine layout files and code. def CreateLayout(self): self.SetTitle("Dialog Test") # load dialog from resource file if self.LoadDialogResource(10000, None, 0) == False: return False # set a different title self.SetTitle("New Title") # disable a GUI element self.Enable(10001, False) return True See GeDialog Manual and Layout files. best wishes, Sebastian
  • 0 Votes
    6 Posts
    2k Views
    r_giganteR
    Hi Shir, thanks for following up and providing your additional info. Showing parameter in the Attribute Manager or a custom icon in the Object Manager is not such a big issue: you can start looking at Py-RoundedTube which is an ObjectData derived plugin where all such a stuff (and more) is shown. That said, the real question is instead to understand what your rig is actually doing and see if it's reasonable to implement the Xpresso functionality from a set of "primitive" functions you implement in your plugin or if would be instead easier to programmatically recreate the Xpresso rig in an XpressoTag then attached to the object generated by your plugin. Actually this assessment can't be done from here where the final functionality and the complexity of your Xpresso network is unknown. So far I do see three approches: start on your own, step-by-step, dissect the code from the example I mentioned above and try to move your steps alone outsource the task to some paid developer or call for volunteers in our very helpful PluginCafe community. I'm sorry not be more helpful but, as said in the first post, we can't deliver turn-key plugins or scripts but rather help our customer to learn from our resources. Best, Riccardo
  • how to insert a gradiet with step interperation?

    Cinema 4D SDK python r20
    3
    0 Votes
    3 Posts
    934 Views
    M
    yeah! I got it! Thank you very much!
  • Sample the color of a vertex

    Moved Cinema 4D SDK r20 c++
    5
    0 Votes
    5 Posts
    1k Views
    R
    It seems quite simple, reading your code. However, that is python and I'm doing it in c++. I was trying to attach the old code I was using, but the uploader only allows for images. However, I'm now trying to make more generic, by internally baking the material, as it allows for more complex material assignments to objects. I'm still struggling but I will try to solve it myself, before coming back here
  • r20 python Field

    Moved Cinema 4D SDK r20 python
    3
    0 Votes
    3 Posts
    722 Views
    M
    Hi @Nenov, first of all, welcome in the plugincafe community. No worry since it's your first post, but I would like to point you to the Q&A Functionality and How to Post Questions especially about categories. I've setup your topic correctly and moved to the correct category. Regarding your issue, this actually the purpose of the example to do a different operation on even and odd clones. With that's said you can find more example in our Github repository especially theses following files: field_python_color_direction.c4d field_pythonmodifier_readcolor.c4d field_pythonmodifier_vertexmap.c4d If you have any question please let me know, Cheers, Maxime.
  • 0 Votes
    4 Posts
    890 Views
    M
    @a_block It was the ID. I did use a random number, apparently one too many. I didn't think it would matter for testing but I guess I was wrong! I figured it would be something dumb like that. It was just weird it pointed me to that line for the error. And yes sorry my code snippet was confusing, I thought it was standard practice to put RegisterObjectPlugin on multiple lines for easier reading. Thanks again!
  • Deformer update and Fields

    Cinema 4D SDK c++ r20 windows macos
    2
    0 Votes
    2 Posts
    842 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); }
  • Incorrect file structure

    Cinema 4D SDK r20
    6
    0 Votes
    6 Posts
    3k Views
    a_blockA
    Hi Roger, that's good news! Cheers, Andreas
  • Seperators in GetSubContainer

    Cinema 4D SDK python windows r20
    2
    1
    0 Votes
    2 Posts
    536 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.
  • Adding Bitmap Button to ListView

    Cinema 4D SDK c++ r20 sdk
    5
    1
    0 Votes
    5 Posts
    1k Views
    O
    Thank you @m_adam It works fine
  • Filling vertex_color for SceneHook

    Cinema 4D SDK
    2
    0 Votes
    2 Posts
    492 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;

    Cinema 4D SDK c++ r20
    3
    0 Votes
    3 Posts
    615 Views
    R
    Thank you Andres. I'm going with the boolean variable to flag if a BaseContainer contains something or not.