Houdini Engine 7.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Parameters

Query Parameter Info

You can get a node's parameter information like so:

  1. Fill a HAPI_NodeInfo struct using HAPI_GetNodeInfo(), as described in Nodes Basics.
  2. Allocate an array of HAPI_NodeInfo::parmCount HAPI_ParmInfo's.
  3. Call HAPI_GetParameters() with the HAPI_NodeInfo::id, the array you just allocated, 0 as the start and HAPI_NodeInfo::parmCount as the length. You can of course specify a more selective range.

You now have one or more HAPI_ParmInfo's. The main idea here is that there are several categories of information about the parameter that the data in this structure is encoding:

  • Basic information about the parameter including its id, type, name, label, tuple size, and information on how to retrieve the actual values of the parameter in the form of an index into a different values array. This structure does NOT contain the value of the parameter.
  • The hierarchy information about the parameter as parenting status.
  • More meta data about how the parameter should be presented to the user, such as the minimum and maximum UI values, whether the labels should be shown, whether the parameter is hidden, and whether the parameter should appear on the same line as the next one.

There are a couple of useful helper functions that operate on the HAPI_ParmInfo:

Getting Values

The values of a parameter are not stored in the HAPI_ParmInfo. Instead, the values are stored in separate arrays, each array containing all the values of a specific raw data type (such as int and float) of all parameters. These arrays are retrieved using:

The values pertaining to a specific parameter can be retrieved from the relevant array using HAPI_ParmInfo::intValuesIndex, HAPI_ParmInfo::floatValuesIndex, HAPI_ParmInfo::stringValuesIndex, or HAPI_ParmInfo::choiceIndex, along with HAPI_ParmInfo::size for the number of values.

Alternatively, for int, float, and string parameters, you can get single values using:

Setting Values

The values of a parameter are not stored in the HAPI_ParmInfo. Instead, the values are stored in separate arrays, each array containing all the values of a specific raw data type (such as int and float) of all parameters. The values in these arrays can be written to using:

The values pertaining to a specific parameter can be set in the relevant array using HAPI_ParmInfo::intValuesIndex, HAPI_ParmInfo::floatValuesIndex, HAPI_ParmInfo::stringValuesIndex, or HAPI_ParmInfo::choiceIndex, along with HAPI_ParmInfo::size for the number of values.

String parameter values can only be set one at a time using HAPI_SetParmStringValue(). For convenience, there are also single-parameter variants for HAPI_SetParmIntValue() and HAPI_SetParmFloatValue().

Note
Regardless of the value, when setting a parameter value, if that parameter has a callback function attached to it, that callback function will be called. For example, if the parameter is a button the button will be pressed.

After setting parameter values make sure you cook your asset as described in Cooking.

Incremental Updates

After the asset has been cooked again after a parameter change, the results of the asset need to updated. However, it may be the case that not everything needs updating. To make things more efficient, there are a number of fields on each of HAPI_ObjectInfo and HAPI_GeoInfo to identify the minimum pieces that need to be updated:

Tabs and Folders

Understanding how to get and set parameter values, the next thing is to format the parameters properly for display to the user. Of course, you could present all the parameters as a giant list, but that wouldn't be the proper user experience. The HAPI_ParmInfo structs that you retrieved earlier have all the information you need to properly format the parameters for display and be consistent with how Houdini displays them.

The parameters have not only a label, name, and value, but also a hierarchy. The set of all parameters can be thought of as a big tree, with folders and leaf nodes representing individual parameters with user settable values.

This hierarchy can be explicitly reconstructed from the HAPI_ParmInfo array by using the HAPI_ParmInfo::id and HAPI_ParmInfo::parentId. However, such a reconstruction would be complex and inefficient, requiring scanning the HAPI_ParmInfo array in many passes.

A better approach is to utilize the implicit information passed through the ordering of the HAPI_ParmInfo. The HAPI_ParmInfo array is essentially a flattened version of the tree. By understanding the order of traversal of the tree, it is possible to reconstruct the original parameter tree. The rules are as follows:

  1. Parameters of type within HAPI_PARMTYPE_CONTAINER_START and HAPI_PARMTYPE_CONTAINER_END such as HAPI_PARMTYPE_FOLDERLIST and HAPI_PARMTYPE_FOLDERLIST_RADIO, and the HAPI_PARMTYPE_FOLDER type have a child count associated with them. The child count is indicated by their HAPI_ParmInfo::size.
  2. Parameters of type within HAPI_PARMTYPE_CONTAINER_START and HAPI_PARMTYPE_CONTAINER_END can only contain folders. HAPI_PARMTYPE_FOLDER's cannot contain other HAPI_PARMTYPE_FOLDER's, only HAPI_PARMTYPE_CONTAINERs and regular parameters.
  3. When a parameter of type within HAPI_PARMTYPE_CONTAINER_START and HAPI_PARMTYPE_CONTAINER_END is encountered, we should dive into its contents immediately, while everything else is traversed in a breadth first manner.

A practical example should make this clear. Suppose we have the following hierarchy of parameters:

HAPI_Parameters_TabsAndFolders.jpg

The traversal of the above graph should look like this:

  1. FolderList1 - size 3
  2. Folder1 - size 2
  3. Folder2 - size 2
  4. Folder3 - size 2
  5. param1
  6. param2
  7. FolderList2 - size 2
  8. Folder4 - size 1
  9. Folder5 - size 2
  10. param4
  11. param5
  12. param6
  13. param3
  14. param7
  15. param8
  16. param9

Note that while there is a notion of the root item, in reality it doesn't exist. Parameters that are children of the root will have a HAPI_ParmInfo::parentId of -1.

Radio Button Tabs

Radio button tabs are special in that they behave both like a HAPI_PARMTYPE_FOLDERLIST and a HAPI_PARMTYPE_INT. You will know the current parameter is a radio button folder list by the type HAPI_PARMTYPE_FOLDERLIST_RADIO.

When parsing them, treat them like a HAPI_PARMTYPE_FOLDERLIST. Afterwards, to determine which tab is selected, get the int value using HAPI_GetParmIntValue() or HAPI_GetParmIntValues() as you would a regular integer parameter - always using index of 0, regardless of HAPI_ParmInfo::size. See note below. Setting the tab selection is also done as with any other integer parameter.

Note
Radio button tabs use HAPI_ParmInfo::size to indicate the total number of tabs. When treated like a regular HAPI_PARMTYPE_INT parameter, the HAPI_ParmInfo::size will imply that there are size many int values when in fact there is only one. To get around this, and be consistent with how Houdini handles radio button tabs, Houdini Engine will set ALL the int values to the same value and will return the same int value regardless of which index is given to HAPI_GetParmIntValue(), for example. You should only ever query the first index of a HAPI_PARMTYPE_FOLDERLIST_RADIO.
HAPI_AssetLibraryId library_id = -1;
hapiTestSession, "HAPI_Test_Parameters_RadioButtonTabs.otl",
false, &library_id );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Instantiate the asset.
HAPI_NodeId node_id = -1;
result = HAPI_CreateNode(
hapiTestSession, -1, "Object/HAPI_Test_Parameters_RadioButtonTabs",
nullptr, true, &node_id );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// We explicitly enable sphere and box support so we can easily check
// which branch of the Switch SOP is currently being cooked.
// It should be:
// - Sphere for radio tab 0
// - Box for radio tab 1
cook_options.handleBoxPartTypes = true;
cook_options.handleSpherePartTypes = true;
result = HAPI_CookNode( hapiTestSession, node_id, &cook_options );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Get the radio button tab (folder list) parm info.
HAPI_ParmInfo parm_info;
hapiTestSession, node_id, "radio_button_tabs", &parm_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( parm_info.type == HAPI_PARMTYPE_FOLDERLIST_RADIO );
HAPI_TEST_ASSERT( parm_info.size == 2 );
HAPI_TEST_ASSERT( parm_info.intValuesIndex >= 0 );
// Find which radio button tab is selected.
int selected_radio_tab = -1;
hapiTestSession, node_id, "radio_button_tabs", 0,
&selected_radio_tab );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( selected_radio_tab == 0 );
// Get display geo.
result = HAPI_GetDisplayGeoInfo( hapiTestSession, node_id, &geo_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Make sure the first tab selected means we cook the sphere branch.
HAPI_PartInfo part_info;
result = HAPI_GetPartInfo(
hapiTestSession, geo_info.nodeId, 0, &part_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( part_info.type == HAPI_PARTTYPE_SPHERE );
// Switch to the second tab (the box tab).
hapiTestSession, node_id, "radio_button_tabs", 0, 1 );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Cook the asset.
result = HAPI_CookNode( hapiTestSession, node_id, &cook_options );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Check the value again.
selected_radio_tab = -1;
hapiTestSession, node_id, "radio_button_tabs", 0,
&selected_radio_tab );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( selected_radio_tab == 1 );
// Check the we are now outputing the Box.
result = HAPI_GetPartInfo(
hapiTestSession, geo_info.nodeId, 0, &part_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( part_info.type == HAPI_PARTTYPE_BOX );

Choice Lists

The handling of multiple choice type parameters needs special mention. These parameters make use of both the HAPI_ParmInfo::choiceCount and HAPI_ParmInfo::choiceIndex values to retrieve the range of possible choices.

Choice lists in Houdini can be one of two types:

  • ints
  • strings

Parameter types such as float (and any others) cannot be made a choice list. You can tell if a parameter is a choice list by looking at the HAPI_ParmInfo::choiceCount parameter. If this parameter is 0, then it is not a choice list, otherwise, it is. Where strings are concerned, there can be a token string as well as the label that appears for the user:

HAPI_Parameters_ChoiceLists_Strings.png

Note that for int menus, the same UI is currently available for the tokens, but the values for the tokens are not used. Given the available choices, the actual choice that the user has made can be arrived at as follows:

For example, if I had a 3-choice dropdown that had labels of "Yes", "No", and "Maybe", then the HAPI_ParmInfo::choiceCount would be 3. Let's suppose the HAPI_ParmInfo::choiceIndex was 10, then the possible string labels of "Yes", "No", and "Maybe" would be stored at location 10, 11, and 12 of the parameter choices array from the call to HAPI_GetParmChoiceLists(). The actual choice the user has made, however, will be the string values of "Y", "N", and "M" - and as mentioned above the value can be retrieved with HAPI_ParmInfo::stringValuesIndex.

Here is another example for an int menu: Let's say we have a 3 choice drop down that had the labels of "choice 1", "choice 2", and "choice 3". Let's suppose the choiceIndex was 5, then the possible string labels of "choice 1", "choice 2", and "choice 3" would be stored at location 5, 6, and 7 of the parameter choices array from the call to HAPI_GetParmChoiceLists(). The actual choice the user has made, however, will be the int value of 0, 1, 2 - and as mentioned above the value can be retrieved with HAPI_ParmInfo::intValuesIndex.

Finally, there is a type of parameter that is called "Ordered Menu". This is equivalent to an int menu.

Notice that there isn't a setter function that mirrors the HAPI_GetParmChoiceLists() function. This is because the only thing that can be set with choice lists is the actual choice that the user has made, and that is represented as an integer, or string, as we mentioned earlier.

MultiParms

Multiparms deserve special mention because in essence they are dynamic parameters that can grow or shrink in size as the user interacts with them. For example, clicking on the "+" button in the UI below will result in another available image plane to be created:

HAPI_Parameters_MultiParms_Plus.png

There are two concepts that are core to multiparms: the number of instances and the number of parameters within the multiparm. For example, a multiparm could have 3 instances, where each instance of the multiparm contains 4 individual parameters:

HAPI_Parameters_MultiParms_Instances.png

To work with multiparms, first one must be able to identify a multiparm from other types of parameters. If a parameter is a multiparm, its HAPI_ParmInfo::type will be set to HAPI_PARMTYPE_MULTIPARMLIST.

The number of parameters a multiparm contains per instance is given by the HAPI_ParmInfo::instanceLength. The total number of instances is given by the HAPI_ParmInfo::instanceCount. Instance numbers can start either from 0 or 1 which is given by HAPI_ParmInfo::instanceStartOffset.

Each instance parameter of the multiparm has its own HAPI_ParmInfo struct. In these cases, their type will NOT be set to HAPI_PARMTYPE_MULTIPARMLIST. Instead, the child parameters are identified by the HAPI_ParmInfo::isChildOfMultiParm, which will be set to true. The instance that this child belongs to will be identified by the HAPI_ParmInfo::instanceNum. Also, in this case, the HAPI_ParmInfo::parentId will the the HAPI_ParmId of the HAPI_ParmInfo whose type was set to HAPI_PARMTYPE_MULTIPARMLIST. In the above example, where a multiparm has 3 instances of 4 individual parameters each, the total number of relevant HAPI_ParmInfo will be 13: 1 for the parent multiparm (HAPI_ParmInfo::type set to HAPI_PARMTYPE_MULTIPARMLIST), and 3 x 4 = 12 individual entries for each of the instances of the individual parameters. All of these parameters are to be contiguous in the parameter array.

To change the value of a parameter of an instance of a multiparm (more precisely, a parameter which has the HAPI_ParmInfo::isChildOfMultiParm set to true), all the existing parameter APIs apply.

To add and remove instances to and from a multiparm use HAPI_InsertMultiparmInstance() and HAPI_RemoveMultiparmInstance(). After calling these functions, you must currently refresh your UI, as the parameter layout may have changed completely. That is, start again from Query Parameter Info.

Presets

In order to persist an asset in the same state that a user has left it after manipulation, it would be useful to have a representation of the state of all of the parameters of the asset. At a later time, the same representation of the asset parameters could be pushed back onto the asset in order to restore state.

To this end, Houdini Engine supports the generation of presets, and the restoration of the asset parameters based on the presets. The presets are essentially a binary representation of the state of the parameters of a node. Note that an asset is essentially a special case of a node. We can retrieve a preset for a particular node and restore a node's parameters based on the preset with the following three functions:

There are also two types of presets supported:

  • HAPI_PRESETTYPE_BINARY - Just the presets binary blob. The option with the smallest memory footprint.
  • HAPI_PRESETTYPE_IDX - Saves the presets blob within an IDX file format which can be loaded within Houdini. It also means you can load Houdini preset files within Engine. It does take a bit more memory though.

Query Parameters from Asset Definition

Parameter information and their default values can be queried from an asset without needing to create the asset node. This can save time when using assets that take too long to create their respective nodes, and when only the default parameters are needed. The following specialized functions allow to query parameters from directly from an asset definition: HAPI_GetAssetDefinitionParmCounts, HAPI_GetAssetDefinitionParmInfos, HAPI_GetAssetDefinitionParmValues.

The following describes the recommended steps to use these functions:

  1. Load asset library using HAPI_LoadAssetLibraryFromFile.
  2. Find number of assets within the library using HAPI_GetAvailableAssetCount.
  3. Get names of assets within the library using HAPI_GetAvailableAssets.
  4. Get the number of parameters and sizes of int, float, string, and choice value buffers using HAPI_GetAssetDefinitionParmCounts.
  5. Allocate an array of HAPI_NodeInfo structs of size retrieved from HAPI_GetAssetDefinitionParmCounts.
  6. Populate a number of HAPI_NodeInfo structs using HAPI_GetAssetDefinitionParmInfos.
  7. Allocate arrays of int, float, string, and choice value buffers with sizes retrieved from HAPI_GetAssetDefinitionParmCounts.
  8. Populate the int, float, string, and choice default values using HAPI_GetAssetDefinitionParmValues.

Note that these functions will require a Houdini or Houdini Engine license.