Houdini Engine 1.9
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Curves Samples

For documentation on the asset inputs APIs, see Curves.

The Curve Asset

For documentation on the curve asset, see The Curve Asset.

Below is a sample that creates a NURBS curve with 4 control points.

#include <HAPI\HAPI.h>
#include <string>
static std::string getString( HAPI_StringHandle string_handle )
{
// A string handle of 0 means an invalid string handle -- similar to
// a null pointer. Since we can't return NULL, though, return an empty
// string.
if ( string_handle == 0 )
return "";
int buffer_length;
HAPI_GetStringBufLength( string_handle, &buffer_length );
char * buf = new char[ buffer_length ];
HAPI_GetString( string_handle, buf, buffer_length );
std::string result( buf );
delete[] buf;
return result;
}
int main( int argc, const char * argv[] )
{
HAPI_CookOptions_Init( &cookOptions );
cookOptions.maxVerticesPerPrimitive = 4;
if ( HAPI_Initialize( NULL, NULL, &cookOptions, true, -1 ) != HAPI_RESULT_SUCCESS )
{
printf( "Error: couldn't initialize HAPI\n" );
return -1;
}
int curveId;
HAPI_CreateCurve( &curveId );
HAPI_AssetInfo assetInfo;
HAPI_GetAssetInfo( curveId, &assetInfo );
HAPI_NodeInfo nodeInfo;
HAPI_GetNodeInfo( assetInfo.nodeId, &nodeInfo );
// Get information about all the parameters.
HAPI_ParmInfo *parmInfos = new HAPI_ParmInfo[ nodeInfo.parmCount ];
assetInfo.nodeId, parmInfos, /*start=*/0, nodeInfo.parmCount );
// Also look for the parm named "coords", as underneath the covers we are dealing with
// Houdini curve node. Inspecting the curve node we see that the important parameter to
// set is the "coords" parameter.
int coordsParmIndex = -1;
int typeParmIndex = -1;
for ( int i = 0; i < nodeInfo.parmCount; ++i )
{
std::string parmName = getString( parmInfos[ i ].nameSH );
if ( parmName == "coords" )
{
coordsParmIndex = i;
}
if ( parmName == "type" )
{
typeParmIndex = i;
}
}
if ( coordsParmIndex == -1 || typeParmIndex == -1 )
{
printf( "Error: couldn't find coords/type parm on curve node\n" );
return -1;
}
HAPI_GetParameters( assetInfo.nodeId, &parm, typeParmIndex, 1 );
int typeIndex = 1; // Examining the node, we see 0 == poly curves, 1 == nurbs curves, 2 == bezier.
HAPI_SetParmIntValues( assetInfo.nodeId, &typeIndex, parm.intValuesIndex, 1 );
HAPI_GetParameters( assetInfo.nodeId, &parm, coordsParmIndex, 1 );
HAPI_SetParmStringValue( assetInfo.nodeId, "-4,0,4 -4,0,-4 4,0,-4 4.0,0,4 ", parm.id, 0 );
HAPI_SaveHIPFile( "testoutput.hip" );
return 0;
}

The output file, when opened in Houdini, shows the following:

HAPI_Curves_CurveInput.png

Curve Marshalling

For documentation on curve marshalling, see Curve Marshalling.

The following code uses curve marshalling to create the same curve as in The Curve Asset example:

#include <HAPI/HAPI.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_error() << endl; \
exit( 1 ); \
}
#define ENSURE_COOK_SUCCESS( result ) \
if ( (result) != HAPI_STATE_READY ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_cook_error() << endl; \
exit( 1 ); \
}
static std::string get_last_error();
static std::string get_last_cook_error();
static void wait_for_cook();
int
main( int argc, char **argv )
{
HAPI_CookOptions_Init( &cookOptions );
ENSURE_SUCCESS ( HAPI_Initialize( NULL, NULL, &cookOptions, true, -1 ) );
HAPI_AssetId inputAssetId;
ENSURE_SUCCESS( HAPI_CreateInputAsset( &inputAssetId, NULL ) );
ENSURE_SUCCESS( HAPI_CookAsset( inputAssetId, NULL ) );
wait_for_cook();
partInfo.vertexCount = 4;
partInfo.pointCount = 4;
partInfo.faceCount = 1;
partInfo.isCurve = true;
ENSURE_SUCCESS( HAPI_SetPartInfo( inputAssetId, 0, 0, &partInfo ) );
curveInfo.curveCount = 1;
curveInfo.isPeriodic = false;
curveInfo.order = 4;
curveInfo.hasKnots = true;
curveInfo.knotCount = 8;
ENSURE_SUCCESS( HAPI_SetCurveInfo( inputAssetId, 0, 0, 0, &curveInfo ) );
ENSURE_SUCCESS( HAPI_SetCurveCounts( inputAssetId, 0, 0, 0,
&partInfo.pointCount, 0, 1 ) );
attrInfo.count = 4;
attrInfo.tupleSize = 3; // 3 floats per CV (x, y, z)
attrInfo.exists = true;
ENSURE_SUCCESS( HAPI_AddAttribute( inputAssetId, 0, 0, "P", &attrInfo ) );
const float positions[] = { -4.0f, 0.0f, 4.0f,
-4.0f, 0.0f, -4.0f,
4.0f, 0.0f, -4.0f,
4.0f, 0.0f, 4.0f };
ENSURE_SUCCESS( HAPI_SetAttributeFloatData(
inputAssetId, 0, 0, "P", &attrInfo, positions, 0, attrInfo.count ) );
const float knots[] = { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f };
ENSURE_SUCCESS( HAPI_SetCurveKnots( inputAssetId, 0, 0, 0,
knots, 0, 8 ) );
ENSURE_SUCCESS( HAPI_CommitGeo( inputAssetId, 0, 0 ) );
ENSURE_SUCCESS( HAPI_SaveHIPFile( "testoutput.hip" ) );
return 0;
}
static void
wait_for_cook()
{
int status;
do
{
}
while ( status > HAPI_STATE_MAX_READY_STATE );
ENSURE_COOK_SUCCESS( status );
}
static std::string
get_last_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}
static std::string
get_last_cook_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}

Curve Output

For documentation on curve outputs, see Curve Output.

The code sample below shows loading the above asset via code, and displaying information about each of the curves above.

#include <HAPI/HAPI.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_error() << endl; \
exit( 1 ); \
}
#define ENSURE_COOK_SUCCESS( result ) \
if ( (result) != HAPI_STATE_READY ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_cook_error() << endl; \
exit( 1 ); \
}
static void print_curves_info( int asset_id, const HAPI_AssetInfo &asset_info );
static void dump_part_curves(
int asset_id, int object_id, int geo_id, int part_id );
static std::string get_string( HAPI_StringHandle string_handle );
static std::string get_last_error();
static std::string get_last_cook_error();
static void wait_for_cook();
int main( int argc, char **argv )
{
const char *otl_file = argc == 2 ? argv[ 1 ] : "C:/test/curvesTest.otl";
ENSURE_SUCCESS( HAPI_Initialize(
NULL,
/*dso_search_path=*/ NULL,
&cook_options,
/*use_cooking_thread=*/ true,
/*cooking_thread_max_size=*/ -1 ) );
int library_id;
int asset_id;
otl_file,
true,
&library_id ) != HAPI_RESULT_SUCCESS )
{
cout << "Could not load " << otl_file << endl;
exit( 1 );
}
HAPI_StringHandle asset_name_sh;
ENSURE_SUCCESS( HAPI_GetAvailableAssets( library_id, &asset_name_sh, 1 ) );
std::string asset_name = get_string( asset_name_sh );
asset_name.c_str(),
/* cook_on_load */ true,
&asset_id ) != HAPI_RESULT_SUCCESS )
{
cout << "Could not instantiate asset " << asset_name << endl;
exit( 1 );
}
wait_for_cook();
// Retrieve information about the asset.
HAPI_AssetInfo asset_info;
ENSURE_SUCCESS( HAPI_GetAssetInfo( asset_id, &asset_info ) );
// Print information about the curves contained inside the asset.
print_curves_info( asset_id, asset_info );
ENSURE_SUCCESS( HAPI_Cleanup() );
return 0;
}
static void wait_for_cook()
{
int status;
do
{
}
while ( status > HAPI_STATE_MAX_READY_STATE );
ENSURE_COOK_SUCCESS( status );
}
static void print_curves_info( int asset_id, const HAPI_AssetInfo &asset_info )
{
HAPI_ObjectInfo * object_infos =
new HAPI_ObjectInfo[ asset_info.objectCount ];
ENSURE_SUCCESS( HAPI_GetObjects(
asset_id, object_infos, /*start=*/ 0, asset_info.objectCount ) );
for ( int object_index = 0; object_index < asset_info.objectCount;
++object_index )
{
HAPI_ObjectInfo &object_info = object_infos[ object_index ];
for ( int geo_index = 0; geo_index < object_info.geoCount;
++geo_index )
{
HAPI_GeoInfo geo_info;
ENSURE_SUCCESS( HAPI_GetGeoInfo(
asset_id, object_info.id, geo_index, &geo_info ) );
for ( int part_index = 0; part_index < geo_info.partCount;
++part_index )
{
dump_part_curves( asset_id, object_info.id, geo_info.id, part_index );
}
}
}
delete [] object_infos;
}
static void dump_part_curves(
int asset_id, int object_id, int geo_id, int part_id )
{
cout << "object " << object_id << ", geo " << geo_id
<< ", part " << part_id << endl;
HAPI_PartInfo part_info;
ENSURE_SUCCESS( HAPI_GetPartInfo(
asset_id, object_id, geo_id, part_id, &part_info ) );
if ( part_info.isCurve )
{
HAPI_CurveInfo curve_info;
ENSURE_SUCCESS( HAPI_GetCurveInfo( asset_id, object_id, geo_id, part_id, &curve_info ) );
if ( curve_info.curveType == HAPI_CURVETYPE_LINEAR )
cout << "curve mesh type = Linear" << endl;
else if ( curve_info.curveType == HAPI_CURVETYPE_BEZIER )
cout << "curve mesh type = Bezier" << endl;
else if ( curve_info.curveType == HAPI_CURVETYPE_NURBS )
cout << "curve mesh type = Nurbs" << endl;
else
cout << "curve mesh type = Unknown" << endl;
cout << "curve count: " << curve_info.curveCount << endl;
int vertex_offset = 0;
int knot_offset = 0;
for ( int i = 0; i < curve_info.curveCount; i++ )
{
cout << "curve " << i + 1 << " of " << curve_info.curveCount << ":" << endl;
// Number of CVs
int num_vertices;
asset_id, object_id, geo_id, part_id, &num_vertices, i, 1 );
cout << "num vertices: " << num_vertices << endl;
// Order of this particular curve
int order;
if ( curve_info.order != HAPI_CURVE_ORDER_VARYING
&& curve_info.order != HAPI_CURVE_ORDER_INVALID )
order = curve_info.order;
else
HAPI_GetCurveOrders( asset_id, object_id, geo_id, part_id, &order, i, 1 );
cout << "curve order: " << order << endl;
// If there's not enough vertices, then don't try to create the curve.
if ( num_vertices < order )
{
cout << "not enought vertices on curve " << i << " of "
<< curve_info.curveCount << ": skipping" << endl;
// The curve at i will have numVertices vertices, and may have
// some knots. The knot count will be numVertices + order for
// nurbs curves.
vertex_offset += num_vertices * 4;
knot_offset += num_vertices + order;
continue;
}
HAPI_AttributeInfo attr_info_p;
asset_id, object_id, geo_id, part_id,
"P", HAPI_ATTROWNER_POINT, &attr_info_p
);
std::vector<float> p_array( attr_info_p.count * attr_info_p.tupleSize );
asset_id, object_id, geo_id, part_id,
"P", &attr_info_p,
&p_array.front(), 0, attr_info_p.count
);
HAPI_AttributeInfo attr_info_pw;
asset_id, object_id, geo_id, part_id,
"Pw", HAPI_ATTROWNER_POINT, &attr_info_pw
);
std::vector<float> pw_array( attr_info_pw.count * attr_info_pw.tupleSize );
asset_id, object_id, geo_id, part_id,
"Pw", &attr_info_pw,
&pw_array.front(), 0, attr_info_pw.count
);
for ( int j = 0; j < num_vertices; j++ )
{
cout << "cv " << j << ": " << p_array[ j * 3 + 0 ] << ","
<< p_array[ j * 3 + 1 ] << ","
<< p_array[ j * 3 + 2 ] << ","
<< pw_array[ j ] << endl;
}
if ( curve_info.hasKnots)
{
std::vector< float > knots;
knots.resize( num_vertices + order );
asset_id, object_id, geo_id, part_id, &knots.front(),
knot_offset, num_vertices + order );
for( int j=0; j < num_vertices + order; j++ )
{
cout << "knot " << j << ": " << knots[j] << endl;
}
}
// NOTE: Periodicity is always constant, so periodic and
// non-periodic curve meshes will have different parts.
// The curve at i will have numVertices vertices, and may have
// some knots. The knot count will be numVertices + order for
// nurbs curves.
vertex_offset += num_vertices * 4;
knot_offset += num_vertices + order;
}
}
}
static std::string get_string( HAPI_StringHandle string_handle )
{
// A string handle of 0 means an invalid string handle -- similar to
// a null pointer. Since we can't return NULL, though, return an empty
// string.
if ( string_handle == 0 )
return "";
int buffer_length;
ENSURE_SUCCESS( HAPI_GetStringBufLength( string_handle, &buffer_length ) );
char * buf = new char[ buffer_length ];
ENSURE_SUCCESS( HAPI_GetString( string_handle, buf, buffer_length ) );
std::string result( buf );
delete[] buf;
return result;
}
static std::string get_last_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}
static std::string get_last_cook_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}