====== Example: Bones ====== Querying a model's bone data is straightforward. It is not organized in a hierarchical tree as the [[example_spines|spine data]] is, but as a single array. Each bone is stored in an **SSteBone** structure: struct SSteBone { int m_nID; // zero-based bone ID indexes SSteGeometry::m_pBones int m_nParentID; // -1 = no parent, zero-based otherwise SSteVec3 m_vStart; // position of one end SSteVec3 m_vEnd; // position of other end float m_fRadius; // bone thickness int m_nNumChildren; int* m_pChildren; // children stored by index into SSteGeometry::m_pBones }; The structure **SSteGeometry** contains an array of **SSteBone** objects, called **m_pBones**. Each bone's **m_nID** member corresponds to its position in the array. Each parent and child value is also an index into this same array. #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_Bones bool Example_Bones(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_eResolution = STE_RESOLUTION_HIGH; sGeometryOptions.m_bExport3dGeometry = false; sGeometryOptions.m_bExportBones = true; // pull over the geometry SSteGeometry* pGeometry = SteGetGeometry(pEngine, &sGeometryOptions); if (pGeometry) { // bones are always given in a single array for (int i = 0; i < pGeometry->m_nNumBones; ++i) { const SSteBone* pBone = pGeometry->m_pBones + i; printf(" bone id: %d\n", pBone->m_nID); printf(" parent id: %d\n", pBone->m_nParentID); printf(" start: (%g, %g, %g)\n", pBone->m_vStart.x, pBone->m_vStart.y, pBone->m_vStart.z); printf(" end: (%g, %g, %g)\n", pBone->m_vEnd.x, pBone->m_vEnd.y, pBone->m_vEnd.z); printf(" radius: %g\n", pBone->m_fRadius); if (pBone->m_nNumChildren > 0) { printf(" children: "); for (int j = 0; j < pBone->m_nNumChildren; ++j) printf("%d ", pBone->m_pChildren[j]); printf("\n"); } printf("\n"); } // using C, so no destructors SteDeleteGeometry(pGeometry); bSuccess = true; } } // using C, so no destructors SteDelete(pEngine); } return bSuccess; }