====== 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;
}