Mograph(cloner)



  • On 20/09/2013 at 20:28, xxxxxxxx wrote:

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

    ---------
    How can I get Mograph particle count from Cloner object?



  • On 21/09/2013 at 09:37, xxxxxxxx wrote:

    #include "..\..\..\..\modules\mograph\res\description\mglineararray.h"  
      
      
      BaseObject *obj = doc->GetActiveObject();  
      if (!obj) return FALSE;  
      
      if(obj->IsInstanceOf(1018544))   //If it's a cloner object  
      {  
          GeData d;  
          obj->GetParameter(DescID(MG_LINEAR_COUNT),d, DESCFLAGS_GET_0);  
          LONG count = d.GetLong();  
          GePrint(LongToString(count));  
      }
    

    -ScottA



  • On 21/09/2013 at 10:28, xxxxxxxx wrote:

    Modata has also the GetCount() method.



  • On 21/09/2013 at 11:55, xxxxxxxx wrote:

    ^That's true.
    However. I could not find anywhere in the docs how to do that.
    Specifically. I couldn't find the type for a cloner object.
    So I used the cloner's container to get the number of clones.

    In Coffee & Python we can simply do something like this to get the Modata: var md = GeGetMoData(op);

    But in C++. We have to use type casting to switch from BaseObject to the object's type. And I couldn't find the type for the cloner anywhere in the docs. Just it's ID.
    All I could find in the docs was how to create the Modata from scratch: AutoAlloc<MoData> md;
    But this is useless without knowing how to point it a specific cloner object.

    If you know what the type is I'd love to know. Because I couldn't find it.
     
    -ScottA



  • On 21/09/2013 at 13:03, xxxxxxxx wrote:

    Shouldn't it work with c4datom.Message() the msg ID MSG_GET_MODATA and the 
    GetMoDataMessage struct? Not sure what you do mean with casting in that context, 
    as Modata has no relation to BaseObject. But then again my cpp is still pretty bad.



  • On 21/09/2013 at 14:03, xxxxxxxx wrote:

    Hi, ScottA,littledevil

    I agree with ScottA.
    Actually, in this time, I decided to use GetCache().
    Then, counting manually use GetNext() to get count of Generator.

    -elasticmind



  • On 21/09/2013 at 14:14, xxxxxxxx wrote:

    I don't know LD.
    I'm not 100% certain that we have to do it that way for a cloner. Just a guess.
    A BaseObject doesn't have a MoData method. Or a method that accepts a struct of Modata information. That's why I'm guessing that it needs to be cast to a type that can handle MoData stuff.
    That's how it's done for other things (points, polygons, weight tags, etc...)

    I could not find any information at all in the docs on how to get the MoData values from the cloner object. Which is really the most important part of the whole process.
    It seems like the documentation is targeted mostly towards people making effector plugins. And not the cloner object itself.

    I don't even know if there is any real benefit to getting the Modata from a cloner object?
    Is there anything you'd get from accessing the Modata directly that you can't get from accessing the cloner's container?

    -ScottA



  • On 22/09/2013 at 01:10, xxxxxxxx wrote:

    The number of clones is not necessarily stored in the MG_LINEAR_COUNT parameter, Scott. Eg. if the
    cloner is in Object, Radial or Grid mode. Using the MoData you can reliably retrieve the number of clones
    in the cloner object.

    As littledevil stated, you can use the MSG_GET_MODATA message to retrieve the MoData of a cloner.
    There is no wrapper class for MoGraph objects, the message system is used very intensively here.

    Best,
    -Niklas



  • On 22/09/2013 at 08:09, xxxxxxxx wrote:

    Can you show a small example of this Nik?
    The docs do not offer much help on this.

    Creating the struct is fairly simple. But I can't figure out how to plug the object into it.

        GetMoDataMessage gmdm = GetMoDataMessage();    //The struct  
      gmdm.index = 0;                                //The first Modata instance  
      LONG cloneCount = gmdm.modata->GetCount();     //The Modata message  
      
      obj->Message(MSG_GET_MODATA, &gmdm);    //<---Wrong!!...How do we plug the specific cloner object into the struct?  
      GePrint(LongToString(cloneCount));
    

    -ScottA



  • On 22/09/2013 at 08:43, xxxxxxxx wrote:

    You are supposed to pass a pointer to the GetMoDataMessage struct to the Message() function. This
    is why your code fails. On the second account, if your code would compile, it would crash because
    gmdm.modata is uninitialized.

    GetMoDataMessage data;
    obj->Message(MSG_GET_MODATA, &data);
    LONG count = 0;
    if (data.modata) count = data.modata->GetCount();
      
    // ...
      
    if (data.user_owner) MoData::Free(data.modata);
    

    Where obj of course is the cloner object.



  • On 22/09/2013 at 09:05, xxxxxxxx wrote:

    Thanks,
    But that code always results in zero clones for me.
    Have you tested this yourself?

    -ScottA



  • On 26/09/2013 at 09:19, xxxxxxxx wrote:

    Can we please not just sweep this one under the rug and walk away from it?
    Mograph is a major part of C4D. And this is far too important to just walk away from it unsolved.

    Could you please ask the developers how to access the cloner?

    Thanks,
    -ScottA



  • On 08/11/2013 at 10:09, xxxxxxxx wrote:

    Hello, I've been looking same thing as Scott.  Is there any chance we can get word on this please?

    Dan



  • On 10/11/2013 at 04:42, xxxxxxxx wrote:

    Hi Scott,

    at what point did you try to retrieve the MoData? From a Command plugin? I just tried it from a
    CommandData plugin and it didn't work. I have contacted the devs to clarify at what point it is
    should be possible to retrieve the MoData as the documentation doesn't state much about it.

    Best,
    -Niklas



  • On 10/11/2013 at 08:19, xxxxxxxx wrote:

    Hi Nik,

    Yes. I was using it in a command data type plugin.
    I could never get it to work properly.

    -ScottA



  • On 11/11/2013 at 11:19, xxxxxxxx wrote:

    Got the answer. The message needs to be sent to the MoData Tag of the Cloner/Matrix object. This
    information will be added to the docs.

    > class Command : public CommandData {
    >
    >
    >
    >
    > public:
    >
    >
    >
    >
    >     virtual Bool Execute(BaseDocument* doc) {
    >
    >         BaseObject* op = doc->GetActiveObject();
    >
    >         if (!op) return true;
    >
    >
    >
    >
    >         /* Find the MoData tag. */
    >
    >         BaseTag* tag = op->GetTag(ID_MOTAGDATA);
    >
    >         if (!tag) return true;
    >
    >
    >
    >
    >         /* Retrieve the MoData. */
    >
    >         GetMoDataMessage msg_data;
    >
    >         if (!tag->Message(MSG_GET_MODATA, &msg_data)) {
    >
    >             GePrint("MSG_GET_MODATA message failed.");
    >
    >             return true;
    >
    >         }
    >
    >         if (!msg_data.modata) {
    >
    >             GePrint("MSG_GET_MODATA did not return a MoData pointer.");
    >
    >             return true;
    >
    >         }
    >
    >
    >
    >
    >         Int32 count = msg_data.modata->GetCount();
    >
    >         String message = "Got MoData with " + String::IntToString(count) + " particles. It is ";
    >
    >         if (msg_data.user_owned) message += "user owned.";
    >
    >         else message += "owned by the object.";
    >
    >         GePrint(message);
    >
    >
    >
    >
    >         if (msg_data.user_owned) {
    >
    >             MoData::Free(msg_data.modata);
    >
    >         }
    >
    >         return true;
    >
    >     }
    >
    >
    >
    >
    > };

    Best,
    -Niklas



  • On 11/11/2013 at 13:09, xxxxxxxx wrote:

    Thanks Nik. That helps a lot! 👍
    But I still can't figure out how to get at a specific clone from it.

        BaseObject *clonerObj = doc->SearchObject("Cloner");  
      if (!clonerObj) return true;  
       
      BaseTag *tag = clonerObj->GetTag(ID_MOTAGDATA);  
      if (!tag) return TRUE;  
      
      GetMoDataMessage msg_data;  
      if (!tag->Message(MSG_GET_MODATA, &msg_data)) return TRUE;  
      
      if (!msg_data.modata) return TRUE;  
      
      LONG count = msg_data.modata->GetCount();   //Get the number of clones from the cloner's "Count" attribute  
      //GePrint(LongToString(count));      
      
      BaseContainer *bc = clonerObj->GetDataInstance();    //Get the cloner's container items  
      bc->SetReal(MG_LINEAR_OBJECT_AMOUNT, 0.75);          //Set the strength value to 75%  
      
        
    /////////////////////////////////////////////////////////////////////////////////////      
    /// Now I want to get a specific clone from the cloner's array  
    /// But How?  
        
      //None of these are getting me a specific clone  
      bc->GetContainerInstance(MODATA_MATRIX);  
      LONG first = msg_data.modata->GetArrayIndex(0);  
      void *marr = msg_data.modata->GetArray(MODATA_MATRIX);
    

    I've only used the coffee&python effectors to access a specific clone.
    Is there a way to do this directly from the Cloner object itself?

    -ScottA



  • On 06/01/2014 at 11:14, xxxxxxxx wrote:

    Sorry for bumping this old thread.
    But I figured out how to get the individual clones from the cloner object. So I figured I should post it since nobody else seems to know how to do it.

    //This is how to get the Modata from the cloner directly. Instead of from the gui's description attributes  
      
    #include "c4d_baseeffectordata.h"  
      
      
      
      //The cloner object  
      BaseObject *clonerObj = doc->SearchObject("Cloner");  
      if (!clonerObj) return true;  
      
      //Get the hidden MoData tag that is on the cloner object  
      BaseTag *tag = clonerObj->GetTag(ID_MOTAGDATA);  
      if (!tag) return true;  
      
      //Retrieve the MoData  
      GetMoDataMessage msg_data;  
      if (!tag->Message(MSG_GET_MODATA, &msg_data))   
      {  
          GePrint("MSG_GET_MODATA message failed.");  
          return true;  
      }  
      
      //Check if the pointer exists  
      if (!msg_data.modata)   
      {  
          GePrint("MSG_GET_MODATA did not return a MoData pointer.");  
          return true;  
      }  
      
      //Get the number of clones from the cloner's "Count" attribute  
      LONG count = msg_data.modata->GetCount();  
      GePrint(LongToString(count));      
      
      
      //Get the positions of the clones in the cloner object  
      MoData *md = msg_data.modata;  
      MDArray<Matrix>mtx = md->GetMatrixArray(MODATA_MATRIX);  
      MDArray<LONG>farr = md->GetLongArray(MODATA_FLAGS);  
      
      //Start from the end of the array and work backwards so we never get index errors  
      for(LONG i = count - 1; i >= 0; --i)  
      {  
          //Only grab the visible clones  
          if (!(farr[i]&MOGENFLAG_CLONE_ON) || (!(farr[i]&MOGENFLAG_DISABLE)))  
          {  
              Vector pos = mtx[i].off;  
              GePrint("X: " + LongToString(pos.x)+ " Y: " + LongToString(pos.y) + " Z: " + LongToString(pos.z));  
          }  
      }  
      
      //Check if the clones are user owned  
      //If they are user_owned then we have to free the memory manually ourselves  
      //Otherwise..C4D will free the memory for us  
      if(msg_data.user_owned)   
      {  
          GePrint("userOwned");  
          MoData::Free(msg_data.modata);  
      }
    

    -ScottA



  • On 06/01/2014 at 13:32, xxxxxxxx wrote:

    You're getting that error because in the SDK example the flags array is defined as an array of LONGs - which you'd expect - but you've defined it as a Matrix array. So the compiler rejects it with the error message you showed. Don't forget to change the call to GetLongArray as well as changing the array type.

    Steve



  • On 06/01/2014 at 13:52, xxxxxxxx wrote:

    Doh!
    Silly me. I fixed the code.

    Thanks Steve,
    ScottA


Log in to reply