SpeedTree
    Show / Hide Table of Contents

    Loading .stsdk files

    .stsdk files are binary files that store a single model as defined in and exported from the SpeedTree Modeler. They are designed as a game resource and can be loaded as individual files by the Runtime SDK or stored as part of larger memory blocks and loaded from there. These files are exported from the SpeedTree Modeler via File > Export to Game. They contain geometry, materials, extents, collision objects, and billboard data but they do not contain embedded texture data, only texture references.

    .stsdk files can be loaded by the CCore class function CCore::LoadTree() in the Runtime SDK either by providing a filename or a pointer to an already memory-resident copy of the file. This structure, passed to CCore::LoadTree(), determines how it's loaded:

    struct SLoadConfig
    {
        // load either from a filename or an already-loaded buffer;
        // if filename is empty, the sdk will use m_pFileBlock
        CFixedString    m_strFilename;
    
        const st_byte*  m_pFileBlock;
        size_t          m_siFileBlockSize;
        CFixedString    m_strAssetSearchPath; // if m_strFilename is not used, put search path here
    
        // parameters
        st_bool         m_bGrassModel;
    };
    

    The code below is a simple example of loading a tree model exported as an .stsdk file. Once the file is loaded, all of its data, available from the CCore accessor functions, is immediately available.

    #include "Core/Core.h"
    
    // simple loading of a binary SpeedTree .stsdk file
    
    void SimpleStsdkLoad(const char* pFilename)
    {
        // populate loading config struct so that the sdk
        // handles the file and memory operations automatically
        SpeedTree::CCore::SLoadConfig sLoadConfig;
        sLoadConfig.m_strFilename = pFilename;
        sLoadConfig.m_bGrassModel = false;
    
        // create a core/tree object to read stsdk into
        SpeedTree::CCore cModel;
    
        // call .stsdk-loading function: returns true on success
        //
        // the sdk will use its default file/memory callback definitions
        // to access the file and create a buffer to store its contents
        if (cModel.LoadTree(sLoadConfig))
            printf(".stsdk load was successful\n");
        else
            fprintf(stderr, ".stsdk load was unsuccessful\n");
    }
    

    The next example is more complex, showing how to set a number of key callbacks for the Runtime SDK in addition to how to load an .stsdk file via a memory block instead of passing a filename to the Runtime SDK. See more on the Runtime SDK's callback system.

    #include <cstdio>
    #include "Core/Core.h"
    #include "Core/Callbacks.h"
    using SpeedTree::st_bool;
    using SpeedTree::st_byte;
    
    // simple error callback example
    static void MyErrorCallback(const char* pMsg) { fprintf(stderr, "SpeedTree Runtime SDK Error: [%s]\n", pMsg); }
    
    // simple heap allocation callback example
    static void* MyHeapAllocCallback(size_t siSizeInBytes, size_t siAlignment) { return malloc(siSizeInBytes); }
    
    // simple heap free callback example
    static void MyHeapFreeCallback(void* pBlock) { if (pBlock) free(pBlock); }
    
    // simple file size callback example
    static size_t MyFileSizeCallback(const char* pFilename)
    {
        size_t siSize = 0;
    
        FILE* pFile = NULL;
        if (fopen_s(&pFile, pFilename, "rb") == 0)
        {
            // go to the end of the file
            fseek(pFile, 0L, SEEK_END);
    
            // determine how large the file is
            siSize = static_cast<size_t>(ftell(pFile));
    
            fclose(pFile);
        }
    
        return siSize;
    }
    
    // simple load binary file callback example (returns true on success)
    static bool MyLoadFileCallback(const char* pFilename, void* pBuffer)
    {
        st_bool bSuccess = false;
    
        if (pFilename && pBuffer)
        {
            size_t siFileSize = MyFileSizeCallback(pFilename);
            if (siFileSize > 0)
            {
                FILE* pFile = NULL;
                if (fopen_s(&pFile, pFilename, "rb") == 0)
                {
                    size_t siBytesRead = fread(pBuffer, 1, siFileSize, pFile);
                    bSuccess = (siBytesRead == siFileSize);
    
                    (void) fclose(pFile);
                }
            }
        }
    
        return bSuccess;
    }
    
    // more complex example of loading a SpeedTree STSDK file with 
    // callback overrides
    
    void MoreComplexStsdkLoad(const char* pFilename)
    {
        // assign example callbacks
        SpeedTree::Callbacks::Error( ) = MyErrorCallback;
        SpeedTree::Callbacks::HeapAlloc( ) = MyHeapAllocCallback;
        SpeedTree::Callbacks::HeapFree( ) = MyHeapFreeCallback;
        SpeedTree::Callbacks::GetFileSize( ) = MyFileSizeCallback;
        SpeedTree::Callbacks::LoadBinaryFile( ) = MyLoadFileCallback;
    
        // populate loading config struct so that the loading function will use 
        // a client-side memory block instead of reading the file in the sdk
        SpeedTree::CCore::SLoadConfig sLoadConfig;
        sLoadConfig.m_strFilename = "";
        sLoadConfig.m_bGrassModel = false;
    
        // example of loading the stsdk file into memory on the client side then
        // passing to the sdk (minimal error handling for sake of brevity)
        sLoadConfig.m_siFileBlockSize = MyFileSizeCallback(pFilename);
        sLoadConfig.m_pFileBlock = MyHeapAllocCallback(sLoadConfig.m_siFileBlockSize, 16);
        MyLoadFileCallback(pFilename, sLoadConfig.m_pFileBlock);
    
        // create a model to hold and read the stsdk file
        SpeedTree::CCore cModel;
        if (cModel.LoadTree(sLoadConfig))
        {
            printf(".stsdk load was successful\n");
    
            // do something with the model
            // ...
    
            // delete buffer
            MyHeapFreeCallback(sLoadConfig.m_pFileBlock);
            sLoadConfig.m_pFileBlock = NULL;
        }
        else
            fprintf(stderr, ".stsdk load was unsuccessful\n");
    }
    
    Note

    The bulk of an .stsdk file size is geometry (vertices and indices). Once the geometry has been uploaded to the GPU, that data can be deleted using CCore::DeleteGeometry(), leaving the rest of the CCore/STSDK object intact. This works only when the Runtime SDK has ownership of the .stsdk memory block (when a filename is passed to CCore::LoadTree() instead of a memory block).

    Copyright © 2023 Unity Technologies
    • Legal
    • Privacy Policy
    • Cookies
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)
    "Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
    Generated by DocFX.