Scripting
Scripting
Scripts in 3D-Coat are based on Angelscript that is very close to C++ syntax. Using scripts you may do virtually
everything that is possible within UI. Scripts are intended to perform batch actions, make own macro actions, create
interactive tutorials. At first you may look angelscript documentation to see general features of the language and
difference with C++:
http:angelcode.com/angelscript/sdk/docs/manual/doc_script.html
http:angelcode.com/angelscript/sdk/docs/manual/doc_understanding_as.html
Arrays:
http:angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_arrays.html
Strings:
http:angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_strings.html
It is easy to start writing scripts in 3D-Coat. Just click Scripts->Create your script and select template that is closest
to what you want to do. File will be opened in text editor, after edit you may save it and execute via Scripts->Run
script or from recent list in Scripts menu. Read carefully comments in a file that will be opened in text editor and
follow the recommendations.
Simple examples
This is example of a simple script to demonstate how to handle modal message boxes.
//declare any global variables if need, don't write commands ritght there, do it in main() of any other function.
//...
//This function will be called once when script will be run
//insert any commands there. Start from cmd as described above.
int n=0;
void main(){
// next command is optional, just to keep control of execution in modal message boxes (see
description //of ModalDialogCallback below), if you are new you may delete or ignore next line
SetModalDialogCallback("ModalDialogCallback");
// write your script right there
ModalDialog("This message will disappear soon"," ");
}
//Next function is mostly for advanced users. When you are calling or getting some modal message box you
are loosing control until user will press some button there.
//But each time when modal dialog will be show this function will be called and you may do some action inside
modal message box
void ModalDialogCallback(){
// Example of command - press first button in message box (uncomment next line if need)
if(n++>200)cmd("$DialogButton#1");/*press OK*/
}
Second example - processing all files in some folder. After running the script description dialog will be shown, then
user will be asked to choose files. At the end the number of processed files will be shown.
1
//declare any global variables if need, don't write commands ritght there, do it in main() of any other function.
//...
int nfiles;
//This function will be called once when script will be run
//insert any commands there
void main(){
nfiles=0;
//shows message box if need
if(ModalDialogOkCancel("Just write description there"," ")){
//This function will call void ForAnyFile(string &in FileName) for each file in user defined folder -
jpg and png are just for example
ForEachFileInFolder("","*.png;*.jpg","ForAnyFile");
ModalDialog(formatInt(nfiles,'l')+" files processed."," ");
}
}
//This function will be called for each file in user-defined folder
void ForAnyFile(string &in FileName){
//print there just for example, use Scripts->View execution log
print(FileName + "\n");
nfiles++;
}
A bit more advanced example - select files in folder, import, voxelize, smooth, export back with decimation:
//this is callback for dialog that asks if user needs to save scene after New command
void ModalDialogCallbackDontSave(){
cmd("$DialogButton#2");/*press Don't save - second button*/
}
//this is callback to press OK when user is asked to keep scale or not
void ModalDialogCallbackOk(){
cmd("$DialogButton#1");/*press OK*/
}
//this is callback for decimation dialog
void ModalDialogCallbackDecimation(){
SetSliderValue("$DecimationParams::ReductionPercent",80.0);
cmd("$DialogButton#1");/*press Ok*/
}
int nfiles;
void main(){
nfiles=0;
//This function will call void ForAnyFile(string &in FileName) for each file in user defined folder - stl and obj
are just for example
ForEachFileInFolder("","*.stl;*.obj","ForAnyFile");
ModalDialog(formatInt(nfiles,'l')+" files processed."," ");
}
Next example – trivial tutorial example. It just asks you to click File->New and checks if you done it. Pay attention to
Step function in cycle – it performs one step of rendering cycle in 3D-Coat.
void main(){
ModalDialog("Just some description there. Click OK to start."," ");
do{
Step(1); //Rendering cycle
ShowFloatingMessage("Please click File->New",1); //Show non-modal message
if(WasRecentlyPressed("$CLEARSCENE",15)){ //Check if New was pressed in last 15 sec
ModalDialog("Right, thanks!"," ");
return;
}
}while(GetTimeSinceStart()<40);
ModalDialog("Excuse, I can't wait anymore. Bye!"," ");
}
This is main command that you will use. It performs any action from user interface. To get the command ID hover
your mouse cursor over required item and press MMB+RMB simultaneously. The command ID will be copied to
clipboard. Pay attention that if a command is not present in current UV layout it will not be performed.
do n steps in 3D-Coat rendering process. Important if after performing the command you need UI refresh.
3
void InstallToMenu(string& path,string& ItemName)
Creates permanent new menu item that will run this script. Path is just path to menu like File.Export or Voxels or
Retopo. Script will be copied to Scripts/ExtraMenuItems/
Example:
InstallToMenu("File","Do some stuff");
Show model dialog with text identified ID. The ID is used to take translation from language .xml or just may be shown
directly if translation is not found.
Show dialog with text identified ID and two buttons - Ok and Cancel. Returns true if OK pressed, false if Cancel
pressed. The ID is used to take translation from language .xml or just may be shown directly if translation is not
found.
Show dialog with text identified ID and two buttons - Yes and No. Returns true if OK pressed, false if Cancel pressed.
ID used to take translation from language xml or just may be shown directly if translation not found.
Important! All dialogs may expose list of parameters and you are able to change value of any local or global variable
via dialogs. This is set of functions that allows to control additional parameters:
Each function that adds control passes variable name or other ID. Of course names of variables are are not always
obvious to end-user. So you may translate in on normal language and make correspondence between ID (name of
variable or any other ID in UI) and displayed text.
Add slider for integer vaiable. Variable shiuld be declared as int VariableName; in global or local scope.
void AddDelimiter();
Insert delimiter
Columns(2);
AddButton(“Function1”);
AddButton(“Function2”);
Add checkbox. BoolVarRef shoud refer existing boolean variable declared as bool VariableName;
Add droplist with several cases. Case index will be stored in IntVarRef variable. CaseList is list of possible values for
droplist, delimiters are ,;|
Example
Int Case=0;
…
AddDroplist(“Case”,”Case1,Case2,Case3”);
void StopUICondition();
bool ShowSlider1and2;
float Slider1;
float Slider2;
float Slider3;
bool CheckUI(){
return ShowSlider1and2;
}
void main(){
AddCheckBox("ShowSlider1and2");
5
UICondition("CheckUI");//function CheckUI should return true if elements below should be visible
AddFloatSlider("Slider1",0,123);
AddFloatSlider("Slider2",0,123);
StopUICondition();//This function ends scope of previous UICondition
AddFloatSlider("Slider3",0,123);//This slider is always visible
ModalDialogOkCancel("","");
}
//Making horn
float Angle=10;
int NumberOfChunks=20;
void main(){
AddTranslation(“NumberOfChunks”,” Number of chunks in horn”);
AddFloatSlider("Angle",0,90);
AddIntSlider("NumberOfChunks",1,40);
if(ModalDialogOkCancel("Please enter horn parameters","Making horn")){
ResetPrimTransform();
PrimDensity(0.3);
for(int i=0;i<NumberOfChunks;i++){
capsule(-15,0,0,15,0,0,20,20,0);
PrimRotateY(0,0,0,Angle);
PrimRotateX(0,0,0,Angle);
PrimTranslate(0,15,0);
PrimScaleAt(10,20,30,0.9,0.9,0.9);
ProgressBar("Please wait",(i*100)/NumberOfChunks);
}
}
}
Result:
This function should be called before you call any of modal dialogs function if you want to press button number
ButtonIndex (first button is 1, second is 2).
For example, if you have Yes and No buttons and you call PressInNextDialogs(1) before showing dialog then Yes will
be pressed automatically.
6
void SetModalDialogCallback(string &in name);
When you call any modal dialog the execution of the script will be stopped until user press Ok or other button in the
dialog.
Thus you are loosing control over dialog execution. If you want to do some action in the dialog, change some field
you need to setup routine.
that will be called constantly when dialog will be active. The routine may change fields in dialog, press buttons, and
do other things.
example:
int idx=0;
void DialogCallback(){
if(idx++>100)cmd("$DialogButton#1");/*press OK*/
}
void main(){
SetModalDialogCallback("DialogCallback");
ModalDialog("Hello!");
}
You may get the name of a current dialog name using next function.
void RemoveModalDialogCallbacks();
show non-modal message on screen that will be hidden after some period of time will pass (Time, sec).
returns true if you are in dialog now, also it retuns text and caption in a current dialog to identify it
int GetLastButtonIndex();
File dialogs
bool OpenDialog(string &in extensions,string &out result);
7
The resulting file name will be placed in result
show selecting folder dialog. The resulting file name will be placed in result
some functions in 3D-Coat may engage file dialog that will wait user's input. You may skip that dialogs and provide
file name automatically so that file dialog will return specified file name without waiting for user's input.
Use empty name "" to stop automatic file dialogs skipping othervice all next file dialogs will be skipped and it may
lead to loosing data.
bool FileDialogCancelPressed();
Call Callback for each file in folder. If Folder is empty used will be asked to choose file in folder
8
Check if element exists in UI. ID has same meaning as in cmd
void main(){
int n=0;
do{
string s="$ExtraLight::Color["+formatInt(n,"l")+"]";
if(FieldExists(s)){
n++;
}else break;
}while(true);
string s="Amount of lights = "+formatInt(n,"l");
ModalDialog(s,"");
}
set value of the boolean field in UI. ID has same meaning as in cmd
Get color field from UI as integer value. ID has same meaning as in cmd
set value of the color field in UI. ID has same meaning as in cmd
Substitute string or value to the next input text dialog. You need this command if there is button that triggers input
dialog to enter some text or value. Example - transform tool, ScaleY button. Code to scane object twice along Y axis:
SubstituteInputText(200.0);
cmd("$CubPrim::ScaleY");
Step(1);
Was widget with identifier ID recently (within last Time sec) pressed?
Was widget with identifier ID recently (within last Time sec) pressed via RMB?
Is user in tool identified as ID? To get current tool identifier press RMB+MMB over empty field
float GetTimeSinceStart();
Voxels management
bool IsSurface();
10
returns true if current volume is in surface mode
bool IsInCache();
void ToCache();
void FromCache();
string GetCurVolume();
Set surface/voxel mode for volume Surf=true - set surface mode, false - volume. It is same as click on S/V icon. If
silent=true then no dialogs will be shown, all will be done by default
select first volume in scene, if OnlyVisible==true then first visible volume will be selected
select next volume after current in tree, if OnlyVisible==true then next visible volume will be selected. Returns false
if current volume is last in list.
void main(){
string s=GetCurVolume();//keep current selection
SelectFirstVolume(true);
do{
//insert your action
}while( SelectNextVolume(true));
SetCurVolume(s);//restore initial selection
}
11
bool CurVolumeIsEmpty();
int GetCurVolumePolycount();
int GetVoxSceneVisiblePolycount();
string GetCurVolumeShader();
bool GetVolumeVisibility()
bool GetVolumeGhosting()
12
Set opacity of the current volume if the shader has corresponding property.
3D primitives management
You may create composition of 3D primitives in scene using functions below. It allows to create hardsurface scene in
non-destructive way. You may define some variables to define paraneters of the scene and get different variations of
your scene without complete re-sculpting. There are typical parameters of primitivesthat are self-obvious from the
names like x,y,z (coordinates), radius, height etc. Some primitives like cone and tube have only vertical alignment
(along Y) by default. To resolve such problems you may use transforms to rotate, spale and translate primitives in
space before merging. All transforms are additive and next transform will be applied in addition to all previous. If you
need to start from scratch with transform just use ResetPrimTransform(). For example, you need a cone placed at
point (10,20,30) and aligned aling X axis.
void main(){
ResetPrimTransform();
PrimRotateZ(10,20,30,90);
cone(10,20,30,10,20,0);
Each primitive has Mode parameter. It allows to perform different boolean operations
0 – add to scene, 1 – subtract from scene, 2 – intersect with scene.
void main(){
ResetPrimTransform();
PrimDensity(0.3);
for(int i=0;i<20;i++){
capsule(-15,0,0,15,0,0,20,20,0);
13
PrimRotateY(0,0,0,10);
PrimRotateX(0,0,0,10);
PrimTranslate(0,15,0);
PrimScaleAt(10,20,30,0.9,0.9,0.9);
ProgressBar("Please wait",(i*100)/36);
}
}
The list of related commands:
void ResetPrimTransform();
14
void PrimRotateAroundRode(float x,float y,float z,float xend,float yend,float zend,float Angle);
Set special transform for further primitives. If you will apply primitive that is placed between points (0,-1,0) and
(0,1,0) it will be actually applied as primitive stretched between points (x,y,z) and (xend,yend,zend)
Example:
void main(){
ResetPrimTransform();
PrimStretchBetweenPoints(10,20,30,40,50,60);//stretch between (10,20,30) and (40,50,60)
cylinder(0,-1,0,10,10,2,0);//starts from point (0,-1,0), radius=10, height=2
}
This code will create cylinder of radius 10 between points (10,20,30) and (40,50,60)
Set additional density factor for low-level primitives. 1 means default density.
string GetPrimTransform();
Store current transform for primitives as string to be kept for future usage
Restore current primitives transform from string that was previously kept using GetPrimTransform
Create ellipse
15
void cube(float x,float y,float z,float sizex,float sizey,float sizez,int mode);
Create parallelepiped.
Create cylinder.
Create cone.
void ngon(float x,float y,float z,int sides,float topradius,float bottomradius,float height,int mode);
Create N-gon
Create tube
void capsule(float x,float y,float z,float xend,float yend,float zend,float startradius,float endradius,int
mode);
16
string GetCurrentPaintLayerName();
Select paint layer with name ID. Returns false if layer not found.
Select lowest paint layer. If visible=true, first visible paint layer will be selected
Select next paint layer. Returns false if current layer is last and no new layer was selected.
bool GetPaintLayerVisibility()
Set blending mode of the current paint layer. ID-s are same as in English version
17
void SetPaintLayerDepthBlendingMode(string &in ID)
Set depth blending mode of the current paint layer. ID-s are same as in English version
string GetCurrentRetopoLayerName();
Select Retopo layer with name ID. Returns false if layer not found.
Select lowest Retopo layer. If visible=true, first visible Retopo layer will be selected
Select next Retopo layer. Returns false if current layer is last and no new layer was selected.
bool GetRetopoLayerVisibility()
18
Objects/materials/UV-sets management
int GetMaterialsCount()
Rename material
Delete material
Lock/unlock material
int GetObjectsCount()
Rename object
Lock/unlock object
19
int GetUVSetsCount();
Returns amount of UV sets. Pay attention that UV-set – related functions are room dependent. In retopo mesh it
operates with retopo mesh, in other rooms – with paint mesh.
Rename UV-set
Select all faces in current UV set and in current retopo group in room.
Miscellaneous
string getCommandLine();
Stores some string as global value that may be read later in the session. The value will be stored in 3B file and you
will be able to read in further work with this scene.
string GetSceneFileName()
20
void back(int steps=1);
Opens window described by xml-file pointed by Path. If Path contains .3b file will be opened as 3B file.
void imagemesh();
Import mesh for vertex painting, if path is empty dialog will be shown
Opens mesh for repairing. If id contains "vox" then model will be voxelized, if there is substring "shell" then mesh
will be imported as thin shell. Mesh Opening dialog will be shown.
void bass();
void undercut();
Activate special voxel tool. id may be found in English.xml between <ID>...</ID> if you will find name of tool between
<Text>...</Text> tags
void retopo();
21
Activate retopo tool
void retopopen();
Activate any room - name is one of "Paint", "Tweak", "UV", "Retopo", "Render"
check if you are in specified room - name is one of "Paint", "Tweak", "UV", "Retopo", "Render"
add new volume in voxel room. If name is empty name will be assigned automatically.
void uv();
Activate UV room
void vox();
void surf();
void cursurf();
void voxelize();
Sets merging options in voxel room. opt is just set of subbstring s with different options. Possible values are:
[voxelize=true]
[voxelize=false]
22
[separate=true]
[separate=false]
[respectneg=true]
[respectneg=false]
[as_skin=true]
[as_skin=false]
example: mergeopt("[voxelize=true][as_skin=true][skin=4.5]");
Merge model in voxel room. Empty string means that dialog will be shown.
void apply();
void ApplyAndKeepScale();
Apply in Merge tool without asking "Keep scale?". Scale will not be kept and scene scale will not be changed
void mapply();
Apply in current tool (same as press enter) wint one difference - in Merge tool scale of merged object sill be
automatically kept and scene scale changed if this merge is first.
void recent3b();
23
float randF(float min,float max);
float GetMouseX()
float GetMouseY()
float GetPressure()
bool LMBPressed()
bool RMBPressed()
bool MMBPressed();
24
Check if MMB pressed.
float GetVisiblePenRadius();
void EndStroke()
After that command stroke will be actually drawn. Set of commands StartStroke/ DrawStrokeTo should be
terminated by EndStroke
Example: the script will switch to retopo/strokes and draw 3 closed circles. It is better to assign hotkey for script
execution for convenience of checking.
void main(){
ToRoom("Retopo");
cmd("$[Page2]Strokes");/*Strokes*/
float x=GetMouseX();
float y=GetMouseY();
float r=100;
for(int p=0;p<3;p++){
for(int i=0;i<=32;i++){
float a=i*3.1415*2.0/32.0;
float dx=x+r*cos(a);
float dy=y+r*sin(a);
if(i==0)StartStroke(dx,dy,1);
else DrawStrokeTo(dx,dy,1);
}
EndStroke();
r+=30;
}
}
25