Explode Scene (Coffee-Plugin)
Aus CINEMA 4D Wiki
In diesem Artikel wird ein Coffee-Plugin vorgestellt, und samt Quellcode dokumentiert. Es durchläuft horizontal eine Objekthierarchie, kopiert Objekte in neue Szenen und speichert die Szenen ab. Das Plugin ist sehr klein und einfach, daher gut für Coffee-Einsteiger geeignet.
Inhaltsverzeichnis |
Aufgabe
- Aufgabe
- Eine Szene mit einer unbestimmten Anzahl Objekte soll zur Bearbeitung durch unterschiedliche 3D Artists in einzelne Dateien aufgesplittet werden. Jedes Objekt auf oberster Hierarchie-Ebene soll in eine eigene Datei ausgelagert werden, Unterobjekte sollen erhalten bleiben. Die Benennung der Dateien soll sich aus der Benennung der Objekte ableiten.
- Lösung
- In Coffee wird ein kleines Plugin geschrieben, welches quasi auf Mausklick alle Objekte auf oberster Hierarchie-Ebene in separate Dateien speichert.
Konzept
Das Plugin muss in einer Schleife alle Objekte auf oberster Hierarchie-Ebene durchlaufen. Jedes Objekt samt Unterobjekte wird kopiert, es wird eine neue Szene erzeugt, und das kopierte Objekt dort eingefügt. Die Szene wird gespeichert, wobei der Name dem soeben kopierten Objekt entnommen wird. Dann geht es weiter mit dem nächsten Objekt. Sind alle Objekte abgearbeitet, wird eine "Fertig"-Meldung ausgegeben, und zur Information die Anzahl der gespeicherten Objekte/Szenen gezeigt.
Dateien
Quellcode
Hier ist nun der Quellcode des Plugins. Die Datei sollte als "explodescene.cof" gespeichert werden.
//##############################################################################
//## ##
//## Explode Scene 1.0 ##
//## ================= ##
//## ##
//## Stores all objects on first hierarchy level to separate .c4d files ##
//## Resulting files are named like the object they contain. ##
//## ##
//## 2008 by c4d-Jack; www.c4d-jack.de ##
//## OpenSource. No warranty, no support. ##
//## ##
//##############################################################################
/* Declaration of some basic values */
var PLUGIN_ID = 1022355; // ID is registered at plugincafe.com
var MENU_NAME = "Explode Scene"; // Title of the plugin
var HELP_STR = "Saves all objects in 1st hierarchy level to separate files"; // Help text to appear in the status bar
/* Declaration of the plugin class */
class ExplodeSceneMenu : MenuPlugin
{
public:
ExplodeSceneMenu(); // Constructor
GetHelp(); // Return help text
GetID(); // Return plugin ID
GetName(); // Return plugin title
GetIcon(); // Return icon
Execute(doc); // Execute plugin
}
/* Plugin class constructor */
ExplodeSceneMenu::ExplodeSceneMenu()
{
super();
}
/* Return plugin ID */
ExplodeSceneMenu::GetID()
{
return PLUGIN_ID;
}
/* Return plugin title */
ExplodeSceneMenu::GetName()
{
return MENU_NAME;
}
/* Return help text */
ExplodeSceneMenu::GetHelp()
{
return HELP_STR;
}
/* Return icon (used for menu and toolbar display) */
ExplodeSceneMenu::GetIcon()
{
var fn = GeGetRootFilename();
fn->RemoveLast();
fn->AddLast("explodescene_icon.tif");
var bm = new(BaseBitmap, 1, 1);
bm->Load(fn);
return bm;
}
/* Execute the plugin */
ExplodeSceneMenu::Execute(doc)
{
var cObj = doc->GetFirstObject(); // Get the first object in the scene
var fName = new(Filename); // Filename object (used to assembly the paths & names of the files)
var result; // Store the result of user choices here
var bPath; // Basic path (directory where resulting files will be saved)
var oCount = 0; // Counter
// Check for objects in the scene
if (!cObj)
{
// No objects in the scene -> Output a message and abort
println(MENU_NAME + ": No objects in the scene.");
result = TextDialog("No objects found in the scene.\n" + MENU_NAME + " aborted.",DLG_OK+DLG_ICONSTOP);
}
else
{
// There are objects in the scene. Here we go...
fName->PathSelect("Target directory for files:\n(Existing files will be overwritten)"); // Get destination path from user
bPath = fName->GetFullString(); // Store destination path
if (bPath == "")
{
// User has clicked the CANCEL button -> Ask what should be done
result = TextDialog("You clicked 'Cancel'. Do you want to continue and\nspecify all file names manually?", DLG_OKCANCEL+DLG_ICONQUESTION);
if (result == DLG_R_CANCEL)
{
// User wants to abort the whole process -> Output message & abort
result = TextDialog(MENU_NAME + " aborted.",DLG_OK+DLG_ICONSTOP);
println(MENU_NAME + " aborted by user.");
return FALSE;
}
}
// User wants to continue
println(MENU_NAME + ": Exploding started\n"); // Output starting message to console
println(MENU_NAME + ": Storing fragments in " + bPath); // Output destination path to console
while (cObj)
{
// LOOP: Iterate all objects on 1st hierarchy level (select next object until no more objects are left)
// Select object
println("Selecting " + cObj->GetName()); // Output name of current object to console
doc->SetActiveObject(cObj); // Select current object in the object manager
var SaveScene = new(BaseDocument); // Create an empty new scene
if (SaveScene) // Check if scene creation was successfull
{
// Everything OK -> Output success message to console
println(" Creating new scene... OK");
}
else
{
// Error happened -> Output error message to console
println(" Creating new scene... ERROR");
}
var nObj = cObj->GetClone(CL_ONLY_VISIBLETAGS); // Get a clone of the object
if (SaveScene->InsertObject(nObj, NULL, NULL)) // Insert cloned object into new scene, check if successfull
{
// Object successfully inserted -> Output message to console
println(" Insert " + nObj->GetName() + "... OK");
}
else
{
// Object could not be inserted -> Output error message to console
println(" Insert " + nObj->GetName() + "... ERROR");
}
// Assemble Filename
fName->SetFullString(bPath); // Set basic path (stored at the beginning)
fName->AddLast(cObj->GetName() + ".c4d"); // Get current object's name, set as filename
// Save Scene
if (SaveScene->Save(fName)) // Save scene, check if saving was successfull
{
// Scene successfully saved -> Output message to console and increase counter
println(" Save as " + fName->GetFullString() + "... OK");
oCount++;
}
else
{
// Error while saving scene -> Output error message to console
println(" Save as " + fName->GetFullString() + "... ERROR");
}
cObj = cObj->GetNext(); // Select next object in the scene
} // End of Loop
gc(); // Call garbage collection (free unused resources)
println(MENU_NAME + ": Process finished (" + tostring(oCount) + " files saved)"); // Output message to console
TextDialog(MENU_NAME + " finished.\n" + tostring(oCount) + " files saved",DLG_ICONASTERISK); // Show "finished" box.
}
return TRUE;
}
/* This function is called when CINEMA 4D is started */
main ()
{
if (Register(ExplodeSceneMenu)) // Try to register the plugin
{
// Plugin successfully registered -> Output version and copyright to console
println(MENU_NAME + " 1.0 successfully registered | OpenSource | 2008 by c4d-Jack | www.c4d-jack.de");
return TRUE;
}
else
{
// Plugin could not be registered -> Output error message to console
println(MENU_NAME + " could not be registered!");
return FALSE;
}
}
Besonderheiten
PLUGIN_ID
var PLUGIN_ID = 1022355
Jedes Plugin in CINEMA 4D (egal, ob in C++ oder in Coffee geschrieben) muss eine einzigartige ID haben. Die ID, die im Quellcode von "Explode Scene" eingetragen ist, ist bei www.plugincafe.comfür dieses Plugin registriert, und sollte nicht geändert werden.
class ExplodeSceneMenu : MenuPlugin
class ExplodeSceneMenu : MenuPlugin
{
public:
...
private:
...
}
Mit diesem Code wird die Klasse des Plugins deklariert. Da Explode Scene vom Pluginmenu aus aufgerufen wird, ist es ein Plugin der Klasse MenuPlugin. Im Codeblock können öffentliche (public) und private (private) Methoden und Eigenschaften der Klasse deklariert werden. Öffentlich bedeutet, dass CINEMA 4D auf eine Eigenschaft oder Methode zufreifen kann; privat bedeutet, dass die Eigenschaft oder Methode nur intern im Plugin zur Verfügung ist. Deklarierte Methoden müssen im nachfolgenden Teil des Codes implementiert werden.
WHILE-Schleife
while (cObj)
{
...
...
cObj = cObj->GetNext();
}
Mit diesem Code wird die While-Schleife definiert. Sie überprüft vor jedem Durchlauf, ob sich hinter cObj auch wirklich ein Objekt in der Szene verbirgt. Ist dies nicht der Fall, wird die Schleife nicht ausgeführt. Da noch vor Beginn der Schleife mit var cObj = doc->GetFirstObject() der erste (und hierarchisch oberste) Objekt der Szene ausgewählt wird, wird die Schleife bei einer leeren Szene (ohne Objekte) überhaupt nicht ausgeführt. Weil am Ende der Schleife mit cObj->GetNext() immer zum nachfolgenden Objekt in der Szene weitergeleitet wird, durchläuft sie somit sämtliche Objekte.
GetClone(CL_ONLY_VISIBLETAGS)
var nObj = cObj->GetClone(CL_ONLY_VISIBLETAGS);
Ein Objekt (in diesem Fall cObj) kann immer nur in einer Szene gleichzeitig sein. Versucht man, das selbe Objekt in zwei Szenen gleichzeitig zu verwenden, wird CINEMA 4D früher oder später abstürzen. Aus diesem Grund muss man eine Kopie des Objekts erzeugen, und diese in der neuen Szene einfügen. Das Argument CL_ONLY_VISIBLETAGS bewirkt, dass nur sichtbare Tags mit kopiert werden (sinnvoll, um keinen unnötigen Datenmüll in die neue Szene mitzuschleppen).
ExplodeSceneMenu()
Diese Funktion ist der sog. Konstruktor. Er muss einfach da sein.
GetName(), GetHelp(), GetID(), GetIcon()
Diese vier Funktionen werden von CINEMA 4D dazu benutzt, den Namen, den Hilfetext, die ID und das Icon des Plugins zu ermitteln. GetIcon() kann weggelassen werden, in dem Fall erscheint das Plugin ohne Symbol.
Dateiliste
Insgesamt werden nur 2 Dateien benötigt:
- explodescene.cof
- Die eigentliche Plugin-Datei, die den Code enthält.
- explodescene_icon.tif
- Ein 32x32 Pixel großes Bild im TIFF-Format. Es enthält das Icon (Symbol) des Plugins, welches im Plugin-Menü und ggf. in einer Werkzeugleiste angezeigt. Ein Alpha-Kanal ist nicht erforderlich, bewirkt aber eine schönere Darstellung des Icons, wenn z.B. der Menüpunkt markiert ist, oder wenn ein spezielles GUI-Layout verwendet wird.
Dateistruktur
Die beiden Dateien werden folgendermaßen installiert:
+ MAXON
+ CINEMA 4D Rx
+ plugins
+ ExplodeScene
- explodescene.cof
- explodescene_icon.tif
Testlauf
Sobald die .cof-Datei und die .tif-Datei im richtigen Verzeichnis liegen, kann CINEMA 4D gestartet werden. Das Plugin wird gleich beim Programmstart registriert. Ob das geklappt hat, sieht man sowohl daran, ob es im Plugin-Menü auftaucht, als auch an den Textausgaben in der Console.
Am besten, man erstellt sich eine einfache Szene, erzeugt darin einige verschiedene Grundobjekte, und ordnet ein paar der Objekte einander unter. Dann einfach den Menüpunkt "Explode Scene" im Plugin-Menü aufrufen, und schauen was passiert. Treten Laufzeitfehler auf, werden diese meistens durch entsprechende Textausgaben in der Console gekennzeichnet.
Download
Das fertige Plugin inklusive Icon kann hier heruntergeladen werden:
- CoffeePlugin_ExplodeScene.zip (10 KBytes)
Lizenz
- Explode Scene ist OpenSource.
- Es wird keine Garantie auf fehlerfreie Funktion, oder Gewährleistung bei Schäden bzw. Datenverlust gegeben.
