====== 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 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 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 SDK in addition to how to load an .stsdk file via a memory block instead of passing a filename to the SDK. See more on the SDK's [[callback-system|callback system]]. #include #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 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(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 SDK has ownership of the .stsdk memory block (when a filename is passed to ''CCore::LoadTree()'' instead of a memory block).