Make Editable example [SOLVED]



  • On 27/03/2015 at 12:18, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R16 
    Platform:      Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    Hi,

    I've searched the forum for each make editable-post.
    I've applied all the examples I could find, but always got bugs.
    Never got some build errors, only C4D bug splat errors or C4D quitting...

    So, could somebody provide me with a simple example on how to make a cube, and make it editable??

    This would help me greatly, I guess..

    Thanks for your help and time!
    Greetings,

    Casimir Smets



  • On 28/03/2015 at 10:24, xxxxxxxx wrote:

    It's very simple: use GeneratePrimitive() to create the cube, then SendModelingCommand() with MCOMMAND_MAKEEDITABLE to collapse it. Finally, free up the primitive you created, or you'll get a memory leak.

    Steve



  • On 30/03/2015 at 07:10, xxxxxxxx wrote:

    Well, I found this out now, but, when you use GeneratePrimitive, it gives allready an editable object, eg. a Polygon object. That's what I need. My next question is, how do you set the Y segments?

    I've tried bb->SetInt32(PRIM_CUBE_SUBY, 2); where bb is a basecontainer, but this doesn't seem to do anything, or I'm calling it wrong.

    Greetings,
    Casimir Smets



  • On 30/03/2015 at 07:25, xxxxxxxx wrote:

    GeneratePrimitive returns a primitive. Here's a complete working example - in this case, called from GetVirtualObjects() of an ObjectData plugin, but it doesn't have to be:

    BaseObject* MyClass::CreateCube(HierarchyHelp *hh)   
    {   
         BaseObject *cube = nullptr;   
         BaseContainer bc;   
      
         bc.SetVector(PRIM_CUBE_LEN, Vector(100.0));   
         bc.SetLong(PRIM_CUBE_SUBX, 1);   
         bc.SetLong(PRIM_CUBE_SUBY, 1);   
         bc.SetLong(PRIM_CUBE_SUBZ, 1);   
         cube = GeneratePrimitive(NULL, Ocube, bc, hh->GetLOD(), FALSE, hh->GetThread());   
      
         return cube;   
    }
    

    Steve



  • On 31/03/2015 at 05:56, xxxxxxxx wrote:

    If I try your code, Cinema 4D quits again...

    I've tried to change it to:

      
    BaseContainer* bb = op->GetDataInstance();  
    bb->SetInt32(PRIM_CUBE_SUBY, 2);  
    BaseObject* cube = GeneratePrimitive(doc, Ocube, *bb, 0, false, nullptr);  
    doc->InsertObject(cube, parent, NULL);  
    

    But this doesn't set the Y segments, just places the cube..

    Greetings,
    Casimir Smets



  • On 31/03/2015 at 12:10, xxxxxxxx wrote:

    I've changed it a bit:

      
    BaseContainer* bb = op->GetDataInstance();  
    BaseContainer bc;  
    bc.SetInt32(PRIM_CUBE_SUBY, 2);  
    PolygonObject* cube = (PolygonObject* )GeneratePrimitive(doc, Ocube, bc, 0, false, nullptr);  
    cube->SetRelPos(Vector(4 + bb->GetInt32(WIDTH) / 2, 0, 0));  
    cube->SetName("MyCube");  
    doc->InsertObject(cube, parent, NULL);  
    EventAdd();  
    cube->Message(MSG_UPDATE);  
      
    Int32 pcnt = cube->GetPointCount();  
    GePrint(String::IntToString(pcnt));  
    

    So that now I get an output of how many points I have in my cube.
    It gives me just 8 points, instead of the 12 that I want (subdivision in Y).

    It seems like bc.SetInt32(PRIM_CUBE_SUBY, 2); does nothing.

    Does anybody see the problem here?
    Thanks for much needed help! :D

    Greetings,
    Casimir Smets



  • On 02/04/2015 at 01:15, xxxxxxxx wrote:

    Hi Casimir,

    I suppose you are writing a object generator plugin. Then you can use the following code in GetVirtualObjects() :

    BaseObject *MyObject::GetVirtualObjects(BaseObject *op, HierarchyHelp *hh)
    {
      BaseObject* const cube = BaseObject::Alloc(Ocube);
      if (!cube)
        return nullptr;
      cube->SetName("My Cube");
      cube->SetRelPos(Vector(0.0));
      // set object parameters
      BaseContainer* const bc = cube->GetDataInstance();
      bc->SetVector(PRIM_CUBE_LEN, Vector(100.0));
      bc->SetInt32(PRIM_CUBE_SUBX, 1);
      bc->SetInt32(PRIM_CUBE_SUBY, 2);
      bc->SetInt32(PRIM_CUBE_SUBZ, 3);
      return cube;
    }
    


  • On 02/04/2015 at 05:13, xxxxxxxx wrote:

    Hi Andreas,

    Thanks for your answer!
    But, this doesn't give me an editable object, which I want.

    I first used this approach, and then set my object to the active object and send the make editable command, but that didn't work.

    After that, I thought about just making a primitive cube (which is allready a polygonobject, eg, editable) and setting the SUBY to 2. Making the cube was no problem, but the SUBY was never set to 2.

    Also I really need the object to be a polygonobject instead of a baseobject, because I have to change points later on.

    Could you please provide me with the information to: make the baseobject editable and get a polygonobject. Or: fix the SetInt32 for my SUBY.?

    The code I use to generate my primitive is the last code posted by me.

    Thanks for your help and time!
    Greetings,

    Casimir Smets



  • On 02/04/2015 at 07:31, xxxxxxxx wrote:

    Hi Casimir,

    I'm terribly sorry, somehow I got distracted and then I forgot your initial request.
    This is what it looks like, to get an polygon object:

    BaseObject *MyObject::GetVirtualObjects(BaseObject *op, HierarchyHelp *hh)
    {
      BaseObject* cube = BaseObject::Alloc(Ocube);
      if (!cube)
        return nullptr;
      cube->SetName("My Cube");
      cube->SetRelPos(g_fSizeAtom * Vector(0.0));
      // set object parameters
      BaseContainer* const bc = cube->GetDataInstance();
      if (!bc)
      {
        BaseObject::Free(cube);
        return nullptr;
      }
      bc->SetVector(PRIM_CUBE_LEN, Vector(100.0));
      bc->SetInt32(PRIM_CUBE_SUBX, 1);
      bc->SetInt32(PRIM_CUBE_SUBY, 2);
      bc->SetInt32(PRIM_CUBE_SUBZ, 3);
      
      ModelingCommandData  cd;
      
      cd.doc = hh->GetDocument();
      cd.op = cube;
      if (SendModelingCommand(MCOMMAND_CURRENTSTATETOOBJECT, cd))
      {
        BaseObject::Free(cube);  // don't forget to free the original parametric cube
        return static_cast<BaseObject*>(cd.result->GetIndex(0));
      }
      return cube;
    }
    


  • On 02/04/2015 at 08:23, xxxxxxxx wrote:

    Hi Andreas,

    Thanks for your answer!

    I've tried out the code, yet for me, it doesn't give a cube when I start my plugin.
    Don't you have to insert it in the document or something?

    Also, to get a PolygonObject, shouldn't the return type be a PolygonObject? Or am I misunderstanding that part?

    Also I'd like to store the return value of the modeling command inside a polygon object, so I can alter it afterwards.

    Does anybody have an idea how to do/fix this?
    Thanks for your help and time!

    Greetings,
    Casimir Smets



  • On 02/04/2015 at 08:33, xxxxxxxx wrote:

    Hi Casimir,

    perhaps you can explain a bit more the actual intent, what are you trying to do and why?
    My code indeed returns a PolygonObject (which is derived from BaseObject). No, I don't need to (and nor should I) insert it into the scene, as that's what happens with the result of GetVirtualObjects() anyway. But of course it's still under control of the object generator plugin (as user to another Current State to Object (press C) to see the result. Then try both code versions to see the difference).

    So perhaps my assumption of an object generator plugin is wrong?

    And what do you mean by?

    Also I'd like to store the return value of the modeling command inside a polygon object, so I can alter it afterwards.

    Again, please help me to help you by explaining in more detail, what you are trying to do.



  • On 02/04/2015 at 11:00, xxxxxxxx wrote:

    Hi Andreas,

    Your assumption about an object-generator plugin was right.

    First I should note that I copied the doublecircle-plugin and adjusted it to my needs, since I don't feel I have enough understanding to start from nothing. Because of doing that, I didn't add the function GetVirtualObjects(). Instead, I have GetContour (which is fine for me, because I start with a splinestar), who calls my other object generating functions. -> This could maybe cause the problem.

    Secondly I'm making this plugin for my company, so I can't give too much information about what the plugin needs to do. This said, I'm now working on adding a cube to the scene, giving it 2 segments in the Y-axis. After that, I want to place the points on specific locations, given by user input. (First to generate the object, and again inside Message for if the parameters are changed) Later on I will probably need to put a morph tag on it, which should behave differently on specific situations (probably set in Xpresso).

    This is also the reason I want direct access to the polygon object, probably something like this:

      
    BaseObject* res;  
    PolygonObject* PolyCube;  
        
        
        res = static_cast<BaseObject*>(mcd.result->GetIndex(0));
        
        polyCube = (PolygonObject * )res;
        if(!polyCube) goto Error;
    

    So I could use polyCube->GetPointCount(); etc...

    I hope this is enough information, if not, ask me for more!
    Again thanks in advance for your help and time!!

    Greetings,
    Casimir Smets



  • On 07/04/2015 at 05:34, xxxxxxxx wrote:

    Hi Casimir,

    in my code inside

    if (SendModelingCommand(MCOMMAND_CURRENTSTATETOOBJECT, cd))
    

    there you have the PolygonObject in cd.result->GetIndex(0).
    It is casted to BaseObject in order to return it properly.
    You can simply cast it to a PolygonObject* and from then use GetPolygonR() or GetPolygonW() to get the polygon array. And GetPointR() or GetPointW() to access the point array.
    pretty much like in your last piece of code.



  • On 08/04/2015 at 08:53, xxxxxxxx wrote:

    Hi Andreas,

    Thanks for your answer!
    Still, with my experience, I thought it would be more simple to use the Make Editable command.
    So I did, and now I got it working (I've tried before, with less success).

    For the people wondering how I did it:

      
    BaseContainer* bb = op->GetDataInstance();  
    BaseObject* cube = BaseObject::Alloc(Ocube);  
    if (!cube)  
      return nullptr;  
    cube->SetName("Cube");  
    cube->SetRelPos(Vector(4 + bb->GetInt32(WIDTH) / 2, 0, 0));  
    BaseContainer* const bc = cube->GetDataInstance();  
    bc->SetInt32(PRIM_CUBE_SUBY, 2);  
    doc->InsertObject(cube, parent, NULL);  
    doc->SetActiveObject(cube);  
    CallCommand(12236);  
            
    PolygonObject* polyCube;  
    polyCube = (PolygonObject * )doc->GetActiveObject();  
      
    Int32 pcnt = polyCube->GetPointCount();  
    GePrint(String::IntToString(pcnt));  
    //Used to check if the polygonobject got retrieved  
      
    return polyCube;  
    

    This method gets called inside GetContour (The same method as in DoubleCircle - SDK Example). That's also where I get my doc from.

    You can mark this post as SOLVED.
    Greetings,

    Casimir Smets



  • On 09/04/2015 at 06:53, xxxxxxxx wrote:

    Hi Casimir,

    I need to comment on your solution, as what you are doing there is highly dangerous, actually it is forbidden.
    GetContour() is called in thread context and you are not allowed to do any changes to the scene in this context. Furthermore, I think, the solution (if it would work) is bad for the user, as you are changing the user's selection. Not any user will like this...

    Please note: Changing the active scene from a thread context may seem to work, but the consequences of this error may be manifold and really hard to track.

    I strongly suggest to use my code example. It's really not doing much different than yours, but it should be safe.



  • On 10/04/2015 at 03:28, xxxxxxxx wrote:

    Hi Andreas,

    Thanks for your feedback!
    I'll try to do it the better (your) way.

    But what I'm wondering is, why is the method GetContour() used inside the DoubleCircle SDK example? Doesn't that give threading problems?

    Also, I'm changing the active object again after making it editable. The user also doesn't need to select any objects while working with my plugin, just sliders.

    Greetings,
    Casimir Smets



  • On 10/04/2015 at 03:45, xxxxxxxx wrote:

    Hi Andreas,

    Another quick question: is GetContour() giving the big problem here? Or also the way I'm making my objects? Or is that a matter of personal preference and style?

    Thanks for your time and help!
    Greetings,
    Casimir Smets



  • On 10/04/2015 at 03:58, xxxxxxxx wrote:

    Hi,

    the problem is to call CallCommand() and InsertObject() within GetContour().
    GetContour() is called in a thread context, while CallCommand() and InsertObject() are not allowed to be used in a thread context.



  • On 10/04/2015 at 06:43, xxxxxxxx wrote:

    Hi, me again 😉

    We had some discussion about this thread in our team and perhaps I should add some more info.
    First of all there's an article about threading in the SDK docs: Important Threading Information

    Some more on GetContour(), the same is true for GetVirtualObjects() :
    These functions are only thought to generate a spline or an object (these also may have childs) and then return these. Cinema 4D will handle all the integration into the scene. And as these are called in a thread context, you must never ever do any changes directly to the scene in these functions.

    Finally I completely ignored the "PolygonObject in GetContour" problem. I'm wondering, what you are actually trying to do with this object in GetContour(), as you can't return it and are not allowed to insert it into the scene. The correct place to generate your PolygonObject would rather be GenerateVirtualObjects().



  • On 20/04/2015 at 07:50, xxxxxxxx wrote:

    Hi Andreas,

    Thanks for your information!
    I've tried and tried, but without success.
    Could you maybe provide me with a simple example on how to add a nullobject-child to the cube (parent).

    Also, I'm not allowed to use InsertUnder() inside GetVirtualObjects, right? Or am I wrong?

    Thanks for your help and time!
    Greetings,
    Casimir Smets


Log in to reply