Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    Putting Layers Inside of Folders?

    SDK Help
    0
    19
    1.6k
    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 17/08/2014 at 13:25, xxxxxxxx wrote:

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

      ---------
      This is probably a long shot.
      But does anyone know how (or if it's possible) to put image layers inside of custom folders we add ourselves?
      I've spent the day learning how to create custom image layers and set up the various options for them. But I can't figure out how to put the layers inside the folders I add.

      //This code copies a bitmap source image and creates a new one using a MultipassBitmap()  
      //Then it adds a new layer to it and sets the various layer options  
        
      Bool SimplePlugin::Execute(BaseDocument *doc)  
      {  
        //The path to the image we want to copy  
        Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg";  
        if(!GeFExist(fn, FALSE)) return FALSE;  
        
        //Put the image into a newBaseBitmap object  
        AutoAlloc<BaseBitmap> sourceImage;  
        sourceImage->Init(fn);   
        
        //Create a new MultipassBitmap using the sourceImage BaseBitmap's data  
        AutoFree<MultipassBitmap> clonedImg = MultipassBitmap::AllocWrapper(sourceImage);  
        clonedImg->Init(fn);  
        
        clonedImg->AddFolder(NULL, FALSE);  //<---How do I put the new layer below insde of this new folder?  
        
        //Save the multilayer image with a new alpha layer so that we can draw on top of the orignal image without destroying it  
        clonedImg->AddLayer(NULL, COLORMODE_ARGBf, FALSE);  
        
        //Retrieve a specific layer  
        LONG layercount = clonedImg->GetLayerCount();  
        //GePrint(LongToString(layercount));  
        
        //ID#s are from ..\..\..\..\resource\res\description\bplayer.h  
        MultipassBitmap *layer = clonedImg->GetLayerNum(0); if(!layer) return FALSE;  
        layer->SetParameter(MPBTYPE_NAME, "My First New Layer");  
        layer->SetParameter(MPBTYPE_BLENDMODE, LAYER_MULTIPLY);   //Sets the blend mode  
        layer->SetParameter(MPBTYPE_PERCENT, 0.5);                //Sets the layer's opacity value  
        layer->SetParameter(MPBTYPE_USERID, 123456);              //Assigns a userID to the layer  
        layer->SetParameter(MPBTYPE_SAVE, TRUE);                  //Saves the layer  
        
        LONG colmode = layer->GetParameter(MPBTYPE_COLORMODE).GetLong();  
        GePrint(LongToString(colmode));  
        LONG DPI = layer->GetParameter(MPBTYPE_DPI).GetLong();  
        GePrint(LongToString(DPI));  
        
        clonedImg->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER);  
        
        
        EventAdd();  
        return TRUE;  
      }
      

      -ScottA

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

        On 17/08/2014 at 13:54, xxxxxxxx wrote:

        from documentation "BTW I don't know anything about the code you posted 😄 , I just searched google for "MultipassBitmap" and it showed the SDK link

          `MultipassBitmap`[URL-REMOVED]\* `AddLayer`[URL-REMOVED](`MultipassBitmap`[URL-REMOVED]\* insertafter, `COLORMODE`[URL-REMOVED] colormode, Bool hidden = false);
          `MultipassBitmap`[URL-REMOVED]\* `AddFolder`[URL-REMOVED](`MultipassBitmap`[URL-REMOVED]\* insertafter, Bool hidden = false);
        
        from this I see that the return of AddFolder is the first argument of AddLayer
        this is all a "guess" so it may be wrong
        

        [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

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

          On 17/08/2014 at 13:56, xxxxxxxx wrote:

          correction to previous post:
          here is what I think now

            `MultipassBitmap`[URL-REMOVED]\* mFolder = clonedImg->AddFolder(NULL, FALSE);  
          
            mFolder->AddLayer(NULL, COLORMODE_ARGBf, FALSE);
          

          [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

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

            On 17/08/2014 at 15:43, xxxxxxxx wrote:

            Thanks. That helps a lot.
            I guess we have to treat layers and folders as MultipasBitamp objects.

            Everything works good now. But I can't seem to figure out how to free the memory correctly.
            This code causes a memory leak and I cannot make it let go no matter what I try:

              
            AutoFree<MultipassBitmap> clonedImg = MultipassBitmap::AllocWrapper(sourceImage);  
            clonedImg->Init(fn);
            

            Here's the full code:

            Bool SimplePlugin::Execute(BaseDocument *doc)  
            {  
              //The path to the image we want to copy  
              Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg";  
              if(!GeFExist(fn, FALSE)) return FALSE;  
              
              //Put the image into a newBaseBitmap object  
              AutoAlloc<BaseBitmap> sourceImage;  
              sourceImage->Init(fn);  
              
              //Create a new MultipassBitmap using the sourceImage BaseBitmap's data  
              AutoFree<MultipassBitmap> clonedImg = MultipassBitmap::AllocWrapper(sourceImage);  
              clonedImg->Init(fn);  
              
              //Create a new layer folder  
              MultipassBitmap *myFolder = clonedImg->AddFolder(NULL, FALSE);  
              myFolder->SetParameter(MPBTYPE_NAME, "My Folder");  
              
              //Create a new layer in the new folder so that we can draw on top of the orignal image without destroying it  
              myFolder->AddLayer(NULL, COLORMODE_ARGBf, FALSE);  
              
              
              
              //Retrieve a specific layer  
              //NOTE: ID#s are from ..\..\..\..\resource\res\description\bplayer.h  
              
              LONG layercount = myFolder->GetLayerCount();  
              //GePrint(LongToString(layercount));  
               
              MultipassBitmap *layer = myFolder->GetLayerNum(0); if(!layer) return FALSE;  
              layer->SetParameter(MPBTYPE_NAME, "My First New Layer");  
              layer->SetParameter(MPBTYPE_BLENDMODE, LAYER_MULTIPLY);   //Sets the blend mode  
              layer->SetParameter(MPBTYPE_PERCENT, 0.5);                //Sets the layer's opacity value  
              layer->SetParameter(MPBTYPE_USERID, 123456);              //Assigns a userID to the layer  
              layer->SetParameter(MPBTYPE_SAVE, TRUE);                  //Saves the layer  
              
              LONG colmode = layer->GetParameter(MPBTYPE_COLORMODE).GetLong();  
              GePrint(LongToString(colmode));  
              LONG DPI = layer->GetParameter(MPBTYPE_DPI).GetLong();  
              GePrint(LongToString(DPI));  
              
              //Adds another layer and inserts it after the first layer created above  
              myFolder->AddLayer(layer, COLORMODE_ARGBf, FALSE);  
              layer->SetParameter(MPBTYPE_NAME, "My Second New Layer");  
              
              clonedImg->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER);  
                
              GeFree(clonedImg);  
              GeFree(layer);  
              GeFree(myFolder);  
              
              EventAdd();  
              return TRUE;  
            }
            

            Any advice on how to properly free the memory for this thing?

            -ScottA

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

              On 17/08/2014 at 16:13, xxxxxxxx wrote:

              I guess GeFree() is made for another allocation type "from documentation it says GeAlloc()"

              from the class there is a static function:

              static void `Free`[URL-REMOVED](`MultipassBitmap`[URL-REMOVED]\*& bc);
              

              [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

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

                On 17/08/2014 at 16:33, xxxxxxxx wrote:

                I tried that one too.
                But it does not work on AutoFree.

                MultipassBitmap::Free(clonedImg);   //<--Nope Not allowed to use this on AutoFree
                  MultipassBitmap::Free(layer);           //Works
                  MultipassBitmap::Free(myFolder);    //works

                What I don't understand is why the memory needs to be manually freed in the first place?
                In any other usage. Auto is handled by C4D automatically and frees the memory for me.
                But this function is doing something weird: MultipassBitmap::AllocWrapper(sourceImage);

                The leak stops if I remove this line of code:  clonedImg->Init(fn);
                But then the code does not work. And it does not create my custom folder and layers.
                There's something very strange going on with this wrapper.

                -ScottA

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

                  On 17/08/2014 at 16:46, xxxxxxxx wrote:

                  then do it the normal way

                  MultiPassBitmap *clonedImg = MultipassBitmap::AllocWrapper(sourceImage);

                  also don't use AutoAlloc for the sourceImage

                  from documentation:

                  static MultipassBitmap[URL-REMOVED]* AllocWrapper(BaseBitmap[URL-REMOVED]* bmp)_<_h4_>_

                  Allocates a multipass wrapper for bmp. The wrapped bitmap has to stay alive and not be freed until after the allocated wrapper has been freed. The returned multipass wrapper can be modified freely.

                  Ret_<_h5_>_h5>

                  > MultipassBitmap[URL-REMOVED]*
                  >
                  >> The allocated wrapper bitmap, or nullptr if the allocation failed.

                  _Paramete_ <_h5_>_>

                  > BaseBitmap[URL-REMOVED]* bmp
                  >
                  >> Bitmap to wrap. The caller owns the pointed object.
                  >


                  [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

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

                    On 17/08/2014 at 16:49, xxxxxxxx wrote:

                    a question here about "The caller owns the pointed object." , does that mean that clonedImg contains all data of sourceImage and when I free clonedImg it will internally free sourceImage?

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

                      On 17/08/2014 at 17:17, xxxxxxxx wrote:

                      Nope.
                      I tried BaseBitmap *sourceImage = BaseBitmap::Alloc();
                      Still the same problem.

                      The only reason why I'm using that wrapper is because I don't know how to copy the color values from the source image into the new MultipassBitmap object.
                      I've seen some posts where people have used a nested for loop (y,x) with GetPixelCnt() to copy the color values. But I could never get it to work.
                      That's why I'm using the wrapper function.

                      But this stupid wrapper won't let go of the memory it's given. 😠

                      -ScottA

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

                        On 17/08/2014 at 17:35, xxxxxxxx wrote:

                        not sure how you free them, but I guess it should be like this:

                        MultipassBitmap::Free(clonedImg);  
                            MultipassBitmap::Free(layer);          
                            MultipassBitmap::Free(myFolder);  
                            BaseBitmap::Free(sourceImage);

                        try to post your updated code here

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

                          On 17/08/2014 at 17:54, xxxxxxxx wrote:

                          It means that the BaseBitmap passed is owned by the caller and you have to free it.  Anything resulting is owned by whomever they assign it to (probably the class and its free method).

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

                            On 17/08/2014 at 18:17, xxxxxxxx wrote:

                            The problem is coming from clonedImg->Init(fn);

                            -The sourceImage BaseBitmap gets the color values from the file(fn).
                            -After I wrap the sourceImage BaseBitmap into the MultipassBitmap *clonedImg. I'm expecting the clonedImg to inherit that color info from sourceImage.
                            But if I try to add folders and layers to it. It does nothing.
                            It's as if MultipassBitmap *clonedImg does not exist.

                            But when I add clonedImg->Init(fn); to re initialize the wrapped clonedImg. Somehow it forces it to become a real thing that I can add layers and folders to it.
                            So whatever is going on with the wrapper. It's not doing what I expected. And by using Init(fn) on it. I'm somehow able to cheat and trick it to work. But this "trick" comes with a memory leak error.

                            All I'm trying to do is:
                            -Get an image from a file on my desktop.
                            -Load it into a MultipassBitmap object. So I can then add layers and folders to it.
                            -Then save the image back to another file on my desktop

                            That's it.
                            Should be easy peezy... but it's proving to be a royal pain.

                            -ScottA

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

                              On 17/08/2014 at 18:39, xxxxxxxx wrote:

                              looks weird, but I don't know where the problem lies 😞
                              off topic as I'm stuck in preparing my first plugin, I cloned the SDK, removed what I don't want, then just left a simple example "double circle object"

                              it compiles fine, runs fine, I can create the object and play with it, but for some reason the whole description doesn't appear "can't see radius, interpolation, ..."

                              what am I missing?

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

                                On 17/08/2014 at 19:14, xxxxxxxx wrote:

                                ^I can't help much with that plugin problem because I don't make plugins that way.
                                I hate doing it that way. Because it's too easy to delete something important. Which is probably what you've done.

                                I build my plugins from scratch. Without the api loaded in the solution.
                                I don't do that whole copy &delete stuff.
                                I'm a rebel.!Wink[URL-REMOVED]

                                -ScottA


                                [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

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

                                  On 17/08/2014 at 20:53, xxxxxxxx wrote:

                                  Lol. Check this out.
                                  I figured out how to copy the colors over without using that crazy wrapper method. And look what other insanity pops up in my face to deal with.

                                  Bool SimplePlugin::Execute(BaseDocument *doc)  
                                  {  
                                    //The path to the image we want to copy  
                                    Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg";  
                                    if(!GeFExist(fn, FALSE)) return FALSE;  
                                    
                                    //Put the image into a BaseBitmap object  
                                    AutoAlloc<BaseBitmap> sourceImage;  
                                    //BaseBitmap *sourceImage = BaseBitmap::Alloc();  
                                    sourceImage->Init(fn);  
                                    
                                    //Create a new MultipassBitmap using the sourceImage BaseBitmap's data  
                                    MultipassBitmap *clonedImg = MultipassBitmap::Alloc(sourceImage->GetBw(), sourceImage->GetBh(), COLORMODE_ARGBf);  
                                    
                                    //loop through the source image and copy the color values to the MultipassBitmap *clonedImg  
                                    UCHAR *buffer = GeAllocType(UCHAR, 3*sourceImage->GetBw());  
                                    for (LONG y=0; y<sourceImage->GetBh(); y++)  
                                    {  
                                        sourceImage->GetPixelCnt(0,y, sourceImage->GetBw(), buffer, COLORBYTES_RGB, COLORMODE_RGB, PIXELCNT_0);      
                                        clonedImg->SetPixelCnt(0,y, sourceImage->GetBw(), buffer, 3, COLORMODE_RGB, PIXELCNT_0);  
                                    }  
                                    
                                    
                                    //At this point it works with zero memmory leaks..hurray!!!  
                                    //Problems solved right?....Dream on Scott...Now we get a new problem to deal with  
                                    
                                    //Check out what happens when I add a new layer to it  
                                    //sure..it's adds the new layer fine...But...it also makes the base layer with the copied colors HIDDEN!!!!????:angry:  
                                    //Why on earth does it make the thebase image Hidden!!!  
                                    clonedImg->AddLayer(NULL, COLORMODE_ARGBf, FALSE);   
                                    
                                    clonedImg->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER);  
                                    
                                    //Free the memory  
                                    MultipassBitmap::Free(clonedImg);  
                                    GeFree(buffer);  
                                    
                                    EventAdd();  
                                    return TRUE;  
                                  }
                                  

                                  If you don't add any folders or layers. The base image is not set as hidden as expected.
                                  But if you add layers of folders to the MultipassBitmap. Poof! It sets the base image to hidden!
                                  Whuuut?😵

                                  Is Peter Funt going to jump out and say "Smile...you're on Candid Camera"

                                  -ScottA

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

                                    On 18/08/2014 at 09:04, xxxxxxxx wrote:

                                    After a nights sleep and a fresh brain. I attacked this thing again conquered it.
                                    There's a bug (or a feature as the devs would probably call it 😂) that turns the visibility of the BG layer off when we add a layer or folder. But I found a way to turn it back on.

                                    Here's the full working example with no memory leaks.

                                    //This code copies a bitmap source image and creates a new one using a MultipassBitmap()  
                                    //Then it adds a new layer to it and sets the various layer options  
                                      
                                    Bool SimplePlugin::Execute(BaseDocument *doc)  
                                    {  
                                      //The path to the image we want to copy  
                                      Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg";  
                                      if(!GeFExist(fn, FALSE)) return FALSE;  
                                      
                                      //Put the image into a BaseBitmap object  
                                      AutoAlloc<BaseBitmap> sourceImage;  
                                      sourceImage->Init(fn);  
                                      
                                      //Convert the sourceImage bitmap into a new MultipassBitmap using the sourceImage BaseBitmap's data  
                                      MultipassBitmap *sourceToMpb = MultipassBitmap::Alloc(sourceImage->GetBw(), sourceImage->GetBh(), COLORMODE_ARGBf);  
                                      
                                      //Loop through the source image and copy the colors to the MultipassBitmap *sourceToMpb so we can add layers and folders to it later on  
                                      UCHAR *buffer = GeAllocType(UCHAR, 3*sourceImage->GetBw());  
                                      for (LONG y=0; y<sourceImage->GetBh(); y++)  
                                      {  
                                          sourceImage->GetPixelCnt(0,y, sourceImage->GetBw(), buffer, COLORBYTES_RGB, COLORMODE_RGB, PIXELCNT_0);      
                                          sourceToMpb->SetPixelCnt(0,y, sourceImage->GetBw(), buffer, 3, COLORMODE_RGB, PIXELCNT_0);  
                                      }  
                                      
                                      ///////////////////////////////////////////////////////////////////////////////////  
                                      //Ok STOP!!...  
                                      //When we add our first layer or folder. C4D for some God-for-saken reason turns the background layer's visibilty off!!  
                                      //So we have to make sure that we turn it back on using MPBTYPE_SHOW!!!!  
                                      ///////////////////////////////////////////////////////////////////////////////////  
                                      
                                        
                                      //Create a new layer folder  
                                      MultipassBitmap *myFolder = sourceToMpb->AddFolder(NULL, FALSE);  
                                      myFolder->SetParameter(MPBTYPE_NAME, "My Folder");  
                                      
                                      //Now lets go back and turn on the visibilty for the background layer (Yeah..it's lame and probably a bug)  
                                      //Reminder: Layer 0 is the topmost layer. So the BGLayer is currently on layer1  
                                      MultipassBitmap *bgLayer = sourceToMpb->GetLayerNum(1);  
                                      bgLayer->SetParameter(MPBTYPE_SHOW, TRUE);  
                                      
                                      //Now create a new layer in the new folder so that we can draw on top of the orignal image without destroying it  
                                      myFolder->AddLayer(NULL, COLORMODE_ARGBf, FALSE);  
                                      
                                      
                                      //Retrieve a specific layer  
                                      //NOTE: ID#s are from ..\..\..\..\resource\res\description\bplayer.h  
                                      
                                      //LONG layercount = myFolder->GetLayerCount();  
                                      //GePrint(LongToString(layercount));  
                                       
                                      MultipassBitmap *layer1 = myFolder->GetLayerNum(0); if(!layer1) return FALSE;  
                                      layer1->SetParameter(MPBTYPE_NAME, "My First New Layer");  
                                      layer1->SetParameter(MPBTYPE_BLENDMODE, LAYER_MULTIPLY);   //Sets the blend mode  
                                      layer1->SetParameter(MPBTYPE_PERCENT, 0.5);                //Sets the layer's opacity value  
                                      layer1->SetParameter(MPBTYPE_USERID, 123456);              //Assigns a userID to the layer  
                                      layer1->SetParameter(MPBTYPE_SAVE, TRUE);                  //Saves the layer  
                                      
                                      LONG colmode = layer1->GetParameter(MPBTYPE_COLORMODE).GetLong();  
                                      GePrint(LongToString(colmode));  
                                      LONG DPI = layer1->GetParameter(MPBTYPE_DPI).GetLong();  
                                      GePrint(LongToString(DPI));  
                                      
                                      //Adds another layer and inserts it after the first layer created above  
                                      MultipassBitmap *layer2 = myFolder->AddLayer(layer1, COLORMODE_ARGBf, FALSE);  
                                      layer2->SetParameter(MPBTYPE_NAME, "My Second New Layer");  
                                      
                                      sourceToMpb->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER);  
                                      
                                      //Free the memory  
                                      MultipassBitmap::Free(sourceToMpb);  
                                      GeFree(buffer);  
                                      
                                      EventAdd();  
                                      return TRUE;  
                                    }
                                    

                                    -ScottA

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

                                      On 18/08/2014 at 09:32, xxxxxxxx wrote:

                                      it seems like a feature for dynamic UI, so when you add a new layer it collapses old stuff

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

                                        On 18/08/2014 at 09:40, xxxxxxxx wrote:

                                        Maybe.

                                        I'm probably doing a task with it that the developers never considered when writing the SDK functions.
                                        I'm just glad they wrote the MPBTYPE_SHOW option. I would have been screwed without it.

                                        -ScottA

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

                                          On 18/08/2014 at 09:46, xxxxxxxx wrote:

                                          🙂 , I have also found the problem in my first plugin res problems xD

                                          check your messages Scotta

                                          1 Reply Last reply Reply Quote 0
                                          • First post
                                            Last post