====== Example: Typical Geometry Query ====== This example focuses on how geometry will be queried by most users. When **STE_GROUP_BY_GEOMETRY_TYPE** and **STE_GROUP_BY_MATERIAL** are used for **SSteGeometryOptions::m_eGroupType**, all of the geometry is contains in a variable number of nodes directly underneath **SSteGeometry::m_pGoemetryRoot**. This keeps things relatively simply. However, when **STE_GROUP_BY_HIERARCHY** is used, **SSteGeometry::m_pGoemetryRoot** is the root of a tree of variable width and depth. An example of traversing this data is [[example_hierarchy|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**. - Call **SteGetGeometry** to force a compute and return an **SSteGeometry** object. - Pull needed data from **SSteGeometry** object. - Clean up by deleting the **SSteGeometry** and **SSteEngine** objects. #include #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); } /////////////////////////////////////////////////////////////////////// // Example_GeneralGeometryAccess bool Example_GeneralGeometryAccess(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_MEDIUM; sGeometryOptions.m_eGroupType = STE_GROUP_BY_MATERIAL; // 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( )); // if sGeometryOptions.m_eGroupType was set to STE_GROUP_BY_HIERARCHY, we'd have to walk a tree // but using any other option, a simple loop will do // // each child under sGeometry.m_pGeometryRoot represents geometry that shares the same material for (int i = 0; i < pGeometry->m_pGeometryRoot->m_nNumChildren; ++i) { const SSteGeometryBlock* pChild = pGeometry->m_pGeometryRoot->m_pChildren[i]; // should always be one mesh when using STE_GROUP_BY_MATERIAL assert(pChild->m_nNumMeshes == 1); assert(pChild->m_pMeshes); // mesh data const SSteMesh* pMesh = pChild->m_pMeshes; printf(" child %d of %d:\n", i + 1, pGeometry->m_pGeometryRoot->m_nNumChildren); printf(" # meshes: %d\n", pChild->m_nNumMeshes); printf(" # faces: %d\n", pMesh->m_nNumFaces); printf(" # indices: %d\n", pMesh->m_nNumIndices); // mesh indices index pChild->m_pVertices printf(" # vertices: %d (first 3 indexed follow)\n", pChild->m_nNumVertices); for (int j = 0; j < 3 && j < pChild->m_nNumVertices; ++j) { int nIndex = pMesh->m_pIndices[j]; const SSteVec3& vPos = pChild->m_pVertices[nIndex].m_vPos; printf(" pos %d: (%g, %g, %g)\n", j, vPos.x, vPos.y, vPos.z); } // material data const SSteMaterial* pMeshMaterial = pGeometry->m_pMaterials + pMesh->m_nMaterialIndex; printf(" material name: '%s'\n", pMeshMaterial->m_szName); printf(" color map filename: '%s'\n", pMeshMaterial->m_aMaps[STE_MAP_COLOR].m_szFilename); printf("\n"); } // using C, so no destructors SteDeleteGeometry(pGeometry); bSuccess = true; } } // using C, so no destructors SteDelete(pEngine); } return bSuccess; }