#include "dynos.cpp.h" // Free data pointers, but keep nodes and tokens intact // Delete nodes generated from GfxDynCmds template void ClearGfxDataNodes(DataNodes &aDataNodes) { for (s32 i = aDataNodes.Count(); i != 0; --i) { Delete(aDataNodes[i - 1]->mData); } } ///////////// // Writing // ///////////// static bool DynOS_Actor_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData) { FILE *_File = fopen(aOutputFilename.c_str(), "wb"); if (!_File) { PrintError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str()); return false; } for (u64 i = 0; i != aGfxData->mLoadIndex; ++i) { for (auto &_Node : aGfxData->mLights) { if (_Node->mLoadIndex == i) { DynOS_Lights_Write(_File, aGfxData, _Node); } } for (auto &_Node : aGfxData->mLightTs) { if (_Node->mLoadIndex == i) { DynOS_LightT_Write(_File, aGfxData, _Node); } } for (auto &_Node : aGfxData->mAmbientTs) { if (_Node->mLoadIndex == i) { DynOS_AmbientT_Write(_File, aGfxData, _Node); } } for (auto &_Node : aGfxData->mTextures) { if (_Node->mLoadIndex == i) { DynOS_Tex_Write(_File, aGfxData, _Node); } } for (auto &_Node : aGfxData->mTextureLists) { if (_Node->mLoadIndex == i) { DynOS_TexList_Write(_File, aGfxData, _Node); } } for (auto &_Node : aGfxData->mVertices) { if (_Node->mLoadIndex == i) { DynOS_Vtx_Write(_File, aGfxData, _Node); } } for (auto &_Node : aGfxData->mDisplayLists) { if (_Node->mLoadIndex == i) { DynOS_Gfx_Write(_File, aGfxData, _Node); } } for (auto &_Node : aGfxData->mGeoLayouts) { if (_Node->mLoadIndex == i) { DynOS_Geo_Write(_File, aGfxData, _Node); } } } DynOS_Anim_Write(_File, aGfxData); DynOS_Anim_Table_Write(_File, aGfxData); fclose(_File); return true; } ///////////// // Reading // ///////////// GfxData *DynOS_Actor_LoadFromBinary(const SysPath &aPackFolder, const char *aActorName, const SysPath &aFilename) { struct DynosGfxDataCache { SysPath mPackFolder; Array> mGfxData; }; static Array sDynosGfxDataCache = {}; // Look for pack in cache DynosGfxDataCache *_Pack = NULL; for (s32 i = 0; i != sDynosGfxDataCache.Count(); ++i) { if (sDynosGfxDataCache[i]->mPackFolder == aPackFolder) { _Pack = sDynosGfxDataCache[i]; break; } } // Look for actor in pack if (_Pack) { for (s32 i = 0; i != _Pack->mGfxData.Count(); ++i) { if (!strcmp(_Pack->mGfxData[i].first, aActorName)) { return _Pack->mGfxData[i].second; } } } // Load data from binary file GfxData *_GfxData = NULL; FILE *_File = fopen(aFilename.c_str(), "rb"); if (_File) { _GfxData = New(); for (bool _Done = false; !_Done;) { switch (ReadBytes(_File)) { case DATA_TYPE_LIGHT: DynOS_Lights_Load (_File, _GfxData); break; case DATA_TYPE_LIGHT_T: DynOS_LightT_Load (_File, _GfxData); break; case DATA_TYPE_AMBIENT_T: DynOS_AmbientT_Load (_File, _GfxData); break; case DATA_TYPE_TEXTURE: DynOS_Tex_Load (_File, _GfxData); break; case DATA_TYPE_TEXTURE_LIST: DynOS_TexList_Load (_File, _GfxData); break; case DATA_TYPE_VERTEX: DynOS_Vtx_Load (_File, _GfxData); break; case DATA_TYPE_DISPLAY_LIST: DynOS_Gfx_Load (_File, _GfxData); break; case DATA_TYPE_GEO_LAYOUT: DynOS_Geo_Load (_File, _GfxData); break; case DATA_TYPE_ANIMATION: DynOS_Anim_Load (_File, _GfxData); break; case DATA_TYPE_ANIMATION_TABLE: DynOS_Anim_Table_Load(_File, _GfxData); break; case DATA_TYPE_GFXDYNCMD: DynOS_GfxDynCmd_Load (_File, _GfxData); break; default: _Done = true; break; } } fclose(_File); } // Add data to cache, even if not loaded if (_Pack) { _Pack->mGfxData.Add({ aActorName, _GfxData }); } else { _Pack = New(); _Pack->mPackFolder = aPackFolder; _Pack->mGfxData.Add({ aActorName, _GfxData }); sDynosGfxDataCache.Add(_Pack); } return _GfxData; } ////////////// // Generate // ////////////// static String GetActorFolder(const Array> &aActorsFolders, u64 aModelIdentifier) { for (const auto &_Pair : aActorsFolders) { if (_Pair.first == aModelIdentifier) { return _Pair.second; } } return String(); } static void DynOS_Actor_Generate(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData) { // do not regen this folder if we find any existing bins for (s32 geoIndex = _GfxData->mGeoLayouts.Count() - 1; geoIndex >= 0; geoIndex--) { auto &_GeoNode = _GfxData->mGeoLayouts[geoIndex]; String _GeoRootName = _GeoNode->mName; // If there is an existing binary file for this layout, skip and go to the next actor SysPath _BinFilename = fstring("%s/%s.bin", aPackFolder.c_str(), _GeoRootName.begin()); if (fs_sys_file_exists(_BinFilename.c_str())) { return; } } // generate in reverse order to detect children for (s32 geoIndex = _GfxData->mGeoLayouts.Count() - 1; geoIndex >= 0; geoIndex--) { auto &_GeoNode = _GfxData->mGeoLayouts[geoIndex]; // if this is a child geo layout, don't save it as a bin if (_GfxData->mChildGeoLayouts.Find(_GeoNode) != -1) { continue; } String _GeoRootName = _GeoNode->mName; // If there is an existing binary file for this layout, skip and go to the next actor SysPath _BinFilename = fstring("%s/%s.bin", aPackFolder.c_str(), _GeoRootName.begin()); // Init _GfxData->mLoadIndex = 0; _GfxData->mErrorCount = 0; _GfxData->mModelIdentifier = _GeoNode->mModelIdentifier; _GfxData->mPackFolder = aPackFolder; _GfxData->mPointerList = { NULL }; // The NULL pointer is needed, so we add it here _GfxData->mPointerOffsetList = { }; _GfxData->mLuaPointerList = { }; _GfxData->mLuaTokenList = { }; _GfxData->mGfxContext.mCurrentTexture = NULL; _GfxData->mGfxContext.mCurrentPalette = NULL; _GfxData->mGeoNodeStack.Clear(); // Parse data PrintNoNewLine("%s.bin: Model identifier: %X - Processing... ", _GeoRootName.begin(), _GfxData->mModelIdentifier); DynOS_Geo_Parse(_GfxData, _GeoNode, true); // Init animation data for (auto &_AnimBuffer : _GfxData->mAnimValues) Delete(_AnimBuffer); for (auto &_AnimBuffer : _GfxData->mAnimIndices) Delete(_AnimBuffer); for (auto &_AnimNode : _GfxData->mAnimations) Delete(_AnimNode); _GfxData->mAnimValues.Clear(); _GfxData->mAnimIndices.Clear(); _GfxData->mAnimations.Clear(); _GfxData->mAnimationTable.Clear(); // Scan anims folder for animation data String _ActorFolder = GetActorFolder(_ActorsFolders, _GfxData->mModelIdentifier); SysPath _AnimsFolder = fstring("%s/%s/anims", aPackFolder.c_str(), _ActorFolder.begin()); DynOS_Anim_ScanFolder(_GfxData, _AnimsFolder); // Create table for player model animations if ((_GeoRootName == "mario_geo" || _GeoRootName == "luigi_geo" || _GeoRootName == "toad_player_geo" || _GeoRootName == "wario_geo" || _GeoRootName == "waluigi_geo") && !_GfxData->mAnimations.Empty()) { _GfxData->mAnimationTable.Resize(256); for (s32 i = 0; i != 256; ++i) { String _AnimName("anim_%02X", i); if (_GfxData->mAnimations.FindIf([&_AnimName](const DataNode *aNode) { return aNode->mName == _AnimName; }) != -1) { _GfxData->mAnimationTable[i] = { _AnimName, NULL }; } else { _GfxData->mAnimationTable[i] = { "NULL", NULL }; } } } // Write if no error if (_GfxData->mErrorCount == 0) { DynOS_Actor_WriteBinary(_BinFilename, _GfxData); } else { Print(" %u error(s): Unable to parse data", _GfxData->mErrorCount); } // Clear data pointers ClearGfxDataNodes(_GfxData->mLights); ClearGfxDataNodes(_GfxData->mLightTs); ClearGfxDataNodes(_GfxData->mAmbientTs); ClearGfxDataNodes(_GfxData->mTextures); ClearGfxDataNodes(_GfxData->mTextureLists); ClearGfxDataNodes(_GfxData->mVertices); ClearGfxDataNodes(_GfxData->mDisplayLists); ClearGfxDataNodes(_GfxData->mGeoLayouts); ClearGfxDataNodes(_GfxData->mCollisions); _GfxData->mPointerList.Clear(); _GfxData->mPointerOffsetList.Clear(); _GfxData->mLuaPointerList.Clear(); _GfxData->mLuaTokenList.Clear(); } _GfxData->mChildGeoLayouts.Clear(); } void DynOS_Actor_GeneratePack(const SysPath &aPackFolder) { Print("---------- Pack folder: \"%s\" ----------", aPackFolder.c_str()); Array> _ActorsFolders; GfxData *_GfxData = New(); // Read all the model.inc.c files and geo.inc.c files from the subfolders of the pack folder // Animations are processed separately DIR *aPackDir = opendir(aPackFolder.c_str()); if (aPackDir) { struct dirent *_PackEnt = NULL; while ((_PackEnt = readdir(aPackDir)) != NULL) { // Skip . and .. if (SysPath(_PackEnt->d_name) == ".") continue; if (SysPath(_PackEnt->d_name) == "..") continue; // For each subfolder, read tokens from model.inc.c and geo.inc.c SysPath _Folder = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); if (fs_sys_dir_exists(_Folder.c_str())) { _GfxData->mModelIdentifier = 0; // Remember the geo layout count s32 prevGeoLayoutCount = _GfxData->mGeoLayouts.Count(); DynOS_Read_Source(_GfxData, fstring("%s/model.inc.c", _Folder.c_str())); DynOS_Read_Source(_GfxData, fstring("%s/geo.inc.c", _Folder.c_str())); DynOS_Read_Source(_GfxData, fstring("%s/collision.inc.c", _Folder.c_str())); if (_GfxData->mModelIdentifier != 0) { _ActorsFolders.Add({ _GfxData->mModelIdentifier, String(_PackEnt->d_name) }); } } } closedir(aPackDir); } // Generate a binary file for each actor found in the GfxData DynOS_Col_Generate(aPackFolder, _ActorsFolders, _GfxData); DynOS_Actor_Generate(aPackFolder, _ActorsFolders, _GfxData); DynOS_Gfx_Free(_GfxData); }