User Tools

Site Tools


Example: Hierarchical Geometry Query

This example focuses on how geometry will be queried when the hierarchical arrangement is important. When SSteGeometryOptions::m_eGroupType is set to STE_GROUP_BY_HIERARCHY, SSteGeometry::m_pGoemetryRoot is the root of a tree of variable width and depth. This example shows how to traverse it.

A simpler approach that ignores the hierarchy is available here.

Most queries are set up similarly to this example. The general set up is:

  1. Make sure the callbacks are set (done once per application lifetime).
  2. Allocate a new SSteEngine object.
  3. Load the SpeedTree Model file (STE or SPM).
  4. Create, init, and set the query options using SSteGeometryOptions.
  5. Create and init the SSteGeometry object to hold the data.
  6. Call SteGetGeometry to force a compute and population of the SSteGeometry object.
  7. Pull needed data from SSteGeometry object using a recursive function.
  8. Clean up by deleting the SSteGeometry and SSteEngine objects.
#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);
}
 
 
///////////////////////////////////////////////////////////////////////
//  Indent
 
inline void Indent(int nLevel)
{
    for (int i = 0; i < nLevel; ++i)
        printf("   ");
}
 
 
///////////////////////////////////////////////////////////////////////
//  RecurseThroughGeometry
 
static void RecurseThroughGeometry(const SSteGeometryBlock* pNode, int nLevel = 0)
{
    Indent(nLevel); printf("---- NODE at level %d ---\n", nLevel);
 
    // mesh data
    Indent(nLevel); printf("  # meshes: %d\n", pNode->m_nNumMeshes);
    Indent(nLevel); printf("  # vertices: %d\n", pNode->m_nNumVertices);
 
    Indent(nLevel); printf("---- %d %s\n\n", 
        pNode->m_nNumChildren, 
        pNode->m_nNumChildren == 1 ? "child -----------" : "children --------");
 
    for (int i = 0; i < pNode->m_nNumChildren; ++i)
        RecurseThroughGeometry(pNode->m_pChildren[i], nLevel + 1);
}
 
 
///////////////////////////////////////////////////////////////////////
//  Example_HierarchicalGeometryAccess
 
bool Example_HierarchicalGeometryAccess(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); // functions used to init most structs
            sGeometryOptions.m_eResolution = STE_RESOLUTION_HIGH;
            sGeometryOptions.m_eGroupType = STE_GROUP_BY_HIERARCHY;
            sGeometryOptions.m_nHierarchy = 2; // how far down the hierarchy to separate geometry; 0 = one level,
                                               // 1 = trunk one level, everything else in another, so forth
 
            // init structure to hold generated geometry
            SSteGeometry sGeometry;
            SteInitGeometry(&sGeometry);
 
            // this causes the api to compute the geometry from the model file definition already loaded
            if (SteGetGeometry(pEngine, &sGeometryOptions, &sGeometry) == STE_SUCCESS)
            {
                printf("\n[%s] has %s polys, %s vertices, and %s total indices.\n\n",
                       SpeedTree::FilenameNoPath(pModelFilename).c_str( ),
                       SpeedTree::FormatWithCommas(sGeometry.m_nNumPolygons).c_str( ),
                       SpeedTree::FormatWithCommas(sGeometry.m_nNumVertices).c_str( ),
                       SpeedTree::FormatWithCommas(sGeometry.m_nNumIndices).c_str( ));
 
                // because STE_GROUP_BY_HIERARCHY is used, we have to traverse a tree; other group types can
                // be traversed in a simple loop
                RecurseThroughGeometry(sGeometry.m_pGeometryRoot);
 
                // using C, so no destructors
                SteDeleteGeometry(&sGeometry);
 
                bSuccess = true;
            }
        }
 
        // using C, so no destructors
        SteDelete(pEngine);
    }
 
    return bSuccess;
}