Get Group description children

  • On 01/06/2016 at 11:11, xxxxxxxx wrote:

    Just wanted to let you know, that I can reproduce your issue, but haven't found the culprit, yet.

  • On 01/06/2016 at 14:25, xxxxxxxx wrote:

    Hmm, the docs say the caller owns the pointed container, so I guess it must be instanced first? But that would mean the pointed container is only "filled" (though it could also mean otherwise, as I remember I used description->GetDescEntry() before with a nullptr initialisation of the temp basecontainer and it worked fine..hmmm).
    The function signature of GetNext() is kinda ugly.

          BaseContainer bc;  
          const BaseContainer* bcptr = &bc;  
          while (desc->GetNext(handle, &bcptr, id, groupid))

    Note: I haven't tried this code in practice. And now after writing it kind of doesn't seem right...just grabbing thoughts.

  • On 01/06/2016 at 15:10, xxxxxxxx wrote:

    For Description::GetDescEntry() and GetNext(), the argument is const BaseContainer**.  So, &bcptr; is correct (a pointer to a pointer to a BaseContainer).

  • On 02/06/2016 at 00:26, xxxxxxxx wrote:

    @Samir: Unfortunately the docs are wrong, C4D owns the pointed BaseContainer. I discovered the error yesterday afternoon. Will be corrected in the next release of the SDK Docs. But this is not the reason for the actual issue of this thread. Still looking into it.

  • On 02/06/2016 at 03:32, xxxxxxxx wrote:

    @Kuro: Cheers. What I actually meant was if C4D is actually filling the pointer pointed to with an own instance pointer (allocated internally in the GetNext() function) and the user must free this one or if the pointer comes from the caller (my version). But as the docs are apparently wrong (thanks Andreas for the info), this resolves that it should be nullptr initialised. : )

    @Andreas: thx. Hmm, what is the actual issue of the code then? What is not working with the provided example?

  • On 03/06/2016 at 02:52, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Just wanted to let you know, that I can reproduce your issue, but haven't found the culprit, yet.

    Glad to hear. 
    Thanks for your efforts. :)

  • On 03/06/2016 at 10:19, xxxxxxxx wrote:

    @mp5gosu: I'm sorry, I wasn't able to find the issue until now. Unfortunately I will be at our developer meeting, so surely won't make any progress during the next week. I'm planning to continue to work on this after my return. By experience I already know, that it will get a bit turbulent, when the team has been off for an entire week, so please ping me again, if I don't return to you within a reasonable amount of time (lets say Wednesday?). Terribly sorry!

  • On 03/06/2016 at 10:27, xxxxxxxx wrote:

    Hey Andreas, no worries! I know you Maxonians are busy but dedicated people. ;)
    Sure, I'll note you.

    However, thanks again for having a look into this issue. 
    It's not crucial for me right now but would make me write way less code. Also for others this would help solving some problems regarding this issue.

    Cheers, have a nice weekend and have some fun on the DevMeet!

  • On 13/06/2016 at 22:50, xxxxxxxx wrote:

    Here's your personal reminder. ;)
    Did you find some time to sort this out yet?

  • On 14/06/2016 at 00:38, xxxxxxxx wrote:

    No, I haven't yet. But I haven't forgotten either. Nevertheless thanks for the reminder. I'll continue to investigate today.

  • On 14/06/2016 at 05:33, xxxxxxxx wrote:

    TL;DR but here's a class that I built for the Vray project that allows to browse all parameters in the
    description and check the parent group. For the way I use it, it's working very good. You may use it
    as you like. Usage is pretty straight forward:

    vb::desc::StructureHelper structure(description);
    for (auto const* info : structure.iter()) {
    	if (structure.CheckGroup(info->did, THE_GROUP_ID)) {
    		// This parameter is inside the group THE_GROUP_ID
    		// ...

    In case you don't want to skip the iterator part, nr_iterator is here.

    /// Copyright(C) 2015  Niklas Rosenstein
    /// Developed for laubLAB KG.
    /// Source/Library/lib_desc.h
    #pragma once
    #include "c4d.h"
    #include "nr/iterator.h"
    namespace vb {
    namespace desc {
    	 * Structure that contains the parameter information as it is yielded by
    	 * #Description::GetNext().
    	struct ParamInfo {
    		BaseContainer const* bc = nullptr;
    		DescID did;
    		DescID gid;
    	 * This is a helper class for reading structural information from a node's
    	 * #Description. For instance, it allows you to check if a parameter is inside
    	 * a specific group.
    	class StructureHelper {
    		friend class Iterator;
    		maxon::HashMap<Int32, ParamInfo> map;
    		maxon::BaseArray<Int32> order;  // required for correct order iteration
    		StructureHelper() { }
    		StructureHelper(Description* desc) { Init(desc); }
    		~StructureHelper() { }
    		inline Bool Init(Description* desc) {
    			if (!desc) return false;
    			ParamInfo param;
    			void* handle = desc->BrowseInit();
    			while (desc->GetNext(handle, &param.bc, param.did, param.gid)) {
    				this->map.Put(param.did[0].id, param);
    			return true;
    		 * Returns the #ParamInfo info structure for a specific description ID
    		 * #did or nullptr if there is no parameter with the specified ID.
    		// @{
    		inline ParamInfo const* Get(Int32 did) const {
    			auto* entry = this->map.FindEntry(did);
    			if (entry) return &entry->GetValue();
    			return nullptr;
    		inline ParamInfo const* Get(DescID const& did) const {
    			return this->Get(did[0].id);
    		// @}
    		 * Returns the #ParamInfo for the parent group of the specified parameter.
    		inline ParamInfo const* GetParentGroup(ParamInfo const* info) const {
    			if (!info || info->did[0].id == info->gid[0].id) return nullptr;
    			return this->Get(info->gid);
    		 * Checks if the parameter with the description ID #did is anywhere
    		 * in the group specified by #gid and returns true in that case, false
    		 * otherwise.
    		inline Bool CheckGroup(DescID did, DescID const& gid) const {
    			while (did != gid) {
    				ParamInfo const* group = this->Get(did);
    				if (!group) return false;
    				did = group->gid;
    			return true;
    		 * Helper to iterate over the entries in the description. This will
    		 * happen in the same order as the iteration over the source #Description.
    		class Iterator : public nr::iterator<Iterator> {
    			StructureHelper const& helper;
    			decltype(StructureHelper::order) ::ConstIterator it, itend;
    			Iterator(StructureHelper const& helper) : helper(helper), it(helper.order.begin()), itend(helper.order.end()) { }
    			Bool at_end() const { return it == itend; }
    			ParamInfo const* operator * () const { return helper.Get(*it); }
    			void next() { ++it; }
    		inline Iterator iter() const { return Iterator(*this); }
    }} // namespace vb::desc

  • On 14/06/2016 at 09:55, xxxxxxxx wrote:

    Thanks Niklas. Storing the data into a struct seems like a reasonable approach. I'll give it a try if I find some time. ;)

  • On 30/06/2016 at 03:42, xxxxxxxx wrote:

    Hey Andreas, any progress here yet? ;)

  • On 18/08/2016 at 09:07, xxxxxxxx wrote:


    not sure, if you are still waiting for me, here... I'm terribly sorry, but you gave me quite a hard nut and I was stupidly searching at the wrong end. And in the end it was Sebastian, who solved this.

    Cinema 4D calls GetDDescription() quite a bunch of times. Amongst others when building the GUI and during SetParameter(). When building the GUI your code works and so you see the correct entries in the cycle box. But when calling it during SetParameter(), GetDDescription() is called in "single description mode". When in this mode, calling GetParameterI() sets the description into a special mode, with the effect that any following browse will return only one parameter. With your code this has the unfortunate effect, that you won't fill the items container. So SetParameter() thinks, there are no options and the parameter won't be set.

    For you this means, you can either split your loop and first browse/collect the cycle box items before calling GetParameterI().
    Or you can use a second temporary description for your browse loop.

    AutoAlloc<Description> tempDescription;

    The reasons for this behavior seem to be some heavy optimization, but we need to check this with development. Then we will see, how we can document it properly.

    Again, terribly sorry, this took so long.

  • On 18/08/2016 at 09:19, xxxxxxxx wrote:

    Wow, huuuge thanks to you Andreas!
    Also Sebastian, please buy him a beer. ;)

    Indeed I was eagerly waiting for a response to this. And your answer is very enlightening. 
    With this information, I'm able to circumvent this behaviour in future projects and also reduce my current code a lot!



Log in to reply