Cinema 4D - my COFFEE plugins - sphere changer

From NoskeWiki
Jump to navigation Jump to search
Sphere changer plugin dialog

About

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


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


spherechanger.cof - for changing the properties and detail of many spheres at once

//------------------
//-- FILE:    spherechanger.cof
//-- AUTHORS: Andrew Noske
//--
//-- This Cinema 4D menu plugin brings up a dialog which allows you to recursively
//-- change the properties of ALL spheres within the document, or underneath
//-- the selected object.
//-- Although  possible to select multiple spheres and change their properties
//-- simultaneously using under "Attributes", it only applies this to the first 1000
//-- objects. Hence, this plugins is useful in files with thousands of spheres, where
//-- decreasing the number of sphere section can drastically speed up the redraw process.
//--  
//-- For more information see: http://www.andrewnoske.com/wiki/index.php?title=Cinema_4D

//########################################
//-- Globals Variables:

var PLUGIN_ID = 1023849;                  // unique number I've registered for "Sphere Changer"
var PLUGIN_TITLE = "Sphere Changer";


var totalSpheres = 0;   // used to tally the total number of spheres modified.
var gDoc;               // used to store pointer to document

enum
{
  DLG_EDITNUM_SEGMENTS = 1000,
  DLG_BTN_UPDATE = 1001,
  DLG_RAD_APPLY,
  DLG_CHK_CHANGETYPE,
  DLG_LBL1,
  DLG_LBL2,
  DLG_CBO_TYPE,
  DLG_ROW1,
  DLG_ROW2,
  DLG_COL1,
  DLG_MAIN,
  DLG_DUMMY
}


//########################################
//-- SphereChangerDialog class:

class SphereChangerDialog : GeDialog
{
  private:
    var segments;
  public:
    SphereChangerDialog();
    CreateLayout();
    Command(id, msg);
    SetSphereVals(obj, segs, setType, sphereType);
}


SphereChangerDialog::SphereChangerDialog()
{
  super( PLUGIN_ID );     // for non-modal dialog (GeDialog)
  //super();              //for modal dialog    (GeModalDialog)
}

SphereChangerDialog::CreateLayout() 
{
  SetTitle(PLUGIN_TITLE);
  
  AddGroupBeginV(DLG_MAIN, BFH_SCALEFIT, 1, "", 0);
    AddGroupBorderSpace( 5, 5, 5, 5 );
    
    AddGroupBeginH(DLG_ROW1, BFH_SCALEFIT, 1, "", 0); 
      AddStaticText ( DLG_LBL1, BFH_LEFT, 100, 0, "# segments:", 0);        // label
      AddEditText   ( DLG_EDITNUM_SEGMENTS, BFH_SCALEFIT, 200, 0 );         // text edit
      SetString     ( DLG_EDITNUM_SEGMENTS, "10" );
    AddGroupEnd();
    
    AddGroupBeginH(DLG_ROW2, BFH_SCALEFIT, 1, "", 100);
      
      AddCheckbox ( DLG_CHK_CHANGETYPE, BFH_LEFT, 100, 0, "set type:");   // check box
      
      AddComboBox( DLG_CBO_TYPE, BFH_SCALEFIT, 200, 0 );                  // combo box
      AddItem( DLG_CBO_TYPE, 0, "standard" );
      AddItem( DLG_CBO_TYPE, 1, "tetrahedron" );
      AddItem( DLG_CBO_TYPE, 2, "octahedron" );
      AddItem( DLG_CBO_TYPE, 3, "isoahedron" );
      AddItem( DLG_CBO_TYPE, 4, "hemisphere" );
      SetItem( DLG_CBO_TYPE, 0 );
      
    AddGroupEnd();
    
    AddGroupBeginV(DLG_COL1, BFH_SCALEFIT, 1, "", 0);  
    AddGroupBorder( BORDER_GROUP_IN );
      
      AddStaticText ( DLG_LBL2, BFH_SCALEFIT, 100, 0, "APPLY TO:", 0);    // label
      AddRadioGroupV( DLG_RAD_APPLY, BFH_SCALEFIT, 1 );                   // radio group
      AddItem( DLG_RAD_APPLY, 0, "all objects in scene" );
      AddItem( DLG_RAD_APPLY, 1, "selected object's children only" );
      SetItem( DLG_RAD_APPLY, 0 );
      
    AddGroupEnd();
    
    AddSeparatorH ( DLG_DUMMY );                                          // separator
    AddButton     ( DLG_BTN_UPDATE, BFH_SCALEFIT, 0, 0, "Update");        // button
    
  AddGroupEnd();
  
  return;
}


//------------------
//-- Recursive function which inputs an object and traverses down the 
//-- heirarchy (depth first search) and changes any sphere objects by:
//--  # Setting the number of segments to "segs"
//--  # Setting the sphere type to "sphereType" if "setType" is true
//-- For every sphere found it increments the global variable "totalSpheres"
//-- WARNING: If the heirarchy goes too deep (eg: >40 levels) this may cause a
//--          "Stack overflow" error

SphereChangerDialog::SetSphereVals(obj, segs, setType, sphereType)
{
  while( obj )
  {
    var child = obj->GetDown();
    if( child )
    {
      SetSphereVals(child, segs, setType, sphereType);
    }
    
    if( obj->GetType() == OBJECT_SPHERE )    //%%%%% IN R11 THIS WAS "Object_SPHERE"
    {
      obj#PRIM_SPHERE_SUB = segs;    
      if(setType)
        obj#PRIM_SPHERE_TYPE = sphereType;
      
      totalSpheres++;
    }
    
    obj = obj->GetNext();
  }
}


//------------------
//-- Handles any user input into the "SphereChangerDialog" dialog.

SphereChangerDialog::Command(id, msg) 
{
  switch( id )
  {
    case (DLG_BTN_UPDATE):
    {
      //## RETRIEVE AND CHECK DIALOG VALUES: 
      
      var setType    = GetCheckbox( DLG_CHK_CHANGETYPE );
      var sphereType = GetItem( DLG_CBO_TYPE );
      var applyTo    = GetItem( DLG_RAD_APPLY );
      //var segs = evaluate( GetString( DLG_EDITNUM_SEGMENTS ) );
      var segs = evaluate( GetString( DLG_EDITNUM_SEGMENTS ) );
    
      if( segs<=0 || segs>100  )      // if bad "# segments" value entered:
      {
        TextDialog("You have entered a bad value into 'segments'",
                    DLG_OK + DLG_ICONEXCLAMATION );
        SetString( DLG_EDITNUM_SEGMENTS, "1" );
        break;
      }
      
      //## CHECK WE HAVE A VALID OBJECT TO START WITH:
      
      var startObj;           // first object to input into recursive call
      
      if( applyTo==1 )  // if we want to apply to selected children only:
      {
        if( !gDoc->GetActiveObject() || !gDoc->GetActiveObject()->GetDown() ) {
          TextDialog("You have not selected an object with children", DLG_OK );
          break;
        }
        startObj = gDoc->GetActiveObject()->GetDown();
      }
      else
      {
        if( !gDoc->GetFirstObject() ) {
          TextDialog("Scene is empty", DLG_OK );
          break;
        }
        startObj = gDoc->GetFirstObject();
      }
      
      //## TRAVERSE HIERARCHY, CHANGE SPHERES AND OUTPUT RESULT:
      
      totalSpheres = 0;
      SetSphereVals( startObj, segs, setType, sphereType );     // RECURSIVE FUNCTION
      
      println(totalSpheres, " spheres where updated.");         // output result
      DrawViews( DA_NO_THREAD );                                // redraws the scene
    }
      break;
      
    default:
  }
  
}


//########################################
//-- SphereChangerMenu class:

class SphereChangerMenu : MenuPlugin 
{
 public:
  SphereChangerMenu();
  GetID();
  GetName();
  GetHelp();
  Execute(doc);
}


SphereChangerMenu::SphereChangerMenu() { super(); }
SphereChangerMenu::GetID()             { return PLUGIN_ID; }
SphereChangerMenu::GetName()           { return PLUGIN_TITLE; }
SphereChangerMenu::GetHelp()           { return PLUGIN_TITLE; }

SphereChangerMenu::Execute(doc)
{
    gDoc = doc;
    var d = new(SphereChangerDialog);
    d->Open(TRUE,-1,-1);    // for a non-modal dialog
    //d->Open(-1, -1);      // for modal dialog
}


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

main() 
{
  Register(SphereChangerMenu);
}


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! :)