User Tools

Site Tools


Geometry Structures

While the vertex declarations of SpeedTree geometry may vary from model to model and even within a single SpeedTree model or a single LOD, the hierarchical organization of the geometry structures remain otherwise rigid.


SGeometry Structure

Each tree model contains one SGeometry object that encapsulates all of its 3d, billboard geometry, and render states. Render state objects contain material colors, lighting model data, shader names, and many other states. SGeometry also contains data for vertical and horizontal billboards, with details here.

struct SGeometry
{
        // render states
        st_int32                    m_nNum3dRenderStates;
        st_bool                     m_bDepthOnlyIncluded;
        st_bool                     m_bShadowCastIncluded;
        SRenderState*               m_p3dRenderStates[SHADER_PASS_COUNT];
        SRenderState                m_aBillboardRenderStates[SHADER_PASS_COUNT];
 
        // LODs
        st_int32                    m_nNumLods;
        CLodPointer                 m_pLods;        // typecast to SLod
 
        // billboards
        SVerticalBillboards         m_sVertBBs;
        SHorizontalBillboard        m_sHorzBB;
};

SLod Structure

Each tree model consists of one or more LOD levels, as defined by the SLod structure below. It contains all of the geometries associated with its LOD level, and may optionally have bone data (an option on the Compiler's SRT exporter). If no bones are present, m_pBones is NULL and m_nNumBones is zero.

struct SLod
{
        st_int32            m_nNumDrawCalls;
        CDrawCallPointer    m_pDrawCalls;   // typecast to SDrawCall*
 
        st_int32            m_nNumBones;
        CBonePointer        m_pBones;       // typecast to SBone*
};

SDrawCall Structure

While dubbed SDrawCall, this structure holds a group of geometries that can be rendered in a single draw under a shared render state (e.g. all have backfacing culling active, the same diffuse lighting model, etc). Note the vertex data-accessing functions named GetProperty(). Index data is also available in this structure. Think of m_pIndexData as an st_byte pointer that can be typecast into either an st_uint32* or st_uint16*, depending on the value of m_b32BitIndices.

///////////////////////////////////////////////////////////////////////  
//  Structure SDrawCall
 
// structure is serialized in Parser.cpp
struct SDrawCall
{
    // render state
    CRenderStatePointer         m_pRenderState;      // typecast to SRenderState*
    st_int32                    m_nRenderStateIndex;
 
    // vertices
    st_int32                    m_nNumVertices;
    CBytePointer                m_pVertexData;      // mixed types, but can typecast to st_byte*
 
    // vertex data access helper functions; if you know exacly how the vertex attributes are
    // packed in m_pVertexData, you can skip using these functions and access m_pVertexData directly.
    st_bool                     GetProperty(EVertexProperty eProperty, st_int32 nVertex, st_float32 afValues[4]) const;
    st_bool                     GetProperty(EVertexProperty eProperty, st_int32 nVertex, st_float16 ahfValues[4]) const;
    st_bool                     GetProperty(EVertexProperty eProperty, st_int32 nVertex, st_byte abValues[4]) const;
 
    // indices
    st_int32                    m_nNumIndices;
    st_bool                     m_b32BitIndices;
    CBytePointer                m_pIndexData; // can typecast to st_byte*, then to st_uint32* or st_uint16*,
                                              // depending on m_b32BitIndices
};

Bringing It All Together

The following code example shows how to load an SRT file, access the SGeometry pointer and run through its LODs, draw calls, and access the raw vertex and index data.

using namespace SpeedTree;
 
///////////////////////////////////////////////////////////////////////  
//  Geometry_Structures
 
void Geometry_Structures(void)
{
    const char* pFilename = "example.srt";
 
    // load SRT file
    CCore* pTree = Internal_LoadSrtFile(pFilename);
    if (pTree)
    {
        // access tree's geometry
        const SGeometry* pGeometry = pTree->GetGeometry( );
 
        // each tree may have multiple LOD levels
        for (int i = 0; i < pGeometry->m_nNumLods; ++i)
        {
            const SLod& sLod = pGeometry->m_pLods[i];
 
            // each LOD has a number of "draw calls" which is simply a set
            // of geometries that share the same material/render state
            for (int j = 0; j < sLod.m_nNumDrawCalls; ++j)
            {
                const SDrawCall& sDrawCall = sLod.m_pDrawCalls[j];
 
                // each "draw call" has a vertex declaration
                const SVertexDecl& sVertexDecl = sDrawCall.m_pRenderState->m_sVertexDecl;
 
                // each draw call also contains a vertex buffer block, accessible
                // with the SDrawCall::GetProperty() functions, or raw access as:
                const st_byte* pRawVertexBuffer = sDrawCall.m_pVertexData;
 
                // each draw call is organized as a indexed triangle list, where indices
                // may be 16- or 32-bit; access as follows:
                const st_byte* pRawIndexBuffer = sDrawCall.m_pIndexData;
                if (sDrawCall.m_b32BitIndices)
                {
                    // 32-bit indices
                    const st_uint32* pIndices32 = (const st_uint32*) pRawIndexBuffer;
 
                    // access with 32-bit indices...
                }
                else
                {
                    // 16-bit indices
                    const st_uint16* pIndices16 = (const st_uint16*) pRawIndexBuffer;
 
                    // access with 16-bit indices...
                }
            }
        }
 
        st_delete(pTree);
    }
}