User Tools

Site Tools


Example: Bones

Querying a model's bone data is straightforward. It is not organized in a hierarchical tree as the 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 <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);
}
 
 
///////////////////////////////////////////////////////////////////////
//  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;
}