SpecialEventAdd()

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 16/05/2012 at 12:32, xxxxxxxx wrote:

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

---------
Does anyone have a really, really, simple SpecialEventAdd() example that they can share?
The example in the docs has too many missing parts that I can't solve.
For example:

SpecialEventAdd( MY_PLUGIN_ID, MY_FN_SELECTOR, (VULONG) my_data ); //Which pluginID? The message ID? or the receiving plugin's ID?

What is MY_FN_SELECTOR controlling?
what is my_data controlling?
etc...

If I had an actual simple working example to look at. I think I can figure out all my questions on my own.

Thanks,
-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 16/05/2012 at 15:50, xxxxxxxx wrote:

Hi Scott,

Here's a working example, it's from my render logging plugin and this is the Execute() function of a VideoPostData plugin:

  
RENDERRESULT RenderLog::Execute(BaseVideoPost *node, VideoPostStruct *vps)   
{   
     BaseContainer bc;   
  
     if(vps->vp != VIDEOPOSTCALL_FRAMESEQUENCE)   
          return RENDERRESULT_OK;   
  
     if(vps->renderflags & RENDERFLAGS_EXTERNAL)   
     {   
          if(vps->open)   
               SpecialEventAdd(RL_COMMAND_START);   
          else   
          {   
               bc = vps->render->GetRenderData();   
               renderBC = bc.GetClone(COPYFLAGS_0, NULL);   
               SpecialEventAdd(RL_COMMAND_END, 0, (VULONG)renderBC);   
          }   
     }   
  
     return RENDERRESULT_OK;   
}   

All it does is test if the render is to the picture viewer and if it is, it checks to see if this is the start or end of the render. If it's the start (vps->open is TRUE) then it sends a SpecialEventAdd with no parameters other than the ID. That ID (RL_COMMAND_START) is a unique value, obtained as a plugin ID from this site. It has to be unique so that no other plugin does anything with it. I could have used the videopost plugin's ID, but I needed two IDs so I got two new ones.

The second message (RL_COMMAND_END) is sent on the end of the render and this time it sends a copy of the render data (the 'renderBC' variable is a class-level pointer to a base container).

The main plugin listens for these two messages by overriding CoreMessage() and takes action accordingly.

That should be all you need to get it working.

Steve

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 16/05/2012 at 16:54, xxxxxxxx wrote:

Thanks Steve,

Could I possibly see how you handle the sent messages in the main plugin's CoreMessage() method?
Because for some reason I'm not picking up the VideoPostData's SEA message in my dialog's CoreMessage() method.

Bool myDialog::CoreMessage(LONG id, const BaseContainer& msg)  
{  
   
  if (id == RL_COMMAND_START)                      //If id equals the SEA message   
  {  
    GePrint("Testing if message is working");      //Print this message<---Not working!  
    this->SetString(4002,"Rendering in progress"); //Display this text when rendering<-----Not working!  
  }  
  
  
  return GeDialog::CoreMessage(id, msg);  
}

I can post the entire .cpp code if needed.
It's not that long.

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 17/05/2012 at 01:15, xxxxxxxx wrote:

Sure. Here's the CoreMessage() function of the dialog which is watching for those messages. You can see there's actually a third message in there, RL_COMMAND_NEWDOC, which is sent by a SceneHook plugin whenever a document is loaded.

  
Bool RLDialog::CoreMessage(LONG id, const BaseContainer &msg;)   
{   
     switch(id)   
     {   
     case RL_COMMAND_START:   
          // do some stuff   
          break;   
  
     case RL_COMMAND_END:   
          // do some other stuff   
          break;   
  
     case RL_COMMAND_NEWDOC:   
          // do some stuff when a document is loaded   
          break;   
     }   
  
     return GeDialog::CoreMessage(id, msg);   
}   

As you can see, the method is basically the same as the one you're using, so I don't know why it isn't working for you.

Steve

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 17/05/2012 at 07:55, xxxxxxxx wrote:

Oh Darn.
I was hoping to see something magical I was missing in your CoreMessage() code that I was doing wrong.

Obviously I'm doing something wrong. So I'll post my entire .cpp code.
It's just a simple dialog plugin with a button, checkbox, combobutton, and an editable text field.
Both plugins are also listed in the main.cpp file. And everything runs without errors....Except the SpecialEventAdd() code doesn't work.

#include "c4d.h"  
#include "c4d_symbols.h"  
  
#define DIALOG_ID 1000006   //testing plugin ID for the dialog part of this example  
#define VPOST_ID  1000007   //testing plugin ID for the VideoPostData part of this example  
  
#define RL_COMMAND_START 1000009     //This is a unique ID number for the SpecialEventAdd() param1  
  
  
class MyPostData : public VideoPostData  
{  
  public:  
      static NodeData *Alloc(void) { return gNew MyPostData; }  
      virtual RENDERRESULT Execute(BaseVideoPost *node, VideoPostStruct *vps);  
      virtual VIDEOPOSTINFO GetRenderInfo(BaseVideoPost *node) { return VIDEOPOSTINFO_0; }  
};  
  
RENDERRESULT MyPostData::Execute(BaseVideoPost *node, VideoPostStruct *vps)  
{  
   BaseContainer bc;  
   if(vps->vp != VIDEOPOSTCALL_FRAMESEQUENCE) return RENDERRESULT_OK;  
  
   if(vps->renderflags & RENDERFLAGS_EXTERNAL)    //If the picture view renderer is being used  
   {  
     if(vps->open)                                //If it's the start of the rendering process  
      {     
       SpecialEventAdd(RL_COMMAND_START);        //Send a SEA message  
      }  
   }      
  
        
  return RENDERRESULT_OK;      
}  
  
Bool RegisterMyPostData(void)  
{  
  return RegisterVideoPostPlugin(VPOST_ID,GeLoadString(IDS_POSTDATA),0,MyPostData::Alloc,"",0,0);  
}  
  
  
class myDialog : public GeDialog  
{  
  private:  
      BitmapButtonCustomGui *myButton;  
      myDialog* dlg;  
  
  public:  
      myDialog(void);  
      ~myDialog(void);  
      virtual Bool CreateLayout(void);  
      virtual Bool InitValues(void);  
      virtual Bool Command(LONG id,const BaseContainer &msg);  
      virtual LONG Message(const BaseContainer &msg,BaseContainer &result);  
      virtual Bool GetDDescription(GeListNode *node, Description *description,DESCFLAGS_DESC &flags);      
      virtual Bool CoreMessage(LONG id, const BaseContainer& msg);  
};  
  
  
myDialog::myDialog(void)  
{      
}  
  
myDialog::~myDialog(void)  
{      
  GeFree(dlg);  
}  
  
  
Bool myDialog::CreateLayout(void)  
{  
  Bool res = TRUE;  
  res = LoadDialogResource(IDS_RESDIALOG,NULL,0);  //Loads the external .res file resources  
  
  //This text gizmo we'll create here...not in the .res file  
  AddEditText(4002,BFH_SCALEFIT,100,10,0); //id, flags, height, width, password   
  
  return res;  
}  
  
  
Bool myDialog::InitValues(void)  
{  
  // first call the parent instance  
  if (!GeDialog::InitValues()) return FALSE;  
  
  this->SetBool(MY_CHECKBOX,FALSE);           //Sets the checkbox to enabled by default-->looks in the description->c4d_symbols.h file for matching name  
  this->SetLong(MY_COMBOBUTTON,FIRST_CHILD);  //Sets the initial button value to the first option in the list-->looks in the description->c4d_symbols.h file for matching name  
  this->SetString(4002,"Hello");  
  
  return TRUE;  
}  
  
Bool myDialog::CoreMessage(LONG id, const BaseContainer& msg)  
{  
   
  if (id == RL_COMMAND_START)                      //If id equals the SEA message   
  {  
   GePrint("Testing if message is working");      //Print this message<---Not working!  
   this->SetString(4002,"Rendering in progress"); //Display this text when rendering<-----Not working!  
  }  
  
  return GeDialog::CoreMessage(id, msg);  
}  
  
  
Bool myDialog::Command(LONG id,const BaseContainer &msg)  //This is where the code that does something goes  
{  
  BaseDocument *doc = GetActiveDocument(); //Get the active document    
  
  //Set up some actions that will tell c4d that a gizmo has been triggered..We'll used those action variables later on in the switch code block  
  LONG myComboButFirst = msg.GetLong(BFM_ACTION_VALUE);    //Assigns an action to a variable        
  LONG myComboButSecond = msg.GetLong(BFM_ACTION_VALUE);    //Assigns an action to a variable  
  
   
  switch (id)   
    {  
    case MY_BUTTON:               
          GePrint("Button Was Pressed");               
          break;  
  
    case MY_CHECKBOX:            
          GePrint("CHKBox was Toggled");  
          break;  
  
    case MY_COMBOBUTTON:    //This button was created externally in the .res file                  
          if(myComboButFirst == FIRST_CHILD) GePrint("First Option Selected");  
          if(myComboButSecond == SECOND_CHILD) GePrint("Second Option Selected");  
          break;  
    }   
  
  EventAdd();  
  
  return TRUE;  
}  
  
LONG myDialog::Message(const BaseContainer &msg, BaseContainer &result)  
{  
//not used  
return GeDialog::Message(msg,result);  
}  
  
Bool myDialog::GetDDescription(GeListNode *node, Description *description,DESCFLAGS_DESC &flags)  
{      
  //not used  
  return TRUE;  
}   
  
  
class myResDialog : public CommandData // myResDialog is the class name that needs to be listed in the main.cpp file to register it properly   
{  
  private:  
      myDialog dlg;  
  
  public:  
      virtual Bool Execute(BaseDocument *doc);  
      virtual LONG GetState(BaseDocument *doc);  
      virtual Bool RestoreLayout(void *secret);          
};  
  
LONG myResDialog::GetState(BaseDocument *doc)  
{   
  //Not Used  
  return CMD_ENABLED;  
}  
  
Bool myResDialog::Execute(BaseDocument *doc)  
{  
  StopAllThreads();  
  return dlg.Open(DLG_TYPE_ASYNC,DIALOG_ID, -1, -1, 300,150);  
}  
  
Bool myResDialog::RestoreLayout(void *secret)  
{  
  return dlg.RestoreLayout(DIALOG_ID,0,secret);  
}  
  
Bool RegistermyResDialog(void)  
{  
  String Help = "C++ Dialog is using external resources(.res)"; //This string appears in the status bar when the user hovers over the plugin name in the menu  
  //Register the plugin  
  return RegisterCommandPlugin(IDS_RESDIALOG, "C++ SpecialEventAdd Example", 0, AutoBitmap("icon.tif"),Help, gNew myResDialog);  
}

Hopefully someone can tell me why the SpecialEventAdd() is not working.

Thanks a lot for your help Steve,
-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 17/05/2012 at 08:08, xxxxxxxx wrote:

This may be a silly question, but are you inserting the VP into the render settings? Your VideoPostData should be visible in the 'Effect...' list of the render settings dialog. You will have to add it manually or it won't be called and therefore will never send a message. Or, of course, you can do it from code but you aren't doing that as far as I can see on a quick look.

Steve

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 17/05/2012 at 08:36, xxxxxxxx wrote:

DOH!
Hang my picture on the wall of shame. :blush:

This is the first video effect code I've written. And I was so focused on the code that I forgot all about having to add video effects from the effects option.
The code works fine when the effect is added to the render options.

Thanks again Steve.
-ScottA