====== 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 [[example_typical|here]]. Most queries are set up similarly to this example. The general set up is: - Make sure the callbacks are set (done once per application lifetime). - Allocate a new **SSteEngine** object. - Load the SpeedTree Model file ([[input|STE or SPM]]). - Create, init, and set the query options using **SSteGeometryOptions**. - Create and init the **SSteGeometry** object to hold the data. - Call **SteGetGeometry** to force a compute and population of the **SSteGeometry** object. - Pull needed data from **SSteGeometry** object __using a recursive function__. - Clean up by deleting the **SSteGeometry** and **SSteEngine** objects. #include #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; }