MaterialPreviewCustomGui



  • On 12/08/2015 at 15:20, xxxxxxxx wrote:

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

    ---------
    I have been attempting to create a MaterialPreviewCustomGui object to display a torus. The code does not cause Cinema to crash, but it only results in the preview window being created without the torus. It runs through most of the Switch cases of the Message function from the ObjectPreviewShader, except that it will not run the MATPREVIEW_GENERATE_IMAGE option.

    Code I'm using is below, this was mostly taken from an older post from an earlier version of Cinema.

      
    #define ID_MEMSTAT 200000072  
      
    #include "c4d.h"  
    #include "gradientuserarea.h"  
    #include "c4d_symbols.h"  
    #include "customgui_matpreview.h"  
      
    #define OBJECT_PREVIEW_HOOK_ID     1000001  
    #define OBJECT_PREVIEW_SHADER_ID   1000002  
    #define COMMANDPLUGIN_ID           1000003  
    #define RDATA_RENDERASEDITOR       1000004  
      
      
    //////////////////////////////////////////////////////////////////////////////  
    ///////////// shader class //////////////////////////////////////////////////  
      
    class ObjectPreviewShader : public ShaderData  
    {  
      public:  
            
          virtual Bool Message(GeListNode* node, LONG type, void* data)  
          {  
                
              switch (type)  
              {  
                  case MATPREVIEW_GET_OBJECT_INFO:  
                  {  
                      GePrint("GET_OBJECT_INFO");  
      
                      MatPreviewObjectInfo *info = static_cast<MatPreviewObjectInfo*>(data);  
                      info->bHandlePreview = TRUE;  
                      info->bNeedsOwnScene = TRUE;  
                      info->bNoStandardScene = FALSE;  
                      info->lFlags = MATPREVIEW_FLAG_HIDE_SCENES |  
                                        MATPREVIEW_FLAG_HIDE_ANIMATE |  
                                        MATPREVIEW_FLAG_HIDE_SCENE_SETTINGS |  
                                        MATPREVIEW_FLAG_HIDE_OPEN |  
                                        MATPREVIEW_FLAG_HIDE_SIZE;      
                      break;  
                  }  
      
                  case MATPREVIEW_MODIFY_CACHE_SCENE:  
                  {  
                      GePrint("MODIFY_CACHE_SCENE");  
                      MatPreviewModifyCacheScene *scene = static_cast<MatPreviewModifyCacheScene*>(data);  
      
                      // Kidnap original object...  
                      BaseObject *obj = scene->pDoc->SearchObject("Object");  
                      obj->SetRenderMode(MODE_ON);  
                      obj->SetEditorMode(MODE_ON);  
      
                  // ...and insert our own  
                      AutoAlloc<BaseObject> torus(Otorus);  
                      torus->GetDataInstance()->SetReal(PRIM_TORUS_INNERRAD, 20.0);  
                      torus->GetDataInstance()->SetReal(PRIM_TORUS_OUTERRAD, 60.0);  
                      torus->SetRenderMode(MODE_ON);  
                      torus->SetEditorMode(MODE_ON);  
                      scene->pDoc->InsertObject(torus.Release(), obj, NULL);                          
                        
                      break;  
                  }  
                        
         
                  case MATPREVIEW_PREPARE_SCENE:  
                  {  
      
                      GePrint("PREPARE_SCENE");  
                      MatPreviewPrepareScene* prepare = static_cast<MatPreviewPrepareScene*>(data);  
                      prepare->bScenePrepared = TRUE;  
                      break;  
                  }  
                        
                  case MATPREVIEW_GENERATE_IMAGE:  
                  {  
                      GePrint("GENERATE_IMAGE");  
                        
                      MatPreviewGenerateImage* image = static_cast<MatPreviewGenerateImage*>(data);  
      
                      if (image->pDoc)  
                      {  
                        LONG w = image->pDest->GetBw();  
                        LONG h = image->pDest->GetBh();  
              
                        BaseContainer bcRender = image->pDoc->GetActiveRenderData()->GetData();  
                        bcRender.SetLong(RDATA_XRES, w);  
                        bcRender.SetLong(RDATA_YRES, h);  
                        bcRender.SetLong(RDATA_ANTIALIASING, ANTI_GEOMETRY);  
              
                        if (image->bLowQuality)  
                        {  
                          bcRender.SetBool(RDATA_RENDERASEDITOR, TRUE);  
                        }  
              
                        image->pDest->Clear(0, 0, 0);  
                          image->lResult = RenderDocument(image->pDoc, bcRender, NULL, NULL, image->pDest,  
                          RENDERFLAGS_EXTERNAL | RENDERFLAGS_PREVIEWRENDER, image->pThread);  
                      }  
                        
                      break;  
                  }  
         
                  case MATPREVIEW_GET_PREVIEW_ID:  
                  {  
                      GePrint("GET_PREVIEW_ID");  
                      LONG *id = static_cast<LONG*>(data);  
                      *id = 0;      
                      break;  
                  }  
                        
              }  
      
              return TRUE;  
                
          }  
      
          virtual Vector Output(BaseShader *sh, ChannelData *cd)  { return Vector(1.0, 0.2, 0.0); }  
      
          static NodeData *Alloc(void) { return gNew ObjectPreviewShader; }  
    };  
      
      
    /////////////////////////////////////////////////////////////////////////////////////  
    /////////// SceenHook class ////////////////////////////////////////////////////////  
      
    class ObjectPreviewHook : public SceneHookData  
    {  
      AutoAlloc<BaseShader> shad;  
      
      public:   
          ObjectPreviewHook() : shad(OBJECT_PREVIEW_SHADER_ID) {}  
      
          virtual Bool Init(GeListNode* node)  
          {  
              if(shad)   
              {  
                  static_cast<BaseSceneHook*>(node)->InsertShader(shad);  
              }  
              return TRUE;  
          }  
      
          virtual void Free(GeListNode* node)  
          {  
              shad->Remove();  
          }  
      
          Bool InitPreviewData(MaterialPreviewData* preview_data, LONG dirtyCount)  
          {  
              return preview_data->Init(shad, dirtyCount);  
          }  
      
          static NodeData *Alloc(void) { return gNew ObjectPreviewHook; }  
    };  
      
      
    /////////////////////////////////////////////////////////////////////////  
    ////////// dialog class /////////////////////////////////////////////////  
      
    class ObjectPreviewDialog : public GeDialog  
    {  
      enum  
      {  
      PREVIEW_ID = 1000,  
      GROUP_ID = 1001,  
      MIN_WIDTH = 100,  
      MIN_HEIGHT = 100,  
      };  
      
      private:  
          MaterialPreviewCustomGui *preview;  
          LONG dirtyCount;  
      
      public:  
            
          ObjectPreviewDialog() : preview(NULL), dirtyCount(0) {}  
          virtual void DestroyWindow(){ preview = NULL; }  
          virtual Bool CreateLayout(void);  
          virtual Bool InitValues(void);  
          virtual Bool Command(LONG id,const BaseContainer &msg);  
          void SetPreviewData(LONG dirtyCount);   //A custom method  
    };  
      
    Bool ObjectPreviewDialog::CreateLayout(void)  
    {  
      SetTitle("Preview Gui");  
      
      GroupBegin(GROUP_ID, BFH_FIT | BFV_FIT, 1, 1, "Torus", 0);  
      GroupBorderSpace(2,2,2,2);  
      GroupBorder(BORDER_NONE | BORDER_WITH_TITLE);  
      {  
          BaseContainer settings;  
          settings.SetLong(MATPREVIEW_MIN_WIDTH, MIN_WIDTH);  
          settings.SetLong(MATPREVIEW_MIN_HEIGHT, MIN_HEIGHT);  
          //settings.SetBool(MATPREVIEW_NO_BORDER, TRUE);  
          preview = static_cast<MaterialPreviewCustomGui*>(AddCustomGui(PREVIEW_ID, CUSTOMGUI_MATPREVIEW, "", BFH_FIT | BFV_FIT,SizePix(MIN_WIDTH), SizePix(MIN_HEIGHT), settings));  
      }  
      GroupEnd();  
      
      SetPreviewData(dirtyCount);  
      
      return preview != NULL;  
    }  
      
    Bool ObjectPreviewDialog::InitValues(void)  
    {  
      //First call the parent instance  
      if(!GeDialog::InitValues()) return FALSE;  
      
      if(preview == NULL) return FALSE;  
      preview->SetLayoutMode(LAYOUTMODE_MAXIMIZED);  
        
      return TRUE;  
    }  
      
    Bool ObjectPreviewDialog::Command(LONG id,const BaseContainer &msg)  
    {  
      if(id == PREVIEW_ID)  
      {  
          SetPreviewData(++dirtyCount);  
      }  
      
      return TRUE;  
    }  
      
    //A custom method  
    void ObjectPreviewDialog::SetPreviewData(LONG dirtyCount)  
    {  
      if(preview == NULL) return;  
      
      TriState<GeData> t = preview->GetData();  
      GeData data = t.GetValue();  
      MaterialPreviewData *preview_data =    static_cast<MaterialPreviewData*>(data.GetCustomDataType(CUSTOMDATATYPE_MATPREVIEW));  
      
      if(preview_data)  
      {  
          static_cast<ObjectPreviewHook*>( GetActiveDocument()->FindSceneHook(OBJECT_PREVIEW_HOOK_ID)->GetNodeData())->InitPreviewData(preview_data, dirtyCount);       
          preview_data->SetPreviewSize(MatPreviewSizeDefault);  
          preview_data->SetPreviewType(MatPreviewUser);  
      }  
      
      preview->SetData(data);  
    }  
      
    class MemStatCommand : public CommandData  
    {  
      private:  
          ObjectPreviewDialog dlg;  
          MaterialPreviewCustomGui *preview;  
          LONG dirtyCount;  
      public:  
          virtual Bool Execute(BaseDocument *doc);  
          virtual Bool RestoreLayout(void *secret);  
    };  
      
    Bool MemStatCommand::Execute(BaseDocument *doc)  
    {    
      ObjectPreviewDialog dlg;  
      return dlg.Open(DLG_TYPE_ASYNC, COMMANDPLUGIN_ID, -1, -1, 300, 150);  
    }  
      
    Bool MemStatCommand::RestoreLayout(void *secret)  
    {  
      return dlg.RestoreLayout(ID_MEMSTAT,0,secret);  
    }  
      
    Bool RegisterMemoryStat(void)  
    {  
      RegisterShaderPlugin(OBJECT_PREVIEW_SHADER_ID, "Object Preview", PLUGINFLAG_HIDE, ObjectPreviewShader::Alloc, "", 0);  
      RegisterSceneHookPlugin(OBJECT_PREVIEW_HOOK_ID, "Object Preview", PLUGINFLAG_HIDE, ObjectPreviewHook::Alloc, EXECUTIONPRIORITY_INITIAL, 0, NULL);  
      return RegisterCommandPlugin(ID_MEMSTAT,"Preview GUI",0, AutoBitmap("icon.tif"), String("My Simple Dialog"),gNew MemStatCommand);      
    }  
      
      
    

    I've been looking at this for a while now and any help would be really appreciated.

    Johan



  • On 13/08/2015 at 01:53, xxxxxxxx wrote:

    Hello,

    could you provide some more explanation how your project works? You posted code of a shader, a scene hook, a dialog and a command. How are these element related to each other and to your question?

    One thing that may be a problem is the fact that you catch MATPREVIEW_GET_PREVIEW_ID but you don't set a proper value to "id". You should set this to the ID of the shader parameter representing the MatrialPreviewGUI.

    Best wishes,
    Sebastian



  • On 13/08/2015 at 17:31, xxxxxxxx wrote:

    I'm sorry I wasn't clear with what the problem was. The code I'm using is from a post a year ago about the same topic from ScottA. The code doesn't crash when its run, but it only creates the preview window, it doesn't display the torus object.

    The ObjectPreviewDialog class is responsible for handling the creation of the dialog window and creating the preview window. It also runs the SetPreviewData function that gives the preview its data.
    The line

      static_cast<ObjectPreviewHook*>(GetActiveDocument()->FindSceneHook(OBJECT_PREVIEW_HOOK_ID)->GetNodeData())->InitPreviewData(preview_data, dirtyCount); 
    

    is responsible for calling ObjectPreviewHook class.

    ObjectPreviewShader class is called with

      
    static_cast<BaseSceneHook*>(node)->InsertShader(shad);  
    

    from the ObjectPreviewHook Init(GeListNode* node).

    When the plugin is run the MATPREVIEW_GET_OBJECT_INFO, MATPREVIEW_MODIFY_CACHE_SCENE, and MATPREVIEW_PREPARE_SCENE cases from Message(GeListNode* node, LONG type, void* data) all execute. The MATPREVIEW_GENERATE_IMAGE case does not run.

    This leaves the dialog with only a bordered window. I also tried changing the code with the suggestion of setting the variable id to the proper value in the MATPREVIEW_GET_PREVIEW_ID case and it did not change the results when the plugin is run due to that case not running.

    Johan



  • On 14/08/2015 at 02:15, xxxxxxxx wrote:

    Hello,

    honestly, the approach of your code is quite creative and this is not how a MaterialPreviewGUI is typically used.

    What do you want to achieve in the end? If you just want to display a rendering of an object in your dialog the most simple way to do this would be to render a virtual document using RenderDocument() and to display the result image using a GeUserArea.

    Also, in your MemStatCommand class you have a member variable ObjectPreviewDialog dlg but also a local variable ObjectPreviewDialog dlg in Execute(). This local variable is shadowing the member variable so that only the local dialog is shown (and becoming invalid after Execute() is left).

    Best wishes,
    Sebastian



  • On 14/08/2015 at 10:43, xxxxxxxx wrote:

    Hi,

    I can't seem to find the original thread about this anymore. I'm having trouble getting back to those old posts.
    But I still have my R13 source files hosted on my google sites account.
    https://sites.google.com/site/scottayersmedia/Material Preview GUI R13.zip

    If anyone is interested in this. The source files should compile without any problems for people still set up to compile Windows R13 plugins.
    But as stated above. I could not get it to display the scene objects in the window.
    The old thread about this was written in R12 code. And I couldn't manage to convert it properly from what was posted there.

    -ScottA

    P.S. - I'm finally back on line with a new ISP. But I probably won't be doing any C4D stuff for a while.
    I've got a ton of other things to catch up on first.



  • On 18/08/2015 at 14:16, xxxxxxxx wrote:

    I really appreciate the help Sebastian, sorry for the late reply.

    For a while I've been using my own render document that I then use as part of the RenderDocument function. The bitmap that I get from this is then placed in a BitmapButtonCustomGui. Right now the purpose of this is to take a selected material and give the user an idea of what it would like on an object. This has worked well for me so far but I'm trying find a method that offers more functionality than this, something closer to the render window of the material editor.

      
    BaseBitmap *render;  
    render = BaseBitmap::Alloc();  
    render->Init(300, 300);  
    RenderDocument(renderdocument, container, NULL, NULL, render, RENDERFLAGS_EXTERNAL, NULL);   
    BitmapButtonCustomGui* myButton;  
                   
    BaseContainer bbc;  
                   
    LONG bordertouse =0;  
                   
                   
    bbc.SetLong(BITMAPBUTTON_BORDER, bordertouse);   
    bc.SetBool(BITMAPBUTTON_BUTTON, FALSE);  
      
    myButton = (BitmapButtonCustomGui* )AddCustomGui(idRenderImage,CUSTOMGUI_BITMAPBUTTON,"MY BUTTON", 0L,0,0,bbc);  
    bbc.SetLong(BITMAPBUTTON_TOGGLE, FALSE);  
    myButton->SetImage(bmp, TRUE);  
    

    I tried using a GeUserArea in place of the BitmapButtonCustomGui with my previous code. This only creates the GeUserArea, it doesn't insert the bitmap.

      
    BaseBitmap *render;  
    render = BaseBitmap::Alloc();  
    render->Init(300, 300);  
    RenderDocument(renderdocument, container, NULL, NULL, render, RENDERFLAGS_EXTERNAL, NULL);   
      
    GeUserArea renderArea;  
    renderArea.Init();  
    renderArea.Sized(400, 400);  
    renderArea.DrawBitmap(render, 0, 0, render->GetBw(), render->GetBh(), 0, 0, render->GetBw(), render->GetBh(), BMP_NORMALSCALED);  
                    
      
    AddUserArea(1000, BFV_CENTER, 500, 250);  
    AttachUserArea(renderArea, 1000, USERAREA_0);  
    renderArea.Redraw();  
    

    I've looked at some of the other posts that deal with GeUserArea and no one else seems to be having this problem.

    Johan



  • On 18/08/2015 at 22:00, xxxxxxxx wrote:

    Hi Johan,

    the user area is typically added into a dialog's CreateLayout() function. The user area is usually a class-level object in your dialog, which you've derived from the GeUserArea class itself. E.g:

      
    class My_User_Area : public GeUserArea   
    {   
    private:   
      
       BaseBitmap *bmp;   
      
    public:   
      
       ...list of GeUserArea functions you're overriding...   
       virtual void DrawMsg(LONG x1,LONG y1,LONG x2,LONG y2,const BaseContainer &msg;);   
    };   
      
    // and in your dialog:   
      
    class My_Dialog : public GeDialog   
    {   
    private:   
      
        My_User_Area render;   
      
    public:   
      
       ...overridden dialog functions etc..   
    };   
    

    The drawing of the bitmap itself is done in the GeUserArea's overridden DrawMsg() function. I might let the others assist with what you're trying to do specifically, but as a starting reference, an overridden user area's DrawMsg() might look something like this:

      
    void My_User_Area::DrawMsg(LONG x1,LONG y1,LONG x2,LONG y2,const BaseContainer &msg;)   
    {   
        SetClippingRegion(x1,y1,x2,y2);   
        OffScreenOn();   
            
        this->DrawSetPen(COLOR_BG); // set draw pen with background colour   
        DrawRectangle(x1,y1,x2,y2); // fill user area with a rectangle, in the above pen colour   
      
        this->DrawSetPen(Vector(1.0,0.0,0.0); // if using an alpha, call this and set the colour for the image background, in this case red   
        DrawBitmap(bmp,0,0,100,100,0,0,bmp->GetBw(),bmp->GetBh(),BMP_ALLOWALPHA);   
      
        // note: spend a few minutes playing around with the DrawBitmap() arguments, so you see how the sizing works. Also make sure your bmp is properly init'ed before using it!!   
        }   
    

    Hope that's of some help!

    WP.



  • On 19/08/2015 at 00:23, xxxxxxxx wrote:

    Hello,

    as described by WickedP, a UserArea is supposted to be a member of the host dialog and it must draw its content in its DrawMsg() function.

    You find examples of the use of UserAreas in the CustomGUI example and the GeDialog example on GitHub.

    Best wishes,
    Sebastian



  • On 26/08/2015 at 14:31, xxxxxxxx wrote:

    I appreciate all of the help. I was able to successfully get the MaterialPreviewCustomGui to work properly.

    Johan



  • On 13/01/2016 at 06:31, xxxxxxxx wrote:

    Hi,

    I'm also facing a similar issue with MaterialPreviewCustomGui being just an empty frame when embedded in a separate window and not being part of the description of a material. 
    How did you manage to solve this?


Log in to reply