Terragen tutorial page 2
From Odwiki
Back to the beginning: TerragenSOP
Define the user controls (filename, scale, offset, surface type)
Considering the Terragen Terrain file is so straight forward, there aren't a lot of user controls needed, perhaps a scale and offset control and a surface type control to allow the user to specify the type of surface to create (NURBS or mesh). The filename name is required to be able to specify and read the file.
Other controls under consideration: Point coloring based on elevation, noise and fBm controls to perturb the geometry, and export options for the exporter (yet to be written).
Build the GUI controls
There are some "idiosyncrasies" related to creating GUI's with the HDK. You can learn a lot from the sample code but it can be confusing so it's also a good idea to spend some time browsing the HDK Doxygen documentation and studying the class hierarchies (specifically, look at OP_Node, OP_Parameters, PRM_Parm, PRM_Type and PRM_Template to start with). My suggestion is to experiment a bit with the various parameter types until you feel comfortable with the process. Once you have done this a few times, adding and deleting GUI widgets become relatively easy.
For this SOP, we have a few controls for the user to apply an offset and scale to the geometry and also to select the type of surface to create. We also want to provide feedback to the user about the details of the Terragen Terrain file that is being read by the SOP.
Here we are defining a set of constants that give an "index" into the parameter template when reading and writing data from the GUI.
// User parameters #define ARG_FNAME (myParmBase + 0) #define ARG_SURF_TYPE (myParmBase + 1) #define ARG_SCALE (myParmBase + 2) #define ARG_OFFSET (myParmBase + 3) // "Feedback" fields #define ARG_SIZE (myParmBase + 4) #define ARG_XPTS (myParmBase + 5) #define ARG_YPTS (myParmBase + 6) #define ARG_TERRAIN_SCALE (myParmBase + 7) #define ARG_HEIGHT_SCALE (myParmBase + 8) #define ARG_BASE_HEIGHT (myParmBase + 9) #define ARG_RADIUS (myParmBase + 10) #define ARG_CRVM (myParmBase + 11)
For the GUI controls that need to have their values queried, we define a few functions to do the reading. Note in this example we are reading strings (UT_String, used for the filename), floats (for scale and offset values) and integers (to read a menu for the surface type to create).
void FNAME(UT_String &label, float t)
{ evalString(label, ARG_FNAME, 0, t); }
int SURFACE_TYPE(float t)
{ return evalInt(ARG_SURF_TYPE, 0, t); }
float SCALE(float t)
{ return evalFloat(ARG_SCALE, 0, t); }
float OFFSET(float t)
{ return evalFloat(ARG_OFFSET, 0, t); }
This is an example of building the GUI template; depending on the GUI you're building, you may have to define a number of things before actually getting to the PRM_Template definitions itself.
Here we are creating the user readable labels associated with the various GUI widgets:
// Define our parameter names
static PRM_Name names[] =
{
PRM_Name("fname", "Terragen File Name"),
PRM_Name("surf_type", "Surface Type"),
PRM_Name("scale", "Elevation Scale"),
PRM_Name("offset", "Elevation Offset"),
PRM_Name("size", "Size"),
PRM_Name("xpts", "XPTS"),
PRM_Name("ypts", "YPTS"),
PRM_Name("terrain_scale", "Terrain Scale"),
PRM_Name("height_scale", "Height Scale"),
PRM_Name("base_height", "Base Height"),
PRM_Name("radius", "Radius"),
PRM_Name("crvm", "CRVM"),
PRM_Name(0)
};
Here's the definition for the drop down menu for the surface type to create:
static PRM_Name theSurfaceTypeMenu[] = {
PRM_Name("0", "Mesh"),
PRM_Name("1", "NURBS"),
PRM_Name(0)
};
static PRM_ChoiceList surfaceTypeMenu((PRM_ChoiceListType)(PRM_CHOICELIST_EXCLUSIVE | PRM_CHOICELIST_REPLACE), theSurfaceTypeMenu);
These will help you provide default values and ranges for GUI widgets that the user can input values and/or create channels:
// Data ranges static PRM_Range dataRangeOffset(PRM_RANGE_UI, -1000, PRM_RANGE_UI, 1000); static PRM_Range dataRangeScale(PRM_RANGE_UI, 0, PRM_RANGE_UI, 1000); static PRM_Default dataDefault0(0.0); static PRM_Default dataDefault1(1.0); // Filename defaults static PRM_Default nameDefault1(0,"untitled.ter");
Now we build the actual "template" for the SOP's GUI Interface:
// Built the parameter template
PRM_Template
SOP_Terragen::myTemplateList[] =
{
// Filenames for the image input files
PRM_Template(PRM_FILE, 1, &names[0], &nameDefault1,0),
// Surface type menu (mesh or NURBs)
PRM_Template(PRM_ORD, 1, &names[1], PRMzeroDefaults,
&surfaceTypeMenu, 0, SOP_TerraGen::updateTheMenu),
// Data scale and offset factor
PRM_Template(PRM_FLT_J, 1, &names[2], &dataDefault1, 0, &dataRangeScale),
PRM_Template(PRM_FLT_J, 1, &names[3], &dataDefault0, 0, &dataRangeOffset),
// Size, xpts, ypts
PRM_Template(PRM_LABEL, 1, &names[4]),
PRM_Template(PRM_LABEL, 1, &names[5]),
PRM_Template(PRM_LABEL, 1, &names[6]),
// Terrain scale (vector), height scale, base height
PRM_Template(PRM_LABEL, 1, &names[7]),
PRM_Template(PRM_LABEL, 1, &names[8]),
PRM_Template(PRM_LABEL, 1, &names[9]),
// Radius & crvm
PRM_Template(PRM_LABEL, 1, &names[10]),
PRM_Template(PRM_LABEL, 1, &names[11]),
PRM_Template()
}



