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. Call SteGetGeometry to force a compute and return of an SSteGeometry object.
  6. Pull needed data from SSteGeometry object using a recursive function.
  7. 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
 
            // this causes the api to compute the geometry from the model file definition already loaded
            SSteGeometry* pGeometry = SteGetGeometry(pEngine, &sGeometryOptions);
            if (pGeometry)
            {
                printf("\n[%s] has %s polys, %s vertices, and %s total indices.\n\n",
                       SpeedTree::FilenameNoPath(pModelFilename).c_str( ),
                       SpeedTree::FormatWithCommas(pGeometry->m_nNumPolygons).c_str( ),
                       SpeedTree::FormatWithCommas(pGeometry->m_nNumVertices).c_str( ),
                       SpeedTree::FormatWithCommas(pGeometry->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(pGeometry->m_pGeometryRoot);
 
                // using C, so no destructors
                SteDeleteGeometry(pGeometry);
 
                bSuccess = true;
            }
        }
 
        // using C, so no destructors
        SteDelete(pEngine);
    }
 
    return bSuccess;
}