User Tools

Site Tools


Example: Spines

This example focuses on how to query only the spine data from a tree model. While this can be done with either a flat organization or hierarchically, we use hierarchical in this example because this is more commonly done with spine data.

#include <cstdio>
#include "speedtree_engine.h"
 
///////////////////////////////////////////////////////////////////////
//  SpeedTree Engine API error callback
 
static void MyEngineApiErrorCallback(const char* pError)
{
    fprintf(stderr, "    **[Error Report from SpeedTree Engine API]**: %s\n", pError);
}
 
 
///////////////////////////////////////////////////////////////////////
//  SpeedTree Engine API message callback
 
static void MyEngineApiMessageCallback(const char* pMessage)
{
    fprintf(stderr, "    [Message from SpeedTree Engine API]: %s\n", pMessage);
}
 
 
///////////////////////////////////////////////////////////////////////
//  RecurseThroughSpines
 
static void RecurseThroughSpines(const SSteGeometryBlock* pNode, int nLevel = 0)
{
    if (pNode->m_nNumSpineVertices > 1)
    {
        Indent(nLevel);
        printf("spine at level %d:\n", nLevel);
        for (int i = 0; i < pNode->m_nNumSpineVertices; ++i)
        {
            // use m_vWindyPos instead of m_vBasePos if wind enabled
            const SSteVec3& vPos = pNode->m_pSpineVertices[i].m_vBasePos;
 
            Indent(nLevel);
            printf("  p%d: (%g, %g, %g)\n", i, vPos.x, vPos.y, vPos.z);
        }
    }
 
    for (int i = 0; i < pNode->m_nNumChildren; ++i)
        RecurseThroughSpines(pNode->m_pChildren[i], nLevel + 1);
}
 
 
///////////////////////////////////////////////////////////////////////
//  Example_Spines
 
bool Example_Spines(const char* pModelFilename)
{
    bool bSuccess = false;
 
    // register callback message functions; when api calls fail, messages will be sent here
    SteSetErrorFunction(MyEngineApiErrorCallback);
    SteSetMessageFunction(MyEngineApiMessageCallback);
 
    // uses a C interface -- objects are created and initialized through function calls
    SSteEngine* pEngine = SteNew( );
    if (pEngine)
    {
        // this causes the model file to be loaded and parsed, but nothing is computed yet
        if (SteLoadSpeedTreeFile(pEngine, pModelFilename) == STE_SUCCESS)
        {
            // geometry export options
            SSteGeometryOptions sGeometryOptions;
            SteInitGeometryOptions(pEngine, &sGeometryOptions);
            sGeometryOptions.m_bExport3dGeometry = false;
            sGeometryOptions.m_bExportBranchSpines = true;
            sGeometryOptions.m_eResolution = STE_RESOLUTION_HIGH;
            sGeometryOptions.m_eGroupType = STE_GROUP_BY_HIERARCHY;
            sGeometryOptions.m_nHierarchy = 4; // will generate many separate nodes
 
            // pull over the geometry
            SSteGeometry* pGeometry = SteGetGeometry(pEngine, &sGeometryOptions);
            if (pGeometry)
            {
                // because STE_GROUP_BY_HIERARCHY is used, we need to traverse a tree
                RecurseThroughSpines(pGeometry->m_pGeometryRoot);
 
                // using C, so no destructors
                SteDeleteGeometry(pGeometry);
 
                bSuccess = true;
            }
        }
 
        // using C, so no destructors
        SteDelete(pEngine);
    }
 
    return bSuccess;
}