Cinema 4D - my C++ plugins - add fade

From NoskeWiki
Jump to navigation Jump to search
Add fade plugin dialog

About

NOTE: This page is a daughter page of: Cinema 4D


This page contains code for a C++ plugin I've written for Cinema 4D. To understand how it compiles see Cinema 4D - my C++ plugins.

fade.cpp - for quickly applying a fade in and/or fade out affect to a selected object

//------------------
//-- FILE:    fadedialog.cpp
//-- AUTHORS: Andrew Noske
//--
//-- This Cinema 4D menu plugin creates a fade-in and fade-out effect
//-- for the selected object by giving it a Display tag (if not already)
//-- and animating its "Visibility"
//-- 
//-- For more information see: http://www.andrewnoske.com/wiki/index.php?title=Cinema_4D

//########################################
//-- Includes and Globals Variables:

#include "c4d.h"

#define ID_FADEDIALOGTEST 1023839
                                    // my unique registered plugin ID for "Fade Effect"

enum 
{
  DLG_EDIT_F1       = 1000,
  DLG_EDIT_F2       = 1001,
  DLG_EDIT_F3,
  DLG_EDIT_F4,
  DLG_EDIT_V1,
  DLG_EDIT_V2,
  DLG_EDIT_V3,
  DLG_EDIT_V4,
  DLG_CHK_U1,
  DLG_CHK_U2,
  DLG_CHK_U3,
  DLG_CHK_U4,
  DLG_RAD_APPLY,
  DLG_CBO_TYPE,
  DLG_BTN_UPDATE,
  DLG_LBL1,
  DLG_LBL2,
  DLG_LBL3,
  DLG_LBL4,
  DLG_GRP1,
  DLG_GRP2,
  DLG_GRP3
};

//########################################
//-- Inline Functions:


//------------------
//-- Jumps to the chosen frame number in the current document

inline bool GotoFrame( int frame )
{
  BaseDocument *doc = GetActiveDocument();
  BaseTime time;
  time.SetNumerator   ( (Real)frame );
  time.SetDenominator ( doc->GetFps() );
  doc->SetTime( time );
  return true;
}


//------------------
//-- Creates a keyframe at the given "frame" with given "value" in the "current track"
//-- with the given type of interpolation (interp).
//-- If a keyframe already exists at this location, it changes the "value".
//-- Returns 1 if successful or 0 if unsuccessful. Adds Undo calls for all actions.

inline int SetKeyframe( CTrack *track, int frame, float value, CINTERPOLATION interp  )
{
  BaseDocument *doc = GetActiveDocument();
  BaseTime time( frame, doc->GetFps() );
  CCurve *curve = track->GetCurve();
  
  CKey   *key   = curve->FindKey( time );
  if(!key)
  {
    key   = curve->AddKey(time);
    if(!key)
      return 0;
    doc->AddUndo(UNDOTYPE_NEW, key);
  }
  
  doc->AddUndo(UNDOTYPE_CHANGE, key);
  key->SetInterpolation( curve, interp );
  doc->AddUndo(UNDOTYPE_CHANGE, key);
  key->SetValue( curve, value );
  return 1;
}


//------------------
//-- Returns the value of the matching element ID within "dialog" as a Real.
//-- NOTE: Designed for EditNumber() or EditNumberArrows().

inline Real GetRealFromElement( GeDialog *dialog, int id )
{
  Real real;
  dialog->GetReal(id,real);
  return real;
}

//------------------
//-- Returns the value of the matching element ID within "dialog" as a Bool.
//-- NOTE: Designed for Checkbox().

inline bool GetBoolFromElement( GeDialog *dialog, int id )
{
  Bool boolVal;
  dialog->GetBool(id,boolVal);
  return boolVal;
}


//########################################
//-- FadeDialog class: (the main dialog for this plugin)

class FadeDialog : public GeDialog
{
  public:
    FadeDialog(void) {}
    virtual ~FadeDialog(void) {}
    
    virtual Bool CreateLayout(void)
    {
      this->SetTitle( "Fade Dialog" );
      
      LONG SC_VH = BFH_SCALEFIT | BFV_SCALEFIT;
      
      GroupBorderSpace( 10, 10, 10, 10 );
      GroupSpace(5,5);
      
      
      GroupBegin( DLG_GRP1,SC_VH,1,0,"apply to:",BFV_GRIDGROUP_EQUALROWS );
        GroupBorder(BORDER_WITH_TITLE|BORDER_THIN_IN);
        GroupBorderSpace( 5, 5, 5, 5 );
        GroupSpace(10,10);
        
        AddRadioGroup(DLG_RAD_APPLY, BFH_SCALEFIT, 1 );                   // radio group
        AddChild( DLG_RAD_APPLY, 0, "selected object     \t(display tag visibility)" );
        AddChild( DLG_RAD_APPLY, 1, "selected material  \t(transparency brightness)" );
        
      GroupEnd();
      
      GroupBegin( DLG_GRP2,BFH_LEFT,2,0,"",BFV_GRIDGROUP_EQUALROWS );    
        GroupBorderSpace( 5, 5, 5, 5 );
      
        AddStaticText       (DLG_LBL1,BFH_LEFT,0,0,"interpolation:", BORDER_NONE);
        AddComboBox         (DLG_CBO_TYPE, BFH_SCALEFIT, 0, 0 );         // combo box
        AddChild            (DLG_CBO_TYPE, (int)CINTERPOLATION_SPLINE, "spline" );
        AddChild            (DLG_CBO_TYPE, (int)CINTERPOLATION_LINEAR, "linear" );
        AddChild            (DLG_CBO_TYPE, (int)CINTERPOLATION_STEP,   "step" );
      
      GroupEnd();
          
      GroupBegin(DLG_GRP3,SC_VH,5,0,"keyframes to add:",BFV_GRIDGROUP_EQUALROWS);
        GroupBorderSpace( 5, 5, 5, 5 );
        GroupSpace(3,3);
        
        GroupBorder(BORDER_WITH_TITLE|BORDER_THIN_IN);
        
        AddStaticText       (DLG_LBL2,SC_VH,0,0,"use:", BORDER_NONE);
        AddCheckbox         (DLG_CHK_U1,BFH_CENTER,10,0,"");
        AddCheckbox         (DLG_CHK_U2,BFH_CENTER,10,0,"");
        AddCheckbox         (DLG_CHK_U3,BFH_CENTER,10,0,"");
        AddCheckbox         (DLG_CHK_U4,BFH_CENTER,10,0,"");
        
        AddStaticText       (DLG_LBL3,SC_VH,0,0,"opacity:", BORDER_NONE);
        AddEditNumberArrows (DLG_EDIT_V1,BFH_SCALEFIT,40);
        AddEditNumberArrows (DLG_EDIT_V2,BFH_SCALEFIT,40);
        AddEditNumberArrows (DLG_EDIT_V3,BFH_SCALEFIT,40);
        AddEditNumberArrows (DLG_EDIT_V4,BFH_SCALEFIT,40);
        
        AddStaticText       (DLG_LBL4,SC_VH,0,0,"frame:", BORDER_NONE);
        AddEditNumberArrows (DLG_EDIT_F1,BFH_SCALEFIT,50);
        AddEditNumberArrows (DLG_EDIT_F2,BFH_SCALEFIT,50);
        AddEditNumberArrows (DLG_EDIT_F3,BFH_SCALEFIT,50);
        AddEditNumberArrows (DLG_EDIT_F4,BFH_SCALEFIT,50);
      
      GroupEnd();
    
      AddSeparatorH       (SC_VH);
      AddButton           (DLG_BTN_UPDATE,SC_VH,400,0,"Add Keyframes");
      
      return TRUE;
    }
    
    
    virtual Bool InitValues(void)
    {
      this->SetBool               (DLG_CHK_U1, true);
      this->SetBool               (DLG_CHK_U2, true);
      this->SetBool               (DLG_CHK_U3, true);
      this->SetBool               (DLG_CHK_U4, true);
      
      this->SetPercent            (DLG_EDIT_V1, (Real)0,   0, 100, 5 );
      this->SetPercent            (DLG_EDIT_V2, (Real)100, 0, 100, 5 );
      this->SetPercent            (DLG_EDIT_V3, (Real)100, 0, 100, 5 );
      this->SetPercent            (DLG_EDIT_V4, (Real)0,   0, 100, 5 );
      
      Real fps       = GetActiveDocument()->GetFps();
      Real lastFrame = GetActiveDocument()->GetMaxTime().GetFrame( fps );
      
      this->SetReal               (DLG_EDIT_F1, 40, 0, lastFrame, 1 );
      this->SetReal               (DLG_EDIT_F2, 50, 0, lastFrame, 1 );
      this->SetReal               (DLG_EDIT_F3, 80, 0, lastFrame, 1 );
      this->SetReal               (DLG_EDIT_F4, 90, 0, lastFrame, 1 );
      
      this->SetLong               (DLG_CBO_TYPE, (int)CINTERPOLATION_LINEAR);
      this->SetLong               (DLG_RAD_APPLY, 0);
      return TRUE;
    }
    
    
  virtual Bool Command(LONG id,const BaseContainer &msg)
  {
    switch (id)
    {
      case (DLG_BTN_UPDATE):
      {
        //## RETRIEVE USER ENTERED VALUES:
        BaseDocument *doc = GetActiveDocument();
        
        bool  use1   = GetBoolFromElement( this, DLG_CHK_U1 );
        bool  use2   = GetBoolFromElement( this, DLG_CHK_U2 );
        bool  use3   = GetBoolFromElement( this, DLG_CHK_U3 );
        bool  use4   = GetBoolFromElement( this, DLG_CHK_U4 );
        
        float value1 = GetRealFromElement( this, DLG_EDIT_V1 );
        float value2 = GetRealFromElement( this, DLG_EDIT_V2 );
        float value3 = GetRealFromElement( this, DLG_EDIT_V3 );
        float value4 = GetRealFromElement( this, DLG_EDIT_V4 );
        
        float frame1 = GetRealFromElement( this, DLG_EDIT_F1 );
        float frame2 = GetRealFromElement( this, DLG_EDIT_F2 );
        float frame3 = GetRealFromElement( this, DLG_EDIT_F3 );
        float frame4 = GetRealFromElement( this, DLG_EDIT_F4 );
        
        bool selectedMaterial = (int)GetRealFromElement( this, DLG_RAD_APPLY ) == 1;
        CINTERPOLATION interp = (CINTERPOLATION)GetRealFromElement(this,DLG_CBO_TYPE);
        
        
        if( selectedMaterial )    // if we are applying this to a material
        {
          //## VERIFY MATERIAL IS SELECTED:
          BaseMaterial   *mat = doc->GetActiveMaterial();
          
          if( !mat )
          {
            MessageDialog( "You have not selected a valid material" );
            return FALSE;
          }
          
          //## FIND THE OBJECT'S DISPLAY TAG, OR CREATE NEW ONE:
          
          doc->StartUndo();
          doc->AddUndo( UNDOTYPE_CHANGE, mat );
          
          Material *matm = (Material*)mat;
          matm->SetChannelState( CHANNEL_TRANSPARENCY, 1 );
          
          
          //## GET THE VISIBILITY ANIMATION TRACK FOR TAG, OR CREATE A NEW ONE:
          
          CTrack *track = mat->FindCTrack( DescLevel(MATERIAL_TRANSPARENCY_BRIGHTNESS) );
          
          if(!track)
          {
            track = CTrack::Alloc( mat, MATERIAL_TRANSPARENCY_BRIGHTNESS ); 
            if(!track)  return FALSE;
            mat->InsertTrackSorted( track );
            doc->AddUndo( UNDOTYPE_NEW, track );
          }
          
          //## GENERATE NEW KEYFRAMES:
          
          int framesAdded = 0;
          
          if(use1)  framesAdded += SetKeyframe(track, frame1, (Real)1 - value1, interp);
          if(use2)  framesAdded += SetKeyframe(track, frame2, (Real)1 - value2, interp);
          if(use3)  framesAdded += SetKeyframe(track, frame3, (Real)1 - value3, interp);
          if(use4)  framesAdded += SetKeyframe(track, frame4, (Real)1 - value4, interp);
          
          StatusSetText( RealToString(framesAdded)
                         + " frames were added to " + mat->GetName() );
          
          mat->Message(MSG_UPDATE);
          EventAdd(EVENT_ANIMATE);          
        }
        
        
        else              // (else) if we are applying this to a material
        {
          //## VERIFY OBJECT IS SELECTED:
          BaseObject   *obj = doc->GetActiveObject();
          
          if( !obj )
          {
            MessageDialog( "You have not selected a valid object" );
            return FALSE;
          }
          
          //## FIND THE OBJECT'S DISPLAY TAG, OR CREATE NEW ONE:
          
          BaseTag *tag = obj->GetFirstTag();
          while( tag && tag->GetType() != Tdisplay )
            tag = tag->GetNext();
          
          doc->StartUndo();
          
          if( !tag )                // if no display tag exists: create new one
          {
            String objNameLower = obj->GetName();
            objNameLower.ToLower();
            
            tag = BaseTag::Alloc( Tdisplay );
            tag->SetParameter(DISPLAYTAG_AFFECT_VISIBILITY, GeData(1), DESCFLAGS_SET_0);
            tag->SetName( "Display - " + objNameLower );
            obj->InsertTag(tag, NULL);
            doc->AddUndo( UNDOTYPE_NEW, tag );
          }
          else
          {
            if (!QuestionDialog( "Object already has a display tag\n.... continue?" ))
              return FALSE;
            tag->SetParameter(DISPLAYTAG_AFFECT_VISIBILITY, GeData(1), DESCFLAGS_SET_0);
          }
          
          
          //## GET THE VISIBILITY ANIMATION TRACK FOR TAG, OR CREATE A NEW ONE:
          
          CTrack *track = tag->FindCTrack( DescLevel(DISPLAYTAG_VISIBILITY) );
          
          if(!track)
          {
            track = CTrack::Alloc( tag, DISPLAYTAG_VISIBILITY ); 
            if(!track)  return FALSE;
            tag->InsertTrackSorted( track );
            doc->AddUndo( UNDOTYPE_NEW, track );
          }
          
          //## GENERATE NEW KEYFRAMES:
          
          int framesAdded = 0;
          
          if(use1)  framesAdded += SetKeyframe( track, frame1, value1, interp );
          if(use2)  framesAdded += SetKeyframe( track, frame2, value2, interp );
          if(use3)  framesAdded += SetKeyframe( track, frame3, value3, interp );
          if(use4)  framesAdded += SetKeyframe( track, frame4, value4, interp );
          
          StatusSetText( RealToString(framesAdded)
                         + " frames were added to " + obj->GetName() );
          
          tag->Message(MSG_UPDATE);
          EventAdd(EVENT_ANIMATE);
          
        }
        
        doc->EndUndo();
        DrawViews( DRAWFLAGS_NO_THREAD );
      }
        break;
    }
    return TRUE;
  }
  
};

//########################################

class FadeDialogTest : public CommandData
{
 private:
  FadeDialog dlg;

 public:
  virtual Bool Execute(BaseDocument *doc)
  {
    return dlg.Open(DLG_TYPE_ASYNC, ID_FADEDIALOGTEST,-1,-1);
  }
};

//########################################

Bool RegisterFadeDialog(void)
{
  return RegisterCommandPlugin(ID_FADEDIALOGTEST,"Fade Effect",
                               0,NULL,String("Fade Effects"),gNew FadeDialogTest );
}


See Also


Code license
For all of the code on my site... if there are specific instruction or licence comments please leave them in. If you copy my code with minimum modifications to another webpage, or into any code other people will see I would love an acknowledgment to my site.... otherwise, the license for this code is more-or-less WTFPL (do what you want)! If only copying <20 lines, then don't bother. That said - if you'd like to add a web-link to my site www.andrewnoske.com or (better yet) the specific page with code, that's a really sweet gestures! Links to the page may be useful to yourself or your users and helps increase traffic to my site. Hope my code is useful! :)