home
portfolio
services
notebook
links
This way out

 

 

 

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

 

 


Vantage Graphics and Design Limited
9 Vicarage Lane, Harbury, LEAMINGTON SPA, Warwickshire CV33 9HA, UNITED KINGDOM
Telephone: 01926 614211 Fax: 01926 614226 ISDN: 01926 614210
E-mail: studio@vgd.co.uk

Page last updated: 05 July 2001