Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Update Attribute Manager after SetParameter

    SDK Help
    0
    4
    1.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 13/06/2018 at 10:00, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   19 
      Platform:   Windows  ;   
      Language(s) :     C++  ;

      ---------
      I'm sure I'm missing something obvious, but having not used the C++ SDK for quite a while...

      I'm updating a few parameters from a custom function. This is an ObjectData plugin with a few string and long fields. NR_FRAMEINDEX in this case is LONG.

      // a static callback function
      void(__stdcall NeuronReader::BVHFrameDataReceived)(void* customObj, SOCKET_REF sender, BvhDataHeader* header, float* data) {
      	NeuronReader* pthis = (NeuronReader* )customObj;
      	BaseObject *op = (BaseObject* )(pthis->Get());
      	pthis->ReadNeuronBvhData(sender, header, data, op);
      }
        
      // this should update the parameters
      void NeuronReader::ReadNeuronBvhData(SOCKET_REF sender, BvhDataHeader* header, float* data, BaseObject* op) {
      	if (sender) {
      		Int32 frameIndex = (Int32)(header->FrameIndex);
      		op->SetParameter(DescID(NR_FRAMEINDEX), GeData(frameIndex), DESCFLAGS_SET_0);
      		//op->SetDirty(DIRTYFLAGS_DATA);
      		//op->Message(MSG_CHANGE);
      		//EventAdd(EVENT_ANIMATE);
      	}
      }
      

      This  feels straightforward enough. Checking the NR_FRAMEINDEX parameter via GeConsoleOut shows me that it writes the correct values. However, the Attribute Manager attribute never gets updates.

      Do I need to go through some SetDParameter magic or something? The various EventAdds and MSG_Change etc don't seem to do anything here.

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 14/06/2018 at 03:58, xxxxxxxx wrote:

        I don't get it. I have now gone and implemented a (feeling somewhat convoluted) way to make sure that the SetParameter happens in the MainThread (by creating a MessageData plugin, sending a SpecialEventAdd() there containing a pointer to my object, sending a GePluginMessage() back (again containing the pointer) and then calling a function to apply the parameter.
        I'm checking with GeIsMainThread() all along the way. Yet the UI will not update. Argh!

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 14/06/2018 at 09:50, xxxxxxxx wrote:

          Hi,

          to be honest I don't immediately see the issue, either.
          Normally a EventAdd() (and also your EventAdd(EVENT_ANIMATE)) should do the trick.
          You seem to have had the same sus**cion as I had in your second post. Nevertheless I'd like to ask in which context the functions you posted are called/used? Maybe a rough description of the structure of your ObjectData could help as well.
          In any case I will discuss this tomorrow with the team.

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 15/06/2018 at 02:32, xxxxxxxx wrote:

            This should be all the relevant code...

            This is the output I get:

            Registered the NeuronReader plugin
            Connected to Neuron server at 127.0.0.1:7001
            Demo message
            IS MainThread
            ApplyNeuronData running in MainThread // Modifying:1004
            Before: 0
            MSG_DESCRIPTION_POSTSETPARAMETER: 1004
            POSTSETPARAMETER_VALUE:40
            After: 40
            

            So the parameter is set correctly internally, but somehow it does not get reflected in the UI at all.

            // This is a callback function, being called from a threaded context
            void(__stdcall ONeuronReader::BVHFrameDataReceived)(void* customObj, SOCKET_REF sender, BvhDataHeader* header, float* data) {
                ONeuronReader* pthis = (ONeuronReader* )customObj;
                BaseObject *op = (BaseObject* )(pthis->Get());
                pthis->ReadNeuronBvhData(sender, header, data, op);
            }
              
            // This does nothing other than send a MessageData, which in turn sends a GePluginMessage() to this plugin
            void ONeuronReader::ReadNeuronBvhData(SOCKET_REF sender, BvhDataHeader* header, float* data, BaseObject* op) {
                if (sender) {
                    SpecialEventAdd(MSG_NEURONMESSAGE, 0, (UInt)op);
                }
            }
              
            // Thanks to being called from PluginMessage, this is running in the MainThread (does it even have to?)
            // Attempting to set the LONG parameter to a test value of "40"
            // Value appears to be set correctly, however UI does not change
            void ONeuronReader::ApplyNeuronData(BaseObject *op) {
                if (GeIsMainThread()) {
                    GeConsoleOut("ApplyNeuronData running in MainThread // Modifying:" \+ String::IntToString(NR_FRAMEINDEX));
                    GeData frameIndex;
                    op->GetParameter(NR_FRAMEINDEX, frameIndex, DESCFLAGS_GET_0);
                    GeConsoleOut("Before: " \+ String::IntToString(frameIndex.GetInt32()));
                    op->SetParameter(DescID(NR_FRAMEINDEX), GeData(40), DESCFLAGS_SET_0);
                    op->Message(MSG_CHANGE);
                    EventAdd();
                    op->GetParameter(NR_FRAMEINDEX, frameIndex, DESCFLAGS_GET_0);
                    GeConsoleOut("After: " \+ String::IntToString(frameIndex.GetInt32()));
                }
                else {
                    GeConsoleOut("ApplyNeuronData NOT running in MainThread");
                }
            }
              
            BaseObject* ONeuronReader::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) {
                return BaseObject::Alloc(Onull);
            }
              
            Bool ONeuronReader::Message(GeListNode* node, Int32 type, void* data) {
                BaseContainer* bc;
            ...
                else if (type == MSG_DESCRIPTION_POSTSETPARAMETER)
                {
                    // Get message data
                    DescriptionPostSetValue* dparm = (DescriptionPostSetValue* )data;
                    Int32 parameterId = (*(dparm->descid))[0].id;
                    bc = static_cast<BaseObject*>(node)->GetDataInstance();
                    GeConsoleOut("MSG_DESCRIPTION_POSTSETPARAMETER: " \+ String::IntToString(parameterId));
                    bc->SetInt32(NR_FRAMEINDEX, bc->GetInt32(NR_FRAMEINDEX));
              
                    switch (parameterId)
                    {
                    case NR_FRAMEINDEX:
                        GeConsoleOut("POSTSETPARAMETER_VALUE:" \+ String::IntToString(bc->GetInt32(NR_FRAMEINDEX)));
                        break;
                    }
                }
            ...
                return SUPER::Message(node, type, data);
            }
              
            Bool NeuronMessage::CoreMessage(Int32 id, const BaseContainer& bc)
            {
                switch (id)
                {
                case MSG_NEURONMESSAGE:
                    GeConsoleOut("Demo message");
                    BaseObject* pointer_op = (BaseObject* )bc.GetVoid(BFM_CORE_PAR2);
                    //GeConsoleOut(pointer_op->GetName()); // Just checking...
                    GePluginMessage(MSG_NEURONMESSAGE, (void * )pointer_op);
                }
                return true;
            }
              
            Bool RegisterNeuronReaderObject() {
                return RegisterObjectPlugin(ID_NEURONREADER, GeLoadString(IDS_NEURONREADER), OBJECT_GENERATOR, ONeuronReader::Alloc, "Oneuronreader", AutoBitmap("atom.tif"), 0);
            }
              
            Bool PluginMessage(Int32 id, void *data)
            {
                switch (id)
                {
                    case C4DPL_INIT_SYS:
                        if (!resource.Init())
                            return false;       // don't start plugin without resource
                        return true;
              
                    case MSG_NEURONMESSAGE:
                        if (GeIsMainThread()) {
                            GeConsoleOut("IS MainThread");
                            ONeuronReader* op = (ONeuronReader* )data;
                            //GeConsoleOut(op->GetName()); // just to confirm it is the correct pointer
                            op->ApplyNeuronData((BaseObject* )op);
                        }
                        else {
                            GeConsoleOut("NotMainThread");
                        }
                }
                return false;
            }
            
            1 Reply Last reply Reply Quote 0
            • CJtheTigerC CJtheTiger referenced this topic on
            • First post
              Last post