Cinema 4D R11 - C++ plugins

From NoskeWiki
Jump to navigation Jump to search

About

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


NOTE: This page contains a version of code from the page Cinema 4D - C++ plugins which works with Cinema 4D R11. Between R11 and R12 there were a few changes which means the code below will give errors in R12 - see: C++ Transition from R12.


Some Commonly Occurring Change Between C4D R12 and R11

Here I've listed some of the MANY methods and symbols which have changed. For the full list you'll have download the C4D STK for R12 then go to the page "Contents > Merged Alphabetical List > Getting your code to compile"... there they have a big list of ~85 symbol changes and dozens of changes to methods... and yet there are a few they've missed as well !

Some commonly used symbols which have changed include:

Old Name New Name Comment
UNDO_EDIT UNDOTYPE_EDIT applies for anything starting with UNDO_* (UNDO_NEW, UNDO_CHANGE etc)
DA_NO_THREAD DRAWFLAGS_NO_THREAD applies to everything starting with DA_NO_*
ID_BASEOBJECT_POSITION ID_BASEOBJECT_REL_POSITION or ID_BASEOBJECT_ABS_POSITION Typically you'll want to use "ID_BASEOBJECT_REL_POSITION" (a relative instead of absolute position). A third possible value is ID_BASEOBJECT_FROZEN_POSITION.
ID_BASEOBJECT_ROTATION ID_BASEOBJECT_REL_ROTATION or ID_BASEOBJECT_ABS_ROTATION As above...
ID_BASEOBJECT_SCALE ID_BASEOBJECT_REL_SCALE or ID_BASEOBJECT_ABS_SCALE As above...
NBIT_SET NBITCONTROL_SET applies to everything starting with NBIT_*
CINTER_LINEAR CINTERPOLATION_LINEAR applies to everything starting with CINTER_*
CInterpolation CINTERPOLATION And are a few other cases where you might try uppercase and see if that helps.

Some commonly used methods that have changed include:

Old Method Format New Method Format Comment
Dialog::Open(TRUE, ID_FINDDIALOGTEST,-1,-1); Dialog::Open(DLG_TYPE_ASYNC, ID_FINDDIALOGTEST,-1,-1); Dialog::Open now needs to be passed DLG_TYPE, instead of Bool as the first parameter. DLG_TYPE_ASYNC is for a non-modal dialog (recommended)... DLG_TYPE_MODAL doesn't seem to have any default way to close.
BaseObject::SetParameter(PRIM_TEXT_TEXT, GeData(text), 0); BaseObject::SetParameter(PRIM_TEXT_TEXT, GeData(text), DESCFLAGS_SET_0); GetParameter, SetParameter, GetDDescription, GetDParamter, GetDEnabling and various others must end with a DESCFLAGS_DESC type such as "DESCFLAGS_SET_0". ** This one is very common.
CommandData { ...
virtual Bool YourNewName::Execute(BaseDocument *doc) { ... }
CommandData { ...
virtual BoolExecute(BaseDocument *doc) { ... }
For some reason you can no-longer override your own name as shown on the left.
BaseTime::SetNominator( Real r ); BaseTime::SetNumerator( Real r ); Changes like this are just annoying frankly... I hope they never do it again.



Tutorial 1: Hello World

Open main.cpp (double click) and enter this code (deleting whatever was there before):

#define ID_HELLOTEST 1000001
      // unique ID for this plugin

#include "c4d.h"

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

class HelloWorldTest : public CommandData    // data class for creating new commands (previously known as "menu plugins")
{
public:
  virtual Bool HelloWorldTest::Execute(BaseDocument *doc)        // %%%% MUST BE CHANGED FOR R12 (remove "HellowWorldTest::").
  {
    MessageDialog("Hello World");            // Simple popup message.
    GePrint("This is my first plugin");      // Output to C4D's "Console window".
    return TRUE;
  }
};

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

Bool PluginStart(void)                   // the main function C4D calls to begin your plugin (think of it as main)
{
  return RegisterCommandPlugin( ID_HELLOTEST,"Hello World",
                                0,NULL,String("Hello World"),
                                gNew HelloWorldTest );
  // registers a command plugin with C4D
  // (ie: the class to execute when user selects "Hello World" under the Plugin menu)
}

void PluginEnd(void)                     // Called when the plugin is unloaded from C4D.
{
}

Bool PluginMessage(LONG id, void *data)  // Allows you to receive plugin messages from C4D or other plugins.
{
}


  • Hit build
  • Restart C4D and click: Plugins > Hello World to see your first plugin work.
  • To see your GePrint() output you will need to open the Console [Shift+F10]. This Console is also useful because you can drag-and-drop labels from the Attributes manager into the Console's command line to see the label's ID.


Tutorial 2: Simple Custom Dialog

Modify main.cpp to read as follows:

#include "c4d.h"
      // unique ID for this plugin
 

//########################################
//-- Forward Declarations:
Bool RegisterMyDialog(void);                   // ADD ANY NEW PLUGINS HERE.


//########################################
//-- CD4 Hooks:

Bool PluginStart(void)
{
  if (!RegisterMyDialog())  return FALSE;      // ADD ANY NEW PLUGINS HERE.
  return TRUE;
}

void PluginEnd(void) {}

Bool PluginMessage(LONG id, void *data) {}


This represents a minimal version of the main.cpp in the cinema4dsdk directory. If you try compiling now, it won't do anything - we need to create another file implementing our RegsiterMyDialog() function and our custom dialog. In this dialog we will include an editable text box, a spin box ("edit number arrows"), a checkbox, a button, several labels ("static text") and a group box to lay out some our elements in a grid.

Create a new file and folder MyCPlugins/mydialog/mydialog.cpp, open this file in XCode and add the following code in XCode:

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

#define ID_MYDIALOGTEST 100002      // Unique ID for this dialog.

#include "c4d.h"

enum                                // Uniquely identify all your dialog elements here.
{
  DLG_EDIT_TEXT    = 1000,
  DLG_SPN_SIZE     = 1001,
  DLG_CHK_FLAT,
  DLG_BTN_ADD,
  DLG_LBL1,
  DLG_LBL2,
  DLG_GRP1,
};

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

class MyDialog : public GeDialog
{
 public:
  MyDialog(void)            {}
  virtual ~MyDialog(void)   {}
   
  //----------
  //-- Set up your dialog elements here:
  
  virtual Bool CreateLayout(void)
  {
    this->SetTitle( "My Dialog" );
    GroupBorderSpace( 5, 5, 5, 5 );
    GroupSpace(10,10);
    
    GroupBegin(DLG_GRP1,BFH_SCALEFIT|BFV_SCALEFIT,2,0,"",BFV_GRIDGROUP_EQUALROWS);
      GroupSpace(5,5);
      
      AddStaticText       (DLG_LBL1, BFH_LEFT,0,0,"text:", BORDER_NONE);
      AddEditText         (DLG_EDIT_TEXT, BFH_SCALEFIT|BFV_SCALEFIT,300,0);
      
      AddStaticText       (DLG_LBL2, BFH_LEFT,0,0,"size:", BORDER_NONE);
      AddEditNumberArrows (DLG_SPN_SIZE,BFH_LEFT,50,0);
      
    GroupEnd();
    
    AddCheckbox         (DLG_CHK_FLAT,  BFH_SCALEFIT,0,0,    "flat");
    AddButton           (DLG_BTN_ADD,   BFH_LEFT,0,0, "Add Text");
    
    return TRUE;
  }
    
  //----------
  //-- Assign dialog elements their initial values here:
  
  virtual Bool InitValues(void)
  {
    this->SetString      (DLG_EDIT_TEXT, "Hello World");
    this->SetReal        (DLG_SPN_SIZE, 200, 1, 1000, 10 );
    this->SetBool        (DLG_CHK_FLAT, false);
    return TRUE;
  }
    
  //----------
  //-- Deal with any modification or "clicking" events here:

  virtual Bool Command(LONG id,const BaseContainer &msg)
  {
    switch (id)
    {
      case (DLG_BTN_ADD):
      {
        BaseDocument *doc = GetActiveDocument();
            
        //## GET USER ENTERED DATA:
            
        String text;   this->GetString (DLG_EDIT_TEXT, text);
        Real   size;   this->GetReal   (DLG_SPN_SIZE,  size);
        Bool   flat;   this->GetBool   (DLG_CHK_FLAT,  flat);
            
        doc->StartUndo();
            
        //## CREATE AND ADD NEW EXTRUDE NURBS OBJECT:
            
        BaseObject *objExtr = BaseObject::Alloc( Oextrude );
        if( flat )
        objExtr->SetParameter(EXTRUDEOBJECT_MOVE, GeData( Vector(0,0,0) ), 0);
        objExtr->SetName( text );
        doc->InsertObject( objExtr, NULL, NULL );
        doc->AddUndo( UNDO_NEW, objExtr );
            
        //## CREATE NEW TEXT SPLINE OBJECT AND ADD UNDER EXTRUDE:
            
        BaseObject *objText = BaseObject::Alloc( Osplinetext );
        objText->SetParameter(PRIM_TEXT_TEXT,   GeData(text), 0);        // %%%% MUST BE CHANGED FOR R12.
        objText->SetParameter(PRIM_TEXT_HEIGHT, GeData(size), 0);        // %%%% MUST BE CHANGED FOR R12.
        objText->SetName( text );
            
        doc->InsertObject( objText, objExtr, NULL );
        doc->AddUndo( UNDO_NEW, objText );
            
        //## PRINT OUT VALUES AND REFRESH:
            
        StatusSetText("Text added");
        GePrint("Text size:" + RealToString(size) );
            
        doc->EndUndo();
        DrawViews( DA_NO_THREAD );
      }
      break;
    }
    return TRUE;
  }
};

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

class MyDialogTest : public CommandData
{
 private:
  MyDialog dlg;

 public:
  virtual Bool MyDialogTest::Execute(BaseDocument *doc)
  {
    return dlg.Open(TRUE, ID_MYDIALOGTEST,-1,-1);        // %%%% MUST BE CHANGED FOR R12.
  }
};

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

Bool RegisterMyDialog(void)
{
  return RegisterCommandPlugin(ID_MYDIALOGTEST, "My Dialog",
                               0,NULL,String("My Dialog"),gNew MyDialogTest );
}


Now return to your project and add this file, by selecting the "source" folder on the left right click > Add > Add Existing Files and select mydialog.cpp. Now you click build again, and restart CD4. Open your new plugin and click "Add Text". This useful little plugin creates an "Extrude Nurbs" object and a "Text" object as its child. Text splines are not visible when you render [Cmd+r] unless extruded! Notice also, you can undo this operation thanks to the AddUndo() functions between the StartUndo() and EndUndo(). AddUndo(LONG type, void* data) always has to be called directly before a change is made (the most common are: UNDO_CHANGE, UNDO_CHANGE_NOCHILDS & UNDO_DELETE)... EXCEPT in the case of adding a new object/tag/material/track etc - where the call (using: UNDO_NEW) must be made directly after. Congratulations - you have now created a simple dialog plugin which you can play with and build on!

Download this complete example here.


See Also