|
|
CINEMA
4D, Revision 6
COFFEE
plugin tutorial
Creating a house object
(a
link will be available for part 8 of this tutorial soon)
coffee
tutorial 1: Introduction
coffee tutorial 2: Programming basics
coffee tutorial 3: The nuts and bolts
of a plugin
coffee tutorial 4: Your first dialog
box
coffee tutorial 5: A better dialog
box
coffee tutorial 6: Creating a house object
coffee tutorial 7: Interactive
house modeling
coffee tutorial 8: International resources
For
QuickStarters:
*
copy and paste the listing text (below) to a simple text editor and save
it as a plain text file under the name 'lesson6.cof' into the C4D "plugins"
folder.
*
restart c4d (or use the menu command "Reload Plugins")
*
Open the window "Console"
*
execute the plugin-menu command "coffee-lesson-6"
*
this time we really create a house :) Using data from the dialog box we
create an object with points and polygons, and deal with undo and system
messages.
The Listing:
const var cPlugName = "coffee-lesson-6";
const var cPlugHelp = "Creates a house";
const var cObjName = "House";
const var cHousePntAnz = 10;
const var cHousePolyAnz = 9;
const var cS1 = "Width";
const var cS2 = "Length";
const var cS3 = "Height";
const var cS4 = "rooftop";
const var cB1 = "new house";
const var cB2 = "reset";
const var cFMax = 1e3;
enum
{ eSlider=4000,eSlider1,eSlider2,eSlider3,eSlider4,
eBut=1000,eButNew,eButInit
}
const var cPluginID = 2000006;
var gDial,gHouse;
// --- House
class oHouse
{ public:
fNewHouse(vDoc);
fDimHouse(vObj,vB,vL,vH,vD);
}
oHouse::fNewHouse(vDoc)
{ var vObj,vPointAry,vPolyAry;
var vVarChanged,vBackupTags;
//
// aus SDK: BaseDocument
vObj=new(PolygonObject);
if (!vObj) return NULL;
vObj->SetName(cObjName);
//
vDoc->StartUndo();
vDoc->AddUndo(UNDO_OBJECT_NEW,vObj);
vDoc->EndUndo();
//
// aus SDK: VariableChanged
vVarChanged = new(VariableChanged);
vBackupTags = new(BackupTags);
//
vPointAry = new(array, cHousePntAnz);
vObj->SetPoints(vPointAry);
vBackupTags->Init(vObj);
vVarChanged->Init(0, cHousePntAnz);
if (!vObj->Message(MSG_POINTS_CHANGED, vVarChanged))
{ vBackupTags->Restore();
return NULL;
}
//
vPolyAry = new(array, cHousePolyAnz*4);
vObj->SetPolygons(vPolyAry);
vBackupTags->Init(vObj);
vVarChanged->Init(0, cHousePolyAnz);
if (!vObj->Message(MSG_POLYGONS_CHANGED, vVarChanged))
{ vBackupTags->Restore();
return NULL;
}
vDoc->InsertObject(vObj,NULL,NULL);
GeEventAdd(DOCUMENT_CHANGED);
//
return vObj;
}
oHouse::fDimHouse(vObj,vB,vL,vH,vD)
{ vObj->SetPoint(0,vector(-vB, 0,-vL));
vObj->SetPoint(1,vector( vB, 0,-vL));
vObj->SetPoint(2,vector( vB, 0, vL));
vObj->SetPoint(3,vector(-vB, 0, vL));
vObj->SetPoint(4,vector(-vB,vH,-vL));
vObj->SetPoint(5,vector( vB,vH,-vL));
vObj->SetPoint(6,vector( vB,vH, vL));
vObj->SetPoint(7,vector(-vB,vH, vL));
vObj->SetPoint(8,vector(0,vH+vD,-vL));
vObj->SetPoint(9,vector(0,vH+vD, vL));
//
vObj->SetPolygon(0, 0,3,2,1); // Floor
vObj->SetPolygon(1, 0,1,5,4); // 4x Wall
vObj->SetPolygon(2, 1,2,6,5);
vObj->SetPolygon(3, 2,3,7,6);
vObj->SetPolygon(4, 3,0,4,7);
vObj->SetPolygon(5, 5,6,9,8); // 2x Roof
vObj->SetPolygon(6, 8,9,7,4);
vObj->SetPolygon(7, 4,5,8,8); // 2x Triangle
vObj->SetPolygon(8, 6,7,9,9);
//
vObj->Message(MSG_UPDATE);
}
// --- GeDialog
class oDialog : GeDialog
{ public:
oDialog();
CreateLayout();
Init();
Command(vID,vMSG);
}
oDialog::oDialog() { super(cPluginID); }
oDialog::CreateLayout()
{ SetTitle(cPlugName);
AddGroupBeginV(eSlider,BFH_SCALEFIT,2,"",0);
{ AddStaticText(0,BFH_LEFT,0,0,cS1,0);
AddEditSlider(eSlider1,BFH_SCALEFIT,200,0);
AddStaticText(0,BFH_LEFT,0,0,cS2,0);
AddEditSlider(eSlider2,BFH_SCALEFIT,200,0);
AddStaticText(0,BFH_LEFT,0,0,cS3,0);
AddEditSlider(eSlider3,BFH_SCALEFIT,200,0);
AddStaticText(0,BFH_LEFT,0,0,cS4,0);
AddEditSlider(eSlider4,BFH_SCALEFIT,200,0);
}
AddGroupEnd();
AddGroupBeginV(eBut,BFH_CENTER,2,"",0);
{ AddButton (eButNew ,0,0,0,cB1);
AddButton (eButInit,0,0,0,cB2);
}
AddGroupEnd();
return TRUE;
}
oDialog::Init()
{ SetFloat(eSlider1, 80.0,1,cFMax,1.0);
SetFloat(eSlider2,120.0,1,cFMax,1.0);
SetFloat(eSlider3, 50.0,1,cFMax,1.0);
SetFloat(eSlider4, 30.0,1,cFMax,1.0);
return TRUE;
}
oDialog::Command(vID,vMSG)
{ var vDoc,vObj,vB,vL,vH,vD;
//
switch (vID)
{ case eButNew:
vDoc = GetActiveDocument();
if (!vDoc) return FALSE;
StopAllThreads();
if (!gHouse) gHouse=new(oHouse);
vObj=gHouse->fNewHouse(vDoc);
if (!vObj) return FALSE;
//
vB=GetFloat(eSlider1);
vL=GetFloat(eSlider2);
vH=GetFloat(eSlider3);
vD=GetFloat(eSlider4);
gHouse->fDimHouse(vObj,vB/2,vL/2,vH,vD);
break;
case eButInit:
Init();
break;
}
return TRUE;
}
// --- MenuPlugin
class oMenuPlugin : MenuPlugin
{ public:
oMenuPlugin();
GetID();
GetName();
GetHelp();
Execute(doc);
RestoreLayout(secret);
}
oMenuPlugin::oMenuPlugin() { super(); }
oMenuPlugin::GetID() { return cPluginID; }
oMenuPlugin::GetName() { return cPlugName; }
oMenuPlugin::GetHelp() { return cPlugHelp; }
oMenuPlugin::Execute(doc)
{ if (!gDial) gDial=new(oDialog);
gDial->Open(TRUE,-1,-1);
}
oMenuPlugin::RestoreLayout(secret)
{ if (!gDial) gDial=new(oDialog);
gDial->RestoreLayout(secret);
}
main()
{ Register(oMenuPlugin);
}
The
Explanation:
"case
eButNew:" in "oDialog::Command(vID,vMSG)" has changed a bit and "class
oHouse" has been added in comparison to coffee-lesson-5.
case eButNew:
GetActiveDocument()
- the name says it all. The dialog boxes are modal in comparison to Revision
5. That means they remain opened, other things can be clicked. This demands
a bit more work from the programmer, who has to deal with every possible
user's reaction. This is covered in coffee-lesson-7.
StopAllThreads()
is
also due to the modal property. It's better to stop all other jobs, than
to risk a collision with our job.
oHouse::fNewHouse(vDoc)
Not
only the dialog boxes have changed in CINEMA Revision 6, many things look
other than before. You have certainly noticed, that edges and the differentiation
between 3- and 4-sided polygons are gone.
VariableChanged and BackupTags
are
two of which (I admit) I haven't understood yet completely. The issue
is the internal information flow. Init(alt,New) decreases the number of
the Array, vBackupTags->Init(vObj) stores the action and with vBackupTags->Restore()
it is possible to undo the operation.
vPointAry = new(array, cHousePntAnz);
vObj->SetPoints(vPointAry);
This
reserves memory for the points which is given to the object. Same applies
for the polygons (3-sided and 4-sided are not handled different, anymore).
oHouse::fDimHouse(vObj,vB,vL,vH,vD)
You
will remember this if you have already programmed with C.O.F.F.E.E. R5.
SetPoint contains the X,Y,Z- coordinate of every point. SetPolygon defines
which points belong to this polygon. If you have 3-sided polygons, the
last both Point-Numbers are identical. It's recommendable to work with
a little scribble, on which you can number the points correctly. Ensure
that all surfaces use the same orientation. Enable "Edit polygons" in
CINEMA and choose the wireframe-view to see their normals.
----------------------------------------
Text copyright © H.
G. Seib 2000, HTML copyright © M. D. Abbott 2001
|