diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index 5dd95d61..4d465670 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -647,15 +647,10 @@ bool DynOS_Gfx_ImportTexture(void **aOutput, void *aPtr, s32 aTile, void *aGfxRA Array &DynOS_Gfx_GetActorList(); Array &DynOS_Gfx_GetPacks(); Array &DynOS_Gfx_GetPacksEnabled(); -void DynOS_Gfx_GeneratePacks(const char* directory); Array DynOS_Gfx_Init(); void DynOS_Gfx_Update(); void DynOS_Gfx_SwapAnimations(void *aPtr); -bool DynOS_Gfx_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData); -GfxData *DynOS_Gfx_LoadFromBinary(const SysPath &aPackFolder, const char *aActorName); void DynOS_Gfx_Free(GfxData *aGfxData); -void DynOS_Gfx_GeneratePack(const SysPath &aPackFolder); -void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder); // // String @@ -714,34 +709,66 @@ const char *DynOS_Warp_GetParamName(s32 aLevel, s32 aIndex); // Collisions // -bool DynOS_Col_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData, DataNode* _Node); -DataNode* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const char *aCollisionName); - -// -// Levels -// - -bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData); - -// -// Coop Misc -// - void DynOS_Col_AddCollisionCustom(const SysPath &aPackFolder, const char *aCollisionName); Collision* DynOS_Col_GetCollision(const char* collisionName); +// +// Bin +// + +void DynOS_Gfx_GeneratePacks(const char* directory); +s64 DynOS_RecursiveDescent_Parse(const char* expr, bool* success); +void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename); +char *DynOS_Read_Buffer(FILE* aFile, GfxData* aGfxData); + +void DynOS_Anim_ScanFolder(GfxData *aGfxData, const SysPath &aAnimsFolder); +void DynOS_Anim_Table_Write(FILE* aFile, GfxData* aGfxData); +void DynOS_Anim_Write(FILE* aFile, GfxData* aGfxData); +void DynOS_Anim_Load(FILE *aFile, GfxData *aGfxData); +void DynOS_Anim_Table_Load(FILE *aFile, GfxData *aGfxData); + +DataNode* DynOS_Col_Parse(GfxData* aGfxData, DataNode* aNode, bool aDisplayPercent); +void DynOS_Col_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode); +DataNode* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const char *aCollisionName); +void DynOS_Col_Generate(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData); DataNode* DynOS_Geo_Parse(GfxData* aGfxData, DataNode* aNode, bool aDisplayPercent); +void DynOS_Geo_Write(FILE *aFile, GfxData *aGfxData, DataNode *aNode); +void DynOS_Geo_Load(FILE *aFile, GfxData *aGfxData); + DataNode* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode* aNode); -DataNode* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode* aNode); -DataNode* DynOS_Tex_Parse(GfxData* aGfxData, DataNode* aNode); +void DynOS_Gfx_Write(FILE *aFile, GfxData *aGfxData, DataNode *aNode); +void DynOS_Gfx_Load(FILE *aFile, GfxData *aGfxData); + DataNode* DynOS_Lights_Parse(GfxData* aGfxData, DataNode* aNode); -DataNode* DynOS_Col_Parse(GfxData* aGfxData, DataNode* aNode, bool aDisplayPercent); -DataNode* DynOS_Lvl_Parse(GfxData* aGfxData, DataNode* aNode, bool aDisplayPercent); +void DynOS_Lights_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode); +void DynOS_Lights_Load(FILE *aFile, GfxData *aGfxData); + DataNode* DynOS_MacroObject_Parse(GfxData* aGfxData, DataNode* aNode, bool aDisplayPercent); +// TODO: DynOS_MacroObject_Write +// TODO: DynOS_MacroObject_Load +DataNode* DynOS_Tex_Parse(GfxData* aGfxData, DataNode* aNode); +void DynOS_Tex_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode); +void DynOS_Tex_Load(FILE *aFile, GfxData *aGfxData); void DynOS_Tex_ConvertTextureDataToPng(GfxData *aGfxData, TexData* aTexture); -s64 DynOS_RecursiveDescent_Parse(const char* expr, bool* success); + +DataNode* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode* aNode); +void DynOS_Vtx_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode); +void DynOS_Vtx_Load(FILE *aFile, GfxData *aGfxData); + +void DynOS_Pointer_Write(FILE* aFile, const void* aPtr, GfxData* aGfxData); +void *DynOS_Pointer_Load(FILE *aFile, GfxData *aGfxData, u32 aValue); + +void DynOS_GfxDynCmd_Load(FILE *aFile, GfxData *aGfxData); + +GfxData *DynOS_Actor_LoadFromBinary(const SysPath &aPackFolder, const char *aActorName); +void DynOS_Actor_GeneratePack(const SysPath &aPackFolder); + +DataNode* DynOS_Lvl_Parse(GfxData* aGfxData, DataNode* aNode, bool aDisplayPercent); +// TODO: DynOS_Lvl_Write +// TODO: DynOS_Lvl_Load +void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder); #endif #endif diff --git a/data/dynos_bin_actor.cpp b/data/dynos_bin_actor.cpp new file mode 100644 index 00000000..046f5846 --- /dev/null +++ b/data/dynos_bin_actor.cpp @@ -0,0 +1,232 @@ +#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->mTextures) { + if (_Node->mLoadIndex == i) { + DynOS_Tex_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) { + 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; + SysPath _Filename = fstring("%s/%s.bin", aPackFolder.begin(), aActorName); + FILE *_File = fopen(_Filename.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_TEXTURE: DynOS_Tex_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) { + for (auto &_GeoNode : _GfxData->mGenerateGeoLayouts) { + 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())) { + continue; + } + + // 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->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->mTextures); + ClearGfxDataNodes(_GfxData->mVertices); + ClearGfxDataNodes(_GfxData->mDisplayLists); + ClearGfxDataNodes(_GfxData->mGeoLayouts); + ClearGfxDataNodes(_GfxData->mCollisions); + } +} + +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; + 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); +} diff --git a/data/dynos_bin_animation.cpp b/data/dynos_bin_animation.cpp new file mode 100644 index 00000000..1efe30b3 --- /dev/null +++ b/data/dynos_bin_animation.cpp @@ -0,0 +1,257 @@ +#include "dynos.cpp.h" + + ///////////// + // Parsing // +///////////// + +static void ScanAnimationDataFile(GfxData *aGfxData, const SysPath &aFilename) { + FILE *_File = fopen(aFilename.c_str(), "rb"); + if (!_File) { + PrintError(" ERROR: Unable to open file \"%s\"", aFilename.c_str()); + } + + // Load file into a buffer while removing all comments + char *_FileBuffer = DynOS_Read_Buffer(_File, NULL); + fclose(_File); + + // Parse animation data + u8 _DataType = DATA_TYPE_NONE; + String _DataName; + bool _IsData = false; + Array _Data; + Array _Tokens = Split(_FileBuffer, " []()=&,;\t\r\n\b"); + for (const auto &_Token : _Tokens) { + + // Data type + if (_DataType == DATA_TYPE_NONE) { + if (_Token == "s16" || _Token == "u16" || _Token == "s16") { + _DataType = DATA_TYPE_ANIMATION_VALUE; + } else if (_Token == "Animation") { + _DataType = DATA_TYPE_ANIMATION; + } + } + + // Data name + else if (_DataName.Empty()) { + _DataName = _Token; + if (_DataType == DATA_TYPE_ANIMATION_VALUE && (_DataName.Find("index") != -1 || _DataName.Find("indices") != -1)) { + _DataType = DATA_TYPE_ANIMATION_INDEX; + } + } + + // Is data? + else if (!_IsData) { + if (_Token == "{") { + _IsData = true; + } + } + + // Data + else { + if (_Token == "}") { + switch (_DataType) { + case DATA_TYPE_ANIMATION_VALUE: { + AnimBuffer *_AnimValues = New>(); + _AnimValues->first = _DataName; + for (const auto &_Value : _Data) { + _AnimValues->second.Add(_Value.ParseInt()); + } + aGfxData->mAnimValues.Add(_AnimValues); + } break; + + case DATA_TYPE_ANIMATION_INDEX: { + AnimBuffer *_AnimIndices = New>(); + _AnimIndices->first = _DataName; + for (const auto &_Index : _Data) { + _AnimIndices->second.Add(_Index.ParseInt()); + } + aGfxData->mAnimIndices.Add(_AnimIndices); + } break; + + case DATA_TYPE_ANIMATION: { + if (_Data.Count() < 10) { + PrintError(" ERROR: %s: Not enough data", _DataName.begin()); + break; + } + + DataNode *_Node = New>(); + _Node->mName = _DataName; + _Node->mData = New(); + _Node->mData->mFlags = (s16) _Data[0].ParseInt(); + _Node->mData->mUnk02 = (s16) _Data[1].ParseInt(); + _Node->mData->mUnk04 = (s16) _Data[2].ParseInt(); + _Node->mData->mUnk06 = (s16) _Data[3].ParseInt(); + _Node->mData->mUnk08 = (s16) _Data[4].ParseInt(); + _Node->mData->mUnk0A.first = _Data[6]; // 5 is "ANIMINDEX_NUMPARTS" + _Node->mData->mValues.first = _Data[7]; + _Node->mData->mIndex.first = _Data[8]; + _Node->mData->mLength = (u32) _Data[9].ParseInt(); + aGfxData->mAnimations.Add(_Node); + } break; + } + _DataType = DATA_TYPE_NONE; + _DataName.Clear(); + _IsData = false; + _Data.Clear(); + } else { + _Data.Add(_Token); + } + } + } + Delete(_FileBuffer); +} + +static void ScanAnimationTableFile(GfxData *aGfxData, const SysPath &aFilename) { + FILE *_File = fopen(aFilename.c_str(), "rb"); + if (!_File) { + PrintError(" ERROR: Unable to open file \"%s\"", aFilename.c_str()); + } + + // Load file into a buffer while removing all comments + char *_FileBuffer = DynOS_Read_Buffer(_File, NULL); + fclose(_File); + + // Retrieve animation names + bool _IsAnimName = false; + Array _Tokens = Split(_FileBuffer, " =&,;\t\r\n\b"); + for (const auto &_Token : _Tokens) { + if (_Token == "{") { + _IsAnimName = true; + } else if (_Token == "}") { + _IsAnimName = false; + } else if (_IsAnimName) { + aGfxData->mAnimationTable.Add({ _Token, NULL }); + } + } + Delete(_FileBuffer); +} + +void DynOS_Anim_ScanFolder(GfxData *aGfxData, const SysPath &aAnimsFolder) { + DIR *_AnimsDir = opendir(aAnimsFolder.c_str()); + if (!_AnimsDir) return; + + struct dirent *_AnimsEnt = NULL; + while ((_AnimsEnt = readdir(_AnimsDir)) != NULL) { + + // Skip + if (SysPath(_AnimsEnt->d_name) == ".") continue; + if (SysPath(_AnimsEnt->d_name) == "..") continue; + if (SysPath(_AnimsEnt->d_name) == "data.inc.c") continue; + + // Animation file + SysPath _AnimsFilename = fstring("%s/%s", aAnimsFolder.c_str(), _AnimsEnt->d_name); + if (fs_sys_file_exists(_AnimsFilename.c_str())) { + + // Table file + if (SysPath(_AnimsEnt->d_name) == "table.inc.c") { + ScanAnimationTableFile(aGfxData, _AnimsFilename); + } + + // Data file + else { + ScanAnimationDataFile(aGfxData, _AnimsFilename); + } + } + } + closedir(_AnimsDir); +} + + ///////////// + // Writing // +///////////// + +void DynOS_Anim_Write(FILE* aFile, GfxData* aGfxData) { + for (auto& _Node : aGfxData->mAnimations) { + + // Value buffer + s32 _ValueBufferIdx = aGfxData->mAnimValues.FindIf([&_Node](const AnimBuffer *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mValues.first; }); + if (_ValueBufferIdx == -1) { + continue; + } + + // Index buffer + s32 _IndexBufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mIndex.first; }); + if (_IndexBufferIdx == -1) { + continue; + } + + // Unk0A buffer + s32 _Unk0ABufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mUnk0A.first; }); + if (_Unk0ABufferIdx == -1) { + continue; + } + + // Header + WriteBytes(aFile, DATA_TYPE_ANIMATION); + _Node->mName.Write(aFile); + + // Data + WriteBytes(aFile, _Node->mData->mFlags); + WriteBytes(aFile, _Node->mData->mUnk02); + WriteBytes(aFile, _Node->mData->mUnk04); + WriteBytes(aFile, _Node->mData->mUnk06); + WriteBytes(aFile, _Node->mData->mUnk08); + WriteBytes(aFile, (aGfxData->mAnimIndices[_Unk0ABufferIdx]->second.Count() / 6) - 1); + WriteBytes(aFile, _Node->mData->mLength); + aGfxData->mAnimValues[_ValueBufferIdx]->second.Write(aFile); + aGfxData->mAnimIndices[_IndexBufferIdx]->second.Write(aFile); + } +} + +void DynOS_Anim_Table_Write(FILE* aFile, GfxData* aGfxData) { + for (auto& _AnimName : aGfxData->mAnimationTable) { + + // Header + WriteBytes(aFile, DATA_TYPE_ANIMATION_TABLE); + + // Data + _AnimName.first.Write(aFile); + } +} + + ///////////// + // Reading // +///////////// + +void DynOS_Anim_Load(FILE *aFile, GfxData *aGfxData) { + DataNode *_Node = New>(); + + // Name + _Node->mName.Read(aFile); + + // Data + _Node->mData = New(); + _Node->mData->mFlags = ReadBytes(aFile); + _Node->mData->mUnk02 = ReadBytes(aFile); + _Node->mData->mUnk04 = ReadBytes(aFile); + _Node->mData->mUnk06 = ReadBytes(aFile); + _Node->mData->mUnk08 = ReadBytes(aFile); + _Node->mData->mUnk0A.second = ReadBytes(aFile); + _Node->mData->mLength = ReadBytes(aFile); + _Node->mData->mValues.second.Read(aFile); + _Node->mData->mIndex.second.Read(aFile); + + // Append + aGfxData->mAnimations.Add(_Node); +} + +void DynOS_Anim_Table_Load(FILE *aFile, GfxData *aGfxData) { + void *_AnimationPtr = NULL; + + // Data + String _AnimationName; _AnimationName.Read(aFile); + if (_AnimationName != "NULL") { + for (auto &_AnimData : aGfxData->mAnimations) { + if (_AnimData->mName == _AnimationName) { + _AnimationPtr = (void *) _AnimData->mData; + break; + } + } + if (!_AnimationPtr) { + sys_fatal("Animation not found: %s", _AnimationName.begin()); + } + } + + // Append + aGfxData->mAnimationTable.Add({ "", _AnimationPtr }); +} diff --git a/data/dynos_bin_col.cpp b/data/dynos_bin_col.cpp index e4537694..c0aa1a88 100644 --- a/data/dynos_bin_col.cpp +++ b/data/dynos_bin_col.cpp @@ -9,7 +9,7 @@ extern "C" { // Free data pointers, but keep nodes and tokens intact // Delete nodes generated from GfxDynCmds template -static void ClearColDataNodes(DataNodes &aDataNodes) { +void ClearGfxDataNodes(DataNodes &aDataNodes) { for (s32 i = aDataNodes.Count(); i != 0; --i) { Delete(aDataNodes[i - 1]->mData); } @@ -405,7 +405,7 @@ DataNode* DynOS_Col_Parse(GfxData* aGfxData, DataNode* aNo // Writing // ///////////// -static void WriteCollisionData(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { +void DynOS_Col_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { if (!aNode->mData) return; // Name @@ -419,14 +419,14 @@ static void WriteCollisionData(FILE* aFile, GfxData* aGfxData, DataNode* _Node) { +static bool DynOS_Col_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData, DataNode* _Node) { FILE *_File = fopen(aOutputFilename.c_str(), "wb"); if (!_File) { PrintError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str()); return false; } - WriteCollisionData(_File, aGfxData, _Node); + DynOS_Col_Write(_File, aGfxData, _Node); fclose(_File); return true; @@ -467,3 +467,37 @@ DataNode* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const return collisionNode; } + + ////////////// + // Generate // +////////////// + +void DynOS_Col_Generate(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData) { + for (auto &_ColNode : _GfxData->mCollisions) { + String _ColRootName = _ColNode->mName; + + // If there is an existing binary file for this collision, skip and go to the next actor + SysPath _ColFilename = fstring("%s/%s.col", aPackFolder.c_str(), _ColRootName.begin()); + if (fs_sys_file_exists(_ColFilename.c_str())) { + continue; + } + + // Init + _GfxData->mErrorCount = 0; + _GfxData->mLoadIndex = 0; + + // Parse data + PrintNoNewLine("%s.col: Model identifier: %X - Processing... ", _ColRootName.begin(), _GfxData->mModelIdentifier); + DynOS_Col_Parse(_GfxData, _ColNode, true); + + // Write if no error + if (_GfxData->mErrorCount == 0) { + DynOS_Col_WriteBinary(_ColFilename, _GfxData, _ColNode); + } else { + Print(" %u error(s): Unable to parse data", _GfxData->mErrorCount); + } + + // Clear data pointers + ClearGfxDataNodes(_GfxData->mCollisions); + } +} diff --git a/data/dynos_bin_geo.cpp b/data/dynos_bin_geo.cpp index dbbc12f2..820f38ee 100644 --- a/data/dynos_bin_geo.cpp +++ b/data/dynos_bin_geo.cpp @@ -359,3 +359,53 @@ DataNode* DynOS_Geo_Parse(GfxData* aGfxData, DataNode* aNo } #pragma GCC diagnostic pop + + ///////////// + // Writing // +///////////// + +void DynOS_Geo_Write(FILE *aFile, GfxData *aGfxData, DataNode *aNode) { + if (!aNode->mData) return; + + // Header + WriteBytes(aFile, DATA_TYPE_GEO_LAYOUT); + aNode->mName.Write(aFile); + + // Data + WriteBytes(aFile, aNode->mSize); + for (u32 i = 0; i != aNode->mSize; ++i) { + GeoLayout *_Head = &aNode->mData[i]; + if (aGfxData->mPointerList.Find((void *) _Head) != -1) { + DynOS_Pointer_Write(aFile, (const void *) (*_Head), aGfxData); + } else { + WriteBytes(aFile, *((u32 *) _Head)); + } + } +} + + ///////////// + // Reading // +///////////// + +void DynOS_Geo_Load(FILE *aFile, GfxData *aGfxData) { + DataNode *_Node = New>(); + + // Name + _Node->mName.Read(aFile); + + // Data + _Node->mSize = ReadBytes(aFile); + _Node->mData = New(_Node->mSize); + for (u32 i = 0; i != _Node->mSize; ++i) { + u32 _Value = ReadBytes(aFile); + void *_Ptr = DynOS_Pointer_Load(aFile, aGfxData, _Value); + if (_Ptr) { + _Node->mData[i] = (uintptr_t) _Ptr; + } else { + _Node->mData[i] = (uintptr_t) _Value; + } + } + + // Append + aGfxData->mGeoLayouts.Add(_Node); +} diff --git a/data/dynos_bin_gfx.cpp b/data/dynos_bin_gfx.cpp index c0c84535..e4e10d43 100644 --- a/data/dynos_bin_gfx.cpp +++ b/data/dynos_bin_gfx.cpp @@ -853,3 +853,57 @@ DataNode* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode* aNode) { } #pragma GCC diagnostic pop + + ///////////// + // Writing // +///////////// + +void DynOS_Gfx_Write(FILE *aFile, GfxData *aGfxData, DataNode *aNode) { + if (!aNode->mData) return; + + // Header + WriteBytes(aFile, DATA_TYPE_DISPLAY_LIST); + aNode->mName.Write(aFile); + + // Data + WriteBytes(aFile, aNode->mSize); + for (u32 i = 0; i != aNode->mSize; ++i) { + Gfx *_Head = &aNode->mData[i]; + if (aGfxData->mPointerList.Find((void *) _Head) != -1) { + WriteBytes(aFile, _Head->words.w0); + DynOS_Pointer_Write(aFile, (const void *) _Head->words.w1, aGfxData); + } else { + WriteBytes(aFile, _Head->words.w0); + WriteBytes(aFile, _Head->words.w1); + } + } +} + ///////////// + // Reading // +///////////// + +void DynOS_Gfx_Load(FILE *aFile, GfxData *aGfxData) { + DataNode *_Node = New>(); + + // Name + _Node->mName.Read(aFile); + + // Data + _Node->mSize = ReadBytes(aFile); + _Node->mData = New(_Node->mSize); + for (u32 i = 0; i != _Node->mSize; ++i) { + u32 _WordsW0 = ReadBytes(aFile); + u32 _WordsW1 = ReadBytes(aFile); + void *_Ptr = DynOS_Pointer_Load(aFile, aGfxData, _WordsW1); + if (_Ptr) { + _Node->mData[i].words.w0 = (uintptr_t) _WordsW0; + _Node->mData[i].words.w1 = (uintptr_t) _Ptr; + } else { + _Node->mData[i].words.w0 = (uintptr_t) _WordsW0; + _Node->mData[i].words.w1 = (uintptr_t) _WordsW1; + } + } + + // Append + aGfxData->mDisplayLists.Add(_Node); +} diff --git a/data/dynos_bin_legacy.cpp b/data/dynos_bin_legacy.cpp new file mode 100644 index 00000000..ac8cddf9 --- /dev/null +++ b/data/dynos_bin_legacy.cpp @@ -0,0 +1,30 @@ +#include "dynos.cpp.h" + + ///////////// + // Parsing // +///////////// + + ///////////// + // Writing // +///////////// + + ///////////// + // Reading // +///////////// + +// For retro-compatibility +void DynOS_GfxDynCmd_Load(FILE *aFile, GfxData *aGfxData) { + Gfx *_Data = NULL; + String _DisplayListName; _DisplayListName.Read(aFile); + for (auto& _DisplayList : aGfxData->mDisplayLists) { + if (_DisplayList->mName == _DisplayListName) { + _Data = _DisplayList->mData; + break; + } + } + if (!_Data) { + sys_fatal("Display list not found: %s", _DisplayListName.begin()); + } + ReadBytes(aFile); + ReadBytes(aFile); +} diff --git a/data/dynos_bin_lights.cpp b/data/dynos_bin_lights.cpp index ba3a9bea..ef046a58 100644 --- a/data/dynos_bin_lights.cpp +++ b/data/dynos_bin_lights.cpp @@ -34,3 +34,36 @@ DataNode* DynOS_Lights_Parse(GfxData* aGfxData, DataNode* aNod aNode->mLoadIndex = aGfxData->mLoadIndex++; return aNode; } + + ///////////// + // Writing // +///////////// + +void DynOS_Lights_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { + if (!aNode->mData) return; + + // Header + WriteBytes(aFile, DATA_TYPE_LIGHT); + aNode->mName.Write(aFile); + + // Data + WriteBytes(aFile, *aNode->mData); +} + + ///////////// + // Reading // +///////////// + +void DynOS_Lights_Load(FILE *aFile, GfxData *aGfxData) { + DataNode *_Node = New>(); + + // Name + _Node->mName.Read(aFile); + + // Data + _Node->mData = New(); + *_Node->mData = ReadBytes(aFile); + + // Append + aGfxData->mLights.Add(_Node); +} diff --git a/data/dynos_bin_lvl.cpp b/data/dynos_bin_lvl.cpp index 224c78ec..6d3fd175 100644 --- a/data/dynos_bin_lvl.cpp +++ b/data/dynos_bin_lvl.cpp @@ -1478,7 +1478,7 @@ static DataNode *GetLevelScript(GfxData *aGfxData, const String& aG return NULL; } -bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData) { +static bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData) { bool generated = false; for (auto &_LvlNode : _GfxData->mLevelScripts) { String _LvlRootName = _LvlNode->mName; @@ -1512,3 +1512,41 @@ bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array> _ActorsFolders; + GfxData *_GfxData = New(); + + 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 script.c + SysPath _Folder = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); + if (fs_sys_dir_exists(_Folder.c_str())) { + _GfxData->mModelIdentifier = 0; + DynOS_Read_Source(_GfxData, fstring("%s/model.inc.c", _Folder.c_str())); + DynOS_Read_Source(_GfxData, fstring("%s/area_1/collision.inc.c", _Folder.c_str())); + DynOS_Read_Source(_GfxData, fstring("%s/area_1/geo.inc.c", _Folder.c_str())); + DynOS_Read_Source(_GfxData, fstring("%s/script.c", _Folder.c_str())); + DynOS_Read_Source(_GfxData, fstring("%s/area_1/macro.inc.c", _Folder.c_str())); + } + } + closedir(aPackDir); + } + + // Generate a binary file for each actor found in the GfxData + DynOS_Lvl_GeneratePack_Internal(aPackFolder, _ActorsFolders, _GfxData); + + DynOS_Gfx_Free(_GfxData); +} diff --git a/data/dynos_bin_pointer.cpp b/data/dynos_bin_pointer.cpp new file mode 100644 index 00000000..e1615c6e --- /dev/null +++ b/data/dynos_bin_pointer.cpp @@ -0,0 +1,191 @@ +#include "dynos.cpp.h" + + ///////////// + // Writing // +///////////// + +typedef Pair PointerData; +static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) { + + // Lights + for (auto& _Node : aGfxData->mLights) { + if (&_Node->mData->l[0] == aPtr) { // Light *, not Lights1 * + return { _Node->mName, 1 }; + } + if (&_Node->mData->a == aPtr) { // Ambient *, not Lights1 * + return { _Node->mName, 2 }; + } + } + + // Textures + for (auto& _Node : aGfxData->mTextures) { + if (_Node == aPtr) { + return { _Node->mName, 0 }; + } + } + + // Display lists + for (auto& _Node : aGfxData->mDisplayLists) { + if (_Node == aPtr) { + return { _Node->mName, 0 }; + } + } + + // Geo layouts + for (auto& _Node : aGfxData->mGeoLayouts) { + if (_Node->mData == aPtr) { + return { _Node->mName, 0 }; + } + } + + // Collisions + for (auto& _Node : aGfxData->mCollisions) { + if (_Node->mData == aPtr) { + return { _Node->mName, 0 }; + } + } + + // Level scripts + for (auto& _Node : aGfxData->mLevelScripts) { + if (_Node->mData == aPtr) { + return { _Node->mName, 0 }; + } + } + + // Macro objects + for (auto& _Node : aGfxData->mMacroObjects) { + if (_Node->mData == aPtr) { + return { _Node->mName, 0 }; + } + } + + // Vertices + String _VtxArrayName = ""; + uintptr_t _VtxArrayStart = 0; + for (auto& _Node : aGfxData->mVertices) { + if (_Node->mData == aPtr) { + return { _Node->mName, 0 }; + } + if ((uintptr_t)_Node->mData <= (uintptr_t)aPtr && + (uintptr_t)_Node->mData >= _VtxArrayStart) { + _VtxArrayName = _Node->mName; + _VtxArrayStart = (uintptr_t)_Node->mData; + } + } + return { _VtxArrayName, (u32)((const Vtx*)aPtr - (const Vtx*)_VtxArrayStart) }; +} + +void DynOS_Pointer_Write(FILE* aFile, const void* aPtr, GfxData* aGfxData) { + + // NULL + if (!aPtr) { + WriteBytes(aFile, 0); + return; + } + + // Geo function + s32 _GeoFunctionIndex = DynOS_Geo_GetFunctionIndex(aPtr); + if (_GeoFunctionIndex != -1) { + WriteBytes(aFile, FUNCTION_CODE); + WriteBytes(aFile, _GeoFunctionIndex); + return; + } + + // Pointer + PointerData _PtrData = GetDataFromPointer(aPtr, aGfxData); + WriteBytes(aFile, POINTER_CODE); + _PtrData.first.Write(aFile); + WriteBytes(aFile, _PtrData.second); +} + + ///////////// + // Reading // +///////////// + +static void *GetPointerFromData(GfxData *aGfxData, const String &aPtrName, u32 aPtrData) { + + // Lights + for (auto& _Node : aGfxData->mLights) { + if (_Node->mName == aPtrName) { + if (aPtrData == 1) { + return (void *) &_Node->mData->l[0]; + } + if (aPtrData == 2) { + return (void *) &_Node->mData->a; + } + sys_fatal("Unknown Light type: %u", aPtrData); + } + } + + // Textures + for (auto& _Node : aGfxData->mTextures) { + if (_Node->mName == aPtrName) { + return (void *) _Node; + } + } + + // Display lists + for (auto &_Node : aGfxData->mDisplayLists) { + if (_Node->mName == aPtrName) { + return (void *) _Node->mData; + } + } + + // Geo layouts + for (auto &_Node : aGfxData->mGeoLayouts) { + if (_Node->mName == aPtrName) { + return (void *) _Node->mData; + } + } + + // Vertices + for (auto &_Node : aGfxData->mVertices) { + if (_Node->mName == aPtrName) { + return (void *) (_Node->mData + aPtrData); + } + } + + // Collisions + for (auto &_Node : aGfxData->mCollisions) { + if (_Node->mName == aPtrName) { + return (void *) _Node->mData; + } + } + + // Level scripts + for (auto &_Node : aGfxData->mLevelScripts) { + if (_Node->mName == aPtrName) { + return (void *) _Node->mData; + } + } + + // Macro objects + for (auto &_Node : aGfxData->mMacroObjects) { + if (_Node->mName == aPtrName) { + return (void *) _Node->mData; + } + } + + // Error + sys_fatal("Pointer not found: %s", aPtrName.begin()); + return NULL; +} + +void *DynOS_Pointer_Load(FILE *aFile, GfxData *aGfxData, u32 aValue) { + + // FUNC + if (aValue == FUNCTION_CODE) { + s32 _GeoFunctionIndex = ReadBytes(aFile); + return DynOS_Geo_GetFunctionPointerFromIndex(_GeoFunctionIndex); + } + + // PNTR + if (aValue == POINTER_CODE) { + String _PtrName; _PtrName.Read(aFile); + u32 _PtrData = ReadBytes(aFile); + return GetPointerFromData(aGfxData, _PtrName, _PtrData); + } + + // Not a pointer + return NULL; +} diff --git a/data/dynos_bin_read.cpp b/data/dynos_bin_read.cpp new file mode 100644 index 00000000..cd73eee2 --- /dev/null +++ b/data/dynos_bin_read.cpp @@ -0,0 +1,276 @@ +#include "dynos.cpp.h" + +enum { + COMMENT_NONE = 0, + COMMENT_START, // first slash + COMMENT_SINGLE_LINE, // double slash, reset to COMMENT_NONE if \\n is hit + COMMENT_BLOCK, // slash-star, set to comment block end if * is hit + COMMENT_BLOCK_END, // slash-star-star, set to comment none if / is hit, else return to COMMENT_BLOCK +}; + +struct IfDefPtr { const char *mPtr; u64 mSize; bool mErase; }; +static IfDefPtr GetNearestIfDefPointer(char *pFileBuffer) { + static const IfDefPtr sIfDefs[] = { + { "#ifdef VERSION_JP", 17, true }, + { "#ifndef VERSION_JP", 18, false }, + { "#ifdef VERSION_EU", 17, true }, + { "#ifdef TEXTURE_FIX", 18, false }, + }; + IfDefPtr _Nearest = { NULL, 0, false }; + for (const auto &_IfDef : sIfDefs) { + const char *_Ptr = strstr(pFileBuffer, _IfDef.mPtr); + if (_Ptr != NULL && (_Nearest.mPtr == NULL || _Nearest.mPtr > _Ptr)) { + _Nearest.mPtr = _Ptr; + _Nearest.mSize = _IfDef.mSize; + _Nearest.mErase = _IfDef.mErase; + } + } + return _Nearest; +} + +char *DynOS_Read_Buffer(FILE* aFile, GfxData* aGfxData) { + fseek(aFile, 0, SEEK_END); + s32 _Length = ftell(aFile); + if (aGfxData && aGfxData->mModelIdentifier == 0) { + aGfxData->mModelIdentifier = (u32) _Length; + } + + // Remove comments + rewind(aFile); + char *_FileBuffer = New(_Length + 1); + char *pFileBuffer = _FileBuffer; + char _Previous = 0; + char _Current = 0; + s32 _CommentType = 0; + while (fread(&_Current, 1, 1, aFile)) { + if (_CommentType == COMMENT_NONE) { + if (_Current == '/') { + _CommentType = COMMENT_START; + } else { + *(pFileBuffer++) = _Current; + } + } else if (_CommentType == COMMENT_START) { + if (_Current == '/') { + _CommentType = COMMENT_SINGLE_LINE; + } else if (_Current == '*') { + _CommentType = COMMENT_BLOCK; + } else { + _CommentType = COMMENT_NONE; + *(pFileBuffer++) = _Previous; + *(pFileBuffer++) = _Current; + } + } else if (_CommentType == COMMENT_SINGLE_LINE) { + if (_Current == '\n') { + _CommentType = COMMENT_NONE; + *(pFileBuffer++) = _Current; + } + } else if (_CommentType == COMMENT_BLOCK) { + if (_Current == '*') { + _CommentType = COMMENT_BLOCK_END; + } + } else if (_CommentType == COMMENT_BLOCK_END) { + if (_Current == '/') { + _CommentType = COMMENT_NONE; + } else { + _CommentType = COMMENT_BLOCK; + } + } + _Previous = _Current; + } + *(pFileBuffer++) = 0; + + // Remove ifdef blocks + // Doesn't support nested blocks + for (pFileBuffer = _FileBuffer; pFileBuffer != NULL;) { + IfDefPtr _IfDefPtr = GetNearestIfDefPointer(pFileBuffer); + if (_IfDefPtr.mPtr) { + char *pIfDef = (char *) _IfDefPtr.mPtr; + char *pElse = (char *) strstr(_IfDefPtr.mPtr, "#else"); + char *pEndIf = (char *) strstr(_IfDefPtr.mPtr, "#endif"); + + if (pElse && pElse < pEndIf) { + if (_IfDefPtr.mErase) memset(pIfDef, ' ', pElse + 5 - pIfDef); + else memset(pElse, ' ', pEndIf - pElse); + } else { + if (_IfDefPtr.mErase) memset(pIfDef, ' ', pEndIf - pIfDef); + } + + memset(pIfDef, ' ', _IfDefPtr.mSize); + memset(pEndIf, ' ', 6); + pFileBuffer = pEndIf; + } else { + pFileBuffer = NULL; + } + } + + return _FileBuffer; +} + +template +static void AppendNewNode(GfxData *aGfxData, DataNodes &aNodes, const String &aName, String *&aDataName, Array *&aDataTokens) { + DataNode *_Node = New>(); + _Node->mName = aName; + _Node->mModelIdentifier = aGfxData->mModelIdentifier; + aNodes.Add(_Node); + aDataName = &_Node->mName; + aDataTokens = &_Node->mTokens; +} + +void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) { + FILE *_File = fopen(aFilename.c_str(), "rb"); + if (!_File) return; + + // Remember the geo layout count + s32 prevGeoLayoutCount = aGfxData->mGeoLayouts.Count(); + + // Load file into a buffer while removing all comments + char *_FileBuffer = DynOS_Read_Buffer(_File, aGfxData); + fclose(_File); + + // Scanning the loaded data + s32 _DataType = DATA_TYPE_NONE; + String* pDataName = NULL; + Array *pDataTokens = NULL; + char *pDataStart = NULL; + bool _DataIgnore = false; // Needed to ignore the '#include "file.h"' strings + String _Buffer = ""; + for (char *c = _FileBuffer; *c != 0; ++c) { + + // Scanning data type + if (_DataType == DATA_TYPE_NONE) { + + // Reading data type name + if ((*c >= 'A' && *c <= 'Z') || (*c >= 'a' && *c <= 'z') || (*c >= '0' && *c <= '9') || (*c == '_') || (*c == '\"')) { + if (*c == '\"') { + _DataIgnore = !_DataIgnore; + } else if (!_DataIgnore) { + _Buffer.Add(*c); + } + } + + // Retrieving data type + else if (_Buffer.Length() != 0) { + if (_Buffer == "static") { + // Ignore static keyword + } else if (_Buffer == "const") { + // Ignore const keyword + } else if (_Buffer == "inline") { + // Ignore inline keyword + } else if (_Buffer == "include") { + // Ignore include keyword + } else if (_Buffer == "ALIGNED8") { + // Ignore ALIGNED8 keyword + } else if (_Buffer == "UNUSED") { + // Ignore UNUSED keyword + } else if (_Buffer == "u64") { + _DataType = DATA_TYPE_UNUSED; + } else if (_Buffer == "Lights1") { + _DataType = DATA_TYPE_LIGHT; + } else if (_Buffer == "u8") { + _DataType = DATA_TYPE_TEXTURE; + } else if (_Buffer == "Texture") { + _DataType = DATA_TYPE_TEXTURE; + } else if (_Buffer == "Vtx") { + _DataType = DATA_TYPE_VERTEX; + } else if (_Buffer == "Gfx") { + _DataType = DATA_TYPE_DISPLAY_LIST; + } else if (_Buffer == "GeoLayout") { + _DataType = DATA_TYPE_GEO_LAYOUT; + } else if (_Buffer == "Collision") { + _DataType = DATA_TYPE_COLLISION; + } else if (_Buffer == "LevelScript") { + _DataType = DATA_TYPE_LEVEL_SCRIPT; + } else if (_Buffer == "MacroObject") { + _DataType = DATA_TYPE_MACRO_OBJECT; + } else { + PrintError(" ERROR: Unknown type name: %s", _Buffer.begin()); + } + _Buffer.Clear(); + } + } + + // Scanning data identifier + else if (!pDataTokens) { + + // Reading data identifier name + if ((*c >= 'A' && *c <= 'Z') || (*c >= 'a' && *c <= 'z') || (*c >= '0' && *c <= '9') || (*c == '_')) { + _Buffer.Add(*c); + } + + // Adding new data node + else if (_Buffer.Length() != 0) { + switch (_DataType) { + case DATA_TYPE_LIGHT: AppendNewNode(aGfxData, aGfxData->mLights, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_TEXTURE: AppendNewNode(aGfxData, aGfxData->mTextures, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_VERTEX: AppendNewNode(aGfxData, aGfxData->mVertices, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_DISPLAY_LIST: AppendNewNode(aGfxData, aGfxData->mDisplayLists, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_GEO_LAYOUT: AppendNewNode(aGfxData, aGfxData->mGeoLayouts, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_COLLISION: AppendNewNode(aGfxData, aGfxData->mCollisions, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_LEVEL_SCRIPT: AppendNewNode(aGfxData, aGfxData->mLevelScripts, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_MACRO_OBJECT: AppendNewNode(aGfxData, aGfxData->mMacroObjects, _Buffer, pDataName, pDataTokens); break; + case DATA_TYPE_UNUSED: pDataTokens = (Array *) 1; break; + } + _Buffer.Clear(); + } + } + + // Looking for data + else if (pDataStart == 0) { + if (*c == '=') { + pDataStart = c + 1; + } else if (*c == ';') { + PrintError(" ERROR: %s: Unexpected end of data", pDataName->begin()); + } + } + + // Data end + else if (*c == ';') { + if (_DataType != DATA_TYPE_UNUSED) { + char* pDataEnd = &*c; + String _Token = ""; + for (u8 _Bracket = 0; pDataStart <= pDataEnd; pDataStart++) { + if (*pDataStart == '(') _Bracket++; + if (*pDataStart == ' ' || *pDataStart == '\t' || *pDataStart == '\r' || *pDataStart == '\n') continue; + if (_Bracket <= 1 && (*pDataStart == '(' || *pDataStart == ')' || *pDataStart == ',' || *pDataStart == '{' || *pDataStart == '}' || *pDataStart == ';')) { + if (_Token.Length() != 0) { + pDataTokens->Add(_Token); + _Token.Clear(); + } + } else { + _Token.Add(*pDataStart); + } + if (*pDataStart == ')') _Bracket--; + } + } + _DataType = DATA_TYPE_NONE; + pDataName = NULL; + pDataTokens = NULL; + pDataStart = NULL; + _DataIgnore = false; + _Buffer = ""; + } + } + + // Figure out which geo layouts to generate + s32 geoLayoutCount = aGfxData->mGeoLayouts.Count(); + if (geoLayoutCount > prevGeoLayoutCount) { + // find actors to generate + bool foundActor = false; + for (s32 i = prevGeoLayoutCount; i < geoLayoutCount; i++) { + String _GeoRootName = aGfxData->mGeoLayouts[i]->mName; + const void* actor = DynOS_Geo_GetActorLayoutFromName(_GeoRootName.begin()); + if (actor != NULL) { + foundActor = true; + aGfxData->mGenerateGeoLayouts.Add(aGfxData->mGeoLayouts[i]); + } + } + + // if we haven't found an actor, just add the last geo layout found + if (!foundActor) { + aGfxData->mGenerateGeoLayouts.Add(aGfxData->mGeoLayouts[geoLayoutCount - 1]); + } + } + + Delete(_FileBuffer); + Print("Data read from file \"%s\"", aFilename.c_str()); +} diff --git a/data/dynos_bin_tex.cpp b/data/dynos_bin_tex.cpp index 27753611..184efdcb 100644 --- a/data/dynos_bin_tex.cpp +++ b/data/dynos_bin_tex.cpp @@ -108,3 +108,50 @@ DataNode* DynOS_Tex_Parse(GfxData* aGfxData, DataNode* aNode) aNode->mLoadIndex = aGfxData->mLoadIndex++; return aNode; } + + ///////////// + // Writing // +///////////// + +void DynOS_Tex_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { + if (!aNode->mData) return; + + // Header + WriteBytes(aFile, DATA_TYPE_TEXTURE); + aNode->mName.Write(aFile); + + // Data + aNode->mData->mPngData.Write(aFile); +} + + ///////////// + // Reading // +///////////// + +void DynOS_Tex_Load(FILE *aFile, GfxData *aGfxData) { + DataNode *_Node = New>(); + + // Name + _Node->mName.Read(aFile); + + // Data + _Node->mData = New(); + _Node->mData->mUploaded = false; + _Node->mData->mPngData.Read(aFile); + if (!_Node->mData->mPngData.Empty()) { + u8 *_RawData = stbi_load_from_memory(_Node->mData->mPngData.begin(), _Node->mData->mPngData.Count(), &_Node->mData->mRawWidth, &_Node->mData->mRawHeight, NULL, 4); + _Node->mData->mRawFormat = G_IM_FMT_RGBA; + _Node->mData->mRawSize = G_IM_SIZ_32b; + _Node->mData->mRawData = Array(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4)); + free(_RawData); + } else { // Probably a palette + _Node->mData->mRawData = Array(); + _Node->mData->mRawWidth = 0; + _Node->mData->mRawHeight = 0; + _Node->mData->mRawFormat = 0; + _Node->mData->mRawSize = 0; + } + + // Append + aGfxData->mTextures.Add(_Node); +} diff --git a/data/dynos_bin_utils.cpp b/data/dynos_bin_utils.cpp index 6648681d..ae926905 100644 --- a/data/dynos_bin_utils.cpp +++ b/data/dynos_bin_utils.cpp @@ -1,5 +1,51 @@ #include "dynos.cpp.h" + ////////// + // Misc // +////////// + +void DynOS_Gfx_Free(GfxData* aGfxData) { + if (aGfxData) { + for (auto& _Node : aGfxData->mLights) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mTextures) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mVertices) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mDisplayLists) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mGeoLayouts) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mAnimations) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mCollisions) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mLevelScripts) { + Delete(_Node->mData); + Delete(_Node); + } + for (auto& _Node : aGfxData->mMacroObjects) { + Delete(_Node->mData); + Delete(_Node); + } + Delete(aGfxData); + } +} + /////////////////////// // Recursive Descent // /////////////////////// diff --git a/data/dynos_bin_vtx.cpp b/data/dynos_bin_vtx.cpp index ccd958cf..86c19ae4 100644 --- a/data/dynos_bin_vtx.cpp +++ b/data/dynos_bin_vtx.cpp @@ -26,3 +26,60 @@ DataNode* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode* aNode) { aNode->mLoadIndex = aGfxData->mLoadIndex++; return aNode; } + + ///////////// + // Writing // +///////////// + +void DynOS_Vtx_Write(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { + if (!aNode->mData) return; + + // Header + WriteBytes(aFile, DATA_TYPE_VERTEX); + aNode->mName.Write(aFile); + + // Data + WriteBytes(aFile, aNode->mSize); + for (u32 i = 0; i != aNode->mSize; ++i) { + WriteBytes(aFile, aNode->mData[i].n.ob[0]); + WriteBytes(aFile, aNode->mData[i].n.ob[1]); + WriteBytes(aFile, aNode->mData[i].n.ob[2]); + WriteBytes(aFile, aNode->mData[i].n.flag); + WriteBytes(aFile, aNode->mData[i].n.tc[0]); + WriteBytes(aFile, aNode->mData[i].n.tc[1]); + WriteBytes (aFile, aNode->mData[i].n.n[0]); + WriteBytes (aFile, aNode->mData[i].n.n[1]); + WriteBytes (aFile, aNode->mData[i].n.n[2]); + WriteBytes (aFile, aNode->mData[i].n.a); + } +} + + ///////////// + // Reading // +///////////// + +void DynOS_Vtx_Load(FILE *aFile, GfxData *aGfxData) { + DataNode *_Node = New>(); + + // Name + _Node->mName.Read(aFile); + + // Data + _Node->mSize = ReadBytes(aFile); + _Node->mData = New(_Node->mSize); + for (u32 i = 0; i != _Node->mSize; ++i) { + _Node->mData[i].n.ob[0] = ReadBytes(aFile); + _Node->mData[i].n.ob[1] = ReadBytes(aFile); + _Node->mData[i].n.ob[2] = ReadBytes(aFile); + _Node->mData[i].n.flag = ReadBytes(aFile); + _Node->mData[i].n.tc[0] = ReadBytes(aFile); + _Node->mData[i].n.tc[1] = ReadBytes(aFile); + _Node->mData[i].n.n[0] = ReadBytes (aFile); + _Node->mData[i].n.n[1] = ReadBytes (aFile); + _Node->mData[i].n.n[2] = ReadBytes (aFile); + _Node->mData[i].n.a = ReadBytes(aFile); + } + + // Append + aGfxData->mVertices.Add(_Node); +} diff --git a/data/dynos_gfx_init.cpp b/data/dynos_gfx_init.cpp index 83c716a1..ae885ad0 100644 --- a/data/dynos_gfx_init.cpp +++ b/data/dynos_gfx_init.cpp @@ -32,7 +32,7 @@ void DynOS_Gfx_GeneratePacks(const char* directory) { } SysPath _ActorPackFolder = fstring("%s/%s/actors", directory, dir->d_name); if (fs_sys_dir_exists(_ActorPackFolder.c_str())) { - DynOS_Gfx_GeneratePack(_ActorPackFolder); + DynOS_Actor_GeneratePack(_ActorPackFolder); } } @@ -57,7 +57,7 @@ static void ScanPacksFolder(SysPath _DynosPacksFolder) { // Scan folder for subfolders to convert into .bin files _Pack->mPath = _PackFolder; - DynOS_Gfx_GeneratePack(_PackFolder); + DynOS_Actor_GeneratePack(_PackFolder); // Add pack to pack list pDynosPacks.Add(_Pack); diff --git a/data/dynos_gfx_load.cpp b/data/dynos_gfx_load.cpp deleted file mode 100644 index ea262d3a..00000000 --- a/data/dynos_gfx_load.cpp +++ /dev/null @@ -1,313 +0,0 @@ -#include "dynos.cpp.h" - -// -// Pointers -// - -static void *GetPointerFromData(GfxData *aGfxData, const String &aPtrName, u32 aPtrData) { - - // Lights - for (auto& _Node : aGfxData->mLights) { - if (_Node->mName == aPtrName) { - if (aPtrData == 1) { - return (void *) &_Node->mData->l[0]; - } - if (aPtrData == 2) { - return (void *) &_Node->mData->a; - } - sys_fatal("Unknown Light type: %u", aPtrData); - } - } - - // Textures - for (auto& _Node : aGfxData->mTextures) { - if (_Node->mName == aPtrName) { - return (void *) _Node; - } - } - - // Display lists - for (auto &_Node : aGfxData->mDisplayLists) { - if (_Node->mName == aPtrName) { - return (void *) _Node->mData; - } - } - - // Geo layouts - for (auto &_Node : aGfxData->mGeoLayouts) { - if (_Node->mName == aPtrName) { - return (void *) _Node->mData; - } - } - - // Vertices - for (auto &_Node : aGfxData->mVertices) { - if (_Node->mName == aPtrName) { - return (void *) (_Node->mData + aPtrData); - } - } - - // Error - sys_fatal("Pointer not found: %s", aPtrName.begin()); - return NULL; -} - -static void *ReadPointer(FILE *aFile, GfxData *aGfxData, u32 aValue) { - - // FUNC - if (aValue == FUNCTION_CODE) { - s32 _GeoFunctionIndex = ReadBytes(aFile); - return DynOS_Geo_GetFunctionPointerFromIndex(_GeoFunctionIndex); - } - - // PNTR - if (aValue == POINTER_CODE) { - String _PtrName; _PtrName.Read(aFile); - u32 _PtrData = ReadBytes(aFile); - return GetPointerFromData(aGfxData, _PtrName, _PtrData); - } - - // Not a pointer - return NULL; -} - -// -// Read binary -// - -static void LoadLightData(FILE *aFile, GfxData *aGfxData) { - DataNode *_Node = New>(); - - // Name - _Node->mName.Read(aFile); - - // Data - _Node->mData = New(); - *_Node->mData = ReadBytes(aFile); - - // Append - aGfxData->mLights.Add(_Node); -} - -static void LoadTextureData(FILE *aFile, GfxData *aGfxData) { - DataNode *_Node = New>(); - - // Name - _Node->mName.Read(aFile); - - // Data - _Node->mData = New(); - _Node->mData->mUploaded = false; - _Node->mData->mPngData.Read(aFile); - if (!_Node->mData->mPngData.Empty()) { - u8 *_RawData = stbi_load_from_memory(_Node->mData->mPngData.begin(), _Node->mData->mPngData.Count(), &_Node->mData->mRawWidth, &_Node->mData->mRawHeight, NULL, 4); - _Node->mData->mRawFormat = G_IM_FMT_RGBA; - _Node->mData->mRawSize = G_IM_SIZ_32b; - _Node->mData->mRawData = Array(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4)); - free(_RawData); - } else { // Probably a palette - _Node->mData->mRawData = Array(); - _Node->mData->mRawWidth = 0; - _Node->mData->mRawHeight = 0; - _Node->mData->mRawFormat = 0; - _Node->mData->mRawSize = 0; - } - - // Append - aGfxData->mTextures.Add(_Node); -} - -static void LoadVertexData(FILE *aFile, GfxData *aGfxData) { - DataNode *_Node = New>(); - - // Name - _Node->mName.Read(aFile); - - // Data - _Node->mSize = ReadBytes(aFile); - _Node->mData = New(_Node->mSize); - for (u32 i = 0; i != _Node->mSize; ++i) { - _Node->mData[i].n.ob[0] = ReadBytes(aFile); - _Node->mData[i].n.ob[1] = ReadBytes(aFile); - _Node->mData[i].n.ob[2] = ReadBytes(aFile); - _Node->mData[i].n.flag = ReadBytes(aFile); - _Node->mData[i].n.tc[0] = ReadBytes(aFile); - _Node->mData[i].n.tc[1] = ReadBytes(aFile); - _Node->mData[i].n.n[0] = ReadBytes (aFile); - _Node->mData[i].n.n[1] = ReadBytes (aFile); - _Node->mData[i].n.n[2] = ReadBytes (aFile); - _Node->mData[i].n.a = ReadBytes(aFile); - } - - // Append - aGfxData->mVertices.Add(_Node); -} - -static void LoadDisplayListData(FILE *aFile, GfxData *aGfxData) { - DataNode *_Node = New>(); - - // Name - _Node->mName.Read(aFile); - - // Data - _Node->mSize = ReadBytes(aFile); - _Node->mData = New(_Node->mSize); - for (u32 i = 0; i != _Node->mSize; ++i) { - u32 _WordsW0 = ReadBytes(aFile); - u32 _WordsW1 = ReadBytes(aFile); - void *_Ptr = ReadPointer(aFile, aGfxData, _WordsW1); - if (_Ptr) { - _Node->mData[i].words.w0 = (uintptr_t) _WordsW0; - _Node->mData[i].words.w1 = (uintptr_t) _Ptr; - } else { - _Node->mData[i].words.w0 = (uintptr_t) _WordsW0; - _Node->mData[i].words.w1 = (uintptr_t) _WordsW1; - } - } - - // Append - aGfxData->mDisplayLists.Add(_Node); -} - -static void LoadGeoLayoutData(FILE *aFile, GfxData *aGfxData) { - DataNode *_Node = New>(); - - // Name - _Node->mName.Read(aFile); - - // Data - _Node->mSize = ReadBytes(aFile); - _Node->mData = New(_Node->mSize); - for (u32 i = 0; i != _Node->mSize; ++i) { - u32 _Value = ReadBytes(aFile); - void *_Ptr = ReadPointer(aFile, aGfxData, _Value); - if (_Ptr) { - _Node->mData[i] = (uintptr_t) _Ptr; - } else { - _Node->mData[i] = (uintptr_t) _Value; - } - } - - // Append - aGfxData->mGeoLayouts.Add(_Node); -} - -// For retro-compatibility -static void LoadGfxDynCmd(FILE *aFile, GfxData *aGfxData) { - Gfx *_Data = NULL; - String _DisplayListName; _DisplayListName.Read(aFile); - for (auto& _DisplayList : aGfxData->mDisplayLists) { - if (_DisplayList->mName == _DisplayListName) { - _Data = _DisplayList->mData; - break; - } - } - if (!_Data) { - sys_fatal("Display list not found: %s", _DisplayListName.begin()); - } - ReadBytes(aFile); - ReadBytes(aFile); -} - -static void LoadAnimationData(FILE *aFile, GfxData *aGfxData) { - DataNode *_Node = New>(); - - // Name - _Node->mName.Read(aFile); - - // Data - _Node->mData = New(); - _Node->mData->mFlags = ReadBytes(aFile); - _Node->mData->mUnk02 = ReadBytes(aFile); - _Node->mData->mUnk04 = ReadBytes(aFile); - _Node->mData->mUnk06 = ReadBytes(aFile); - _Node->mData->mUnk08 = ReadBytes(aFile); - _Node->mData->mUnk0A.second = ReadBytes(aFile); - _Node->mData->mLength = ReadBytes(aFile); - _Node->mData->mValues.second.Read(aFile); - _Node->mData->mIndex.second.Read(aFile); - - // Append - aGfxData->mAnimations.Add(_Node); -} - -static void LoadAnimationTable(FILE *aFile, GfxData *aGfxData) { - void *_AnimationPtr = NULL; - - // Data - String _AnimationName; _AnimationName.Read(aFile); - if (_AnimationName != "NULL") { - for (auto &_AnimData : aGfxData->mAnimations) { - if (_AnimData->mName == _AnimationName) { - _AnimationPtr = (void *) _AnimData->mData; - break; - } - } - if (!_AnimationPtr) { - sys_fatal("Animation not found: %s", _AnimationName.begin()); - } - } - - // Append - aGfxData->mAnimationTable.Add({ "", _AnimationPtr }); -} - -// -// Load from binary -// - -GfxData *DynOS_Gfx_LoadFromBinary(const SysPath &aPackFolder, const char *aActorName) { - 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; - SysPath _Filename = fstring("%s/%s.bin", aPackFolder.begin(), aActorName); - FILE *_File = fopen(_Filename.c_str(), "rb"); - if (_File) { - _GfxData = New(); - for (bool _Done = false; !_Done;) { - switch (ReadBytes(_File)) { - case DATA_TYPE_LIGHT: LoadLightData (_File, _GfxData); break; - case DATA_TYPE_TEXTURE: LoadTextureData (_File, _GfxData); break; - case DATA_TYPE_VERTEX: LoadVertexData (_File, _GfxData); break; - case DATA_TYPE_DISPLAY_LIST: LoadDisplayListData(_File, _GfxData); break; - case DATA_TYPE_GEO_LAYOUT: LoadGeoLayoutData (_File, _GfxData); break; - case DATA_TYPE_ANIMATION: LoadAnimationData (_File, _GfxData); break; - case DATA_TYPE_ANIMATION_TABLE: LoadAnimationTable (_File, _GfxData); break; - case DATA_TYPE_GFXDYNCMD: LoadGfxDynCmd (_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; -} diff --git a/data/dynos_gfx_read.cpp b/data/dynos_gfx_read.cpp deleted file mode 100644 index b968a698..00000000 --- a/data/dynos_gfx_read.cpp +++ /dev/null @@ -1,629 +0,0 @@ -#include "dynos.cpp.h" -extern "C" { -} - -// -// Model files -// - -enum { - COMMENT_NONE = 0, - COMMENT_START, // first slash - COMMENT_SINGLE_LINE, // double slash, reset to COMMENT_NONE if \\n is hit - COMMENT_BLOCK, // slash-star, set to comment block end if * is hit - COMMENT_BLOCK_END, // slash-star-star, set to comment none if / is hit, else return to COMMENT_BLOCK -}; - -struct IfDefPtr { const char *mPtr; u64 mSize; bool mErase; }; -static IfDefPtr GetNearestIfDefPointer(char *pFileBuffer) { - static const IfDefPtr sIfDefs[] = { - { "#ifdef VERSION_JP", 17, true }, - { "#ifndef VERSION_JP", 18, false }, - { "#ifdef VERSION_EU", 17, true }, - { "#ifdef TEXTURE_FIX", 18, false }, - }; - IfDefPtr _Nearest = { NULL, 0, false }; - for (const auto &_IfDef : sIfDefs) { - const char *_Ptr = strstr(pFileBuffer, _IfDef.mPtr); - if (_Ptr != NULL && (_Nearest.mPtr == NULL || _Nearest.mPtr > _Ptr)) { - _Nearest.mPtr = _Ptr; - _Nearest.mSize = _IfDef.mSize; - _Nearest.mErase = _IfDef.mErase; - } - } - return _Nearest; -} - -static char *LoadFileBuffer(FILE* aFile, GfxData* aGfxData) { - fseek(aFile, 0, SEEK_END); - s32 _Length = ftell(aFile); - if (aGfxData && aGfxData->mModelIdentifier == 0) { - aGfxData->mModelIdentifier = (u32) _Length; - } - - // Remove comments - rewind(aFile); - char *_FileBuffer = New(_Length + 1); - char *pFileBuffer = _FileBuffer; - char _Previous = 0; - char _Current = 0; - s32 _CommentType = 0; - while (fread(&_Current, 1, 1, aFile)) { - if (_CommentType == COMMENT_NONE) { - if (_Current == '/') { - _CommentType = COMMENT_START; - } else { - *(pFileBuffer++) = _Current; - } - } else if (_CommentType == COMMENT_START) { - if (_Current == '/') { - _CommentType = COMMENT_SINGLE_LINE; - } else if (_Current == '*') { - _CommentType = COMMENT_BLOCK; - } else { - _CommentType = COMMENT_NONE; - *(pFileBuffer++) = _Previous; - *(pFileBuffer++) = _Current; - } - } else if (_CommentType == COMMENT_SINGLE_LINE) { - if (_Current == '\n') { - _CommentType = COMMENT_NONE; - *(pFileBuffer++) = _Current; - } - } else if (_CommentType == COMMENT_BLOCK) { - if (_Current == '*') { - _CommentType = COMMENT_BLOCK_END; - } - } else if (_CommentType == COMMENT_BLOCK_END) { - if (_Current == '/') { - _CommentType = COMMENT_NONE; - } else { - _CommentType = COMMENT_BLOCK; - } - } - _Previous = _Current; - } - *(pFileBuffer++) = 0; - - // Remove ifdef blocks - // Doesn't support nested blocks - for (pFileBuffer = _FileBuffer; pFileBuffer != NULL;) { - IfDefPtr _IfDefPtr = GetNearestIfDefPointer(pFileBuffer); - if (_IfDefPtr.mPtr) { - char *pIfDef = (char *) _IfDefPtr.mPtr; - char *pElse = (char *) strstr(_IfDefPtr.mPtr, "#else"); - char *pEndIf = (char *) strstr(_IfDefPtr.mPtr, "#endif"); - - if (pElse && pElse < pEndIf) { - if (_IfDefPtr.mErase) memset(pIfDef, ' ', pElse + 5 - pIfDef); - else memset(pElse, ' ', pEndIf - pElse); - } else { - if (_IfDefPtr.mErase) memset(pIfDef, ' ', pEndIf - pIfDef); - } - - memset(pIfDef, ' ', _IfDefPtr.mSize); - memset(pEndIf, ' ', 6); - pFileBuffer = pEndIf; - } else { - pFileBuffer = NULL; - } - } - - return _FileBuffer; -} - -template -static void AppendNewNode(GfxData *aGfxData, DataNodes &aNodes, const String &aName, String *&aDataName, Array *&aDataTokens) { - DataNode *_Node = New>(); - _Node->mName = aName; - _Node->mModelIdentifier = aGfxData->mModelIdentifier; - aNodes.Add(_Node); - aDataName = &_Node->mName; - aDataTokens = &_Node->mTokens; -} - -static void ScanModelFile(GfxData *aGfxData, const SysPath &aFilename) { - FILE *_File = fopen(aFilename.c_str(), "rb"); - if (!_File) return; - - // Remember the geo layout count - s32 prevGeoLayoutCount = aGfxData->mGeoLayouts.Count(); - - // Load file into a buffer while removing all comments - char *_FileBuffer = LoadFileBuffer(_File, aGfxData); - fclose(_File); - - // Scanning the loaded data - s32 _DataType = DATA_TYPE_NONE; - String* pDataName = NULL; - Array *pDataTokens = NULL; - char *pDataStart = NULL; - bool _DataIgnore = false; // Needed to ignore the '#include "file.h"' strings - String _Buffer = ""; - for (char *c = _FileBuffer; *c != 0; ++c) { - - // Scanning data type - if (_DataType == DATA_TYPE_NONE) { - - // Reading data type name - if ((*c >= 'A' && *c <= 'Z') || (*c >= 'a' && *c <= 'z') || (*c >= '0' && *c <= '9') || (*c == '_') || (*c == '\"')) { - if (*c == '\"') { - _DataIgnore = !_DataIgnore; - } else if (!_DataIgnore) { - _Buffer.Add(*c); - } - } - - // Retrieving data type - else if (_Buffer.Length() != 0) { - if (_Buffer == "static") { - // Ignore static keyword - } else if (_Buffer == "const") { - // Ignore const keyword - } else if (_Buffer == "inline") { - // Ignore inline keyword - } else if (_Buffer == "include") { - // Ignore include keyword - } else if (_Buffer == "ALIGNED8") { - // Ignore ALIGNED8 keyword - } else if (_Buffer == "UNUSED") { - // Ignore UNUSED keyword - } else if (_Buffer == "u64") { - _DataType = DATA_TYPE_UNUSED; - } else if (_Buffer == "Lights1") { - _DataType = DATA_TYPE_LIGHT; - } else if (_Buffer == "u8") { - _DataType = DATA_TYPE_TEXTURE; - } else if (_Buffer == "Texture") { - _DataType = DATA_TYPE_TEXTURE; - } else if (_Buffer == "Vtx") { - _DataType = DATA_TYPE_VERTEX; - } else if (_Buffer == "Gfx") { - _DataType = DATA_TYPE_DISPLAY_LIST; - } else if (_Buffer == "GeoLayout") { - _DataType = DATA_TYPE_GEO_LAYOUT; - } else if (_Buffer == "Collision") { - _DataType = DATA_TYPE_COLLISION; - } else if (_Buffer == "LevelScript") { - _DataType = DATA_TYPE_LEVEL_SCRIPT; - } else if (_Buffer == "MacroObject") { - _DataType = DATA_TYPE_MACRO_OBJECT; - } else { - PrintError(" ERROR: Unknown type name: %s", _Buffer.begin()); - } - _Buffer.Clear(); - } - } - - // Scanning data identifier - else if (!pDataTokens) { - - // Reading data identifier name - if ((*c >= 'A' && *c <= 'Z') || (*c >= 'a' && *c <= 'z') || (*c >= '0' && *c <= '9') || (*c == '_')) { - _Buffer.Add(*c); - } - - // Adding new data node - else if (_Buffer.Length() != 0) { - switch (_DataType) { - case DATA_TYPE_LIGHT: AppendNewNode(aGfxData, aGfxData->mLights, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_TEXTURE: AppendNewNode(aGfxData, aGfxData->mTextures, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_VERTEX: AppendNewNode(aGfxData, aGfxData->mVertices, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_DISPLAY_LIST: AppendNewNode(aGfxData, aGfxData->mDisplayLists, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_GEO_LAYOUT: AppendNewNode(aGfxData, aGfxData->mGeoLayouts, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_COLLISION: AppendNewNode(aGfxData, aGfxData->mCollisions, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_LEVEL_SCRIPT: AppendNewNode(aGfxData, aGfxData->mLevelScripts, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_MACRO_OBJECT: AppendNewNode(aGfxData, aGfxData->mMacroObjects, _Buffer, pDataName, pDataTokens); break; - case DATA_TYPE_UNUSED: pDataTokens = (Array *) 1; break; - } - _Buffer.Clear(); - } - } - - // Looking for data - else if (pDataStart == 0) { - if (*c == '=') { - pDataStart = c + 1; - } else if (*c == ';') { - PrintError(" ERROR: %s: Unexpected end of data", pDataName->begin()); - } - } - - // Data end - else if (*c == ';') { - if (_DataType != DATA_TYPE_UNUSED) { - char* pDataEnd = &*c; - String _Token = ""; - for (u8 _Bracket = 0; pDataStart <= pDataEnd; pDataStart++) { - if (*pDataStart == '(') _Bracket++; - if (*pDataStart == ' ' || *pDataStart == '\t' || *pDataStart == '\r' || *pDataStart == '\n') continue; - if (_Bracket <= 1 && (*pDataStart == '(' || *pDataStart == ')' || *pDataStart == ',' || *pDataStart == '{' || *pDataStart == '}' || *pDataStart == ';')) { - if (_Token.Length() != 0) { - pDataTokens->Add(_Token); - _Token.Clear(); - } - } else { - _Token.Add(*pDataStart); - } - if (*pDataStart == ')') _Bracket--; - } - } - _DataType = DATA_TYPE_NONE; - pDataName = NULL; - pDataTokens = NULL; - pDataStart = NULL; - _DataIgnore = false; - _Buffer = ""; - } - } - - // Figure out which geo layouts to generate - s32 geoLayoutCount = aGfxData->mGeoLayouts.Count(); - if (geoLayoutCount > prevGeoLayoutCount) { - // find actors to generate - bool foundActor = false; - for (s32 i = prevGeoLayoutCount; i < geoLayoutCount; i++) { - String _GeoRootName = aGfxData->mGeoLayouts[i]->mName; - const void* actor = DynOS_Geo_GetActorLayoutFromName(_GeoRootName.begin()); - if (actor != NULL) { - foundActor = true; - aGfxData->mGenerateGeoLayouts.Add(aGfxData->mGeoLayouts[i]); - } - } - - // if we haven't found an actor, just add the last geo layout found - if (!foundActor) { - aGfxData->mGenerateGeoLayouts.Add(aGfxData->mGeoLayouts[geoLayoutCount - 1]); - } - } - - Delete(_FileBuffer); - Print("Data read from file \"%s\"", aFilename.c_str()); -} - -// -// Animation files -// - -static void ScanAnimationDataFile(GfxData *aGfxData, const SysPath &aFilename) { - FILE *_File = fopen(aFilename.c_str(), "rb"); - if (!_File) { - PrintError(" ERROR: Unable to open file \"%s\"", aFilename.c_str()); - } - - // Load file into a buffer while removing all comments - char *_FileBuffer = LoadFileBuffer(_File, NULL); - fclose(_File); - - // Parse animation data - u8 _DataType = DATA_TYPE_NONE; - String _DataName; - bool _IsData = false; - Array _Data; - Array _Tokens = Split(_FileBuffer, " []()=&,;\t\r\n\b"); - for (const auto &_Token : _Tokens) { - - // Data type - if (_DataType == DATA_TYPE_NONE) { - if (_Token == "s16" || _Token == "u16" || _Token == "s16") { - _DataType = DATA_TYPE_ANIMATION_VALUE; - } else if (_Token == "Animation") { - _DataType = DATA_TYPE_ANIMATION; - } - } - - // Data name - else if (_DataName.Empty()) { - _DataName = _Token; - if (_DataType == DATA_TYPE_ANIMATION_VALUE && (_DataName.Find("index") != -1 || _DataName.Find("indices") != -1)) { - _DataType = DATA_TYPE_ANIMATION_INDEX; - } - } - - // Is data? - else if (!_IsData) { - if (_Token == "{") { - _IsData = true; - } - } - - // Data - else { - if (_Token == "}") { - switch (_DataType) { - case DATA_TYPE_ANIMATION_VALUE: { - AnimBuffer *_AnimValues = New>(); - _AnimValues->first = _DataName; - for (const auto &_Value : _Data) { - _AnimValues->second.Add(_Value.ParseInt()); - } - aGfxData->mAnimValues.Add(_AnimValues); - } break; - - case DATA_TYPE_ANIMATION_INDEX: { - AnimBuffer *_AnimIndices = New>(); - _AnimIndices->first = _DataName; - for (const auto &_Index : _Data) { - _AnimIndices->second.Add(_Index.ParseInt()); - } - aGfxData->mAnimIndices.Add(_AnimIndices); - } break; - - case DATA_TYPE_ANIMATION: { - if (_Data.Count() < 10) { - PrintError(" ERROR: %s: Not enough data", _DataName.begin()); - break; - } - - DataNode *_Node = New>(); - _Node->mName = _DataName; - _Node->mData = New(); - _Node->mData->mFlags = (s16) _Data[0].ParseInt(); - _Node->mData->mUnk02 = (s16) _Data[1].ParseInt(); - _Node->mData->mUnk04 = (s16) _Data[2].ParseInt(); - _Node->mData->mUnk06 = (s16) _Data[3].ParseInt(); - _Node->mData->mUnk08 = (s16) _Data[4].ParseInt(); - _Node->mData->mUnk0A.first = _Data[6]; // 5 is "ANIMINDEX_NUMPARTS" - _Node->mData->mValues.first = _Data[7]; - _Node->mData->mIndex.first = _Data[8]; - _Node->mData->mLength = (u32) _Data[9].ParseInt(); - aGfxData->mAnimations.Add(_Node); - } break; - } - _DataType = DATA_TYPE_NONE; - _DataName.Clear(); - _IsData = false; - _Data.Clear(); - } else { - _Data.Add(_Token); - } - } - } - Delete(_FileBuffer); -} - -static void ScanAnimationTableFile(GfxData *aGfxData, const SysPath &aFilename) { - FILE *_File = fopen(aFilename.c_str(), "rb"); - if (!_File) { - PrintError(" ERROR: Unable to open file \"%s\"", aFilename.c_str()); - } - - // Load file into a buffer while removing all comments - char *_FileBuffer = LoadFileBuffer(_File, NULL); - fclose(_File); - - // Retrieve animation names - bool _IsAnimName = false; - Array _Tokens = Split(_FileBuffer, " =&,;\t\r\n\b"); - for (const auto &_Token : _Tokens) { - if (_Token == "{") { - _IsAnimName = true; - } else if (_Token == "}") { - _IsAnimName = false; - } else if (_IsAnimName) { - aGfxData->mAnimationTable.Add({ _Token, NULL }); - } - } - Delete(_FileBuffer); -} - -static void ScanAnimationFolder(GfxData *aGfxData, const SysPath &aAnimsFolder) { - DIR *_AnimsDir = opendir(aAnimsFolder.c_str()); - if (!_AnimsDir) return; - - struct dirent *_AnimsEnt = NULL; - while ((_AnimsEnt = readdir(_AnimsDir)) != NULL) { - - // Skip - if (SysPath(_AnimsEnt->d_name) == ".") continue; - if (SysPath(_AnimsEnt->d_name) == "..") continue; - if (SysPath(_AnimsEnt->d_name) == "data.inc.c") continue; - - // Animation file - SysPath _AnimsFilename = fstring("%s/%s", aAnimsFolder.c_str(), _AnimsEnt->d_name); - if (fs_sys_file_exists(_AnimsFilename.c_str())) { - - // Table file - if (SysPath(_AnimsEnt->d_name) == "table.inc.c") { - ScanAnimationTableFile(aGfxData, _AnimsFilename); - } - - // Data file - else { - ScanAnimationDataFile(aGfxData, _AnimsFilename); - } - } - } - closedir(_AnimsDir); -} - -// -// Read & Generate -// - -// Free data pointers, but keep nodes and tokens intact -// Delete nodes generated from GfxDynCmds -template -static void ClearGfxDataNodes(DataNodes &aDataNodes) { - for (s32 i = aDataNodes.Count(); i != 0; --i) { - Delete(aDataNodes[i - 1]->mData); - } -} - -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_Col_Generate(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData) { - for (auto &_ColNode : _GfxData->mCollisions) { - String _ColRootName = _ColNode->mName; - - // If there is an existing binary file for this collision, skip and go to the next actor - SysPath _ColFilename = fstring("%s/%s.col", aPackFolder.c_str(), _ColRootName.begin()); - if (fs_sys_file_exists(_ColFilename.c_str())) { - continue; - } - - // Init - _GfxData->mErrorCount = 0; - _GfxData->mLoadIndex = 0; - - // Parse data - PrintNoNewLine("%s.col: Model identifier: %X - Processing... ", _ColRootName.begin(), _GfxData->mModelIdentifier); - DynOS_Col_Parse(_GfxData, _ColNode, true); - - // Write if no error - if (_GfxData->mErrorCount == 0) { - DynOS_Col_WriteBinary(_ColFilename, _GfxData, _ColNode); - } else { - Print(" %u error(s): Unable to parse data", _GfxData->mErrorCount); - } - - // Clear data pointers - ClearGfxDataNodes(_GfxData->mCollisions); - } -} - -static void DynOS_Actor_Generate(const SysPath &aPackFolder, Array> _ActorsFolders, GfxData *_GfxData) { - for (auto &_GeoNode : _GfxData->mGenerateGeoLayouts) { - 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())) { - continue; - } - - // 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->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()); - ScanAnimationFolder(_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_Gfx_WriteBinary(_BinFilename, _GfxData); - } else { - Print(" %u error(s): Unable to parse data", _GfxData->mErrorCount); - } - // Clear data pointers - ClearGfxDataNodes(_GfxData->mLights); - ClearGfxDataNodes(_GfxData->mTextures); - ClearGfxDataNodes(_GfxData->mVertices); - ClearGfxDataNodes(_GfxData->mDisplayLists); - ClearGfxDataNodes(_GfxData->mGeoLayouts); - ClearGfxDataNodes(_GfxData->mCollisions); - } -} - -void DynOS_Gfx_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; - ScanModelFile(_GfxData, fstring("%s/model.inc.c", _Folder.c_str())); - ScanModelFile(_GfxData, fstring("%s/geo.inc.c", _Folder.c_str())); - ScanModelFile(_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); -} - -void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder) { - Print("---------- Level pack folder: \"%s\" ----------", aPackFolder.c_str()); - Array> _ActorsFolders; - GfxData *_GfxData = New(); - - 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 script.c - SysPath _Folder = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); - if (fs_sys_dir_exists(_Folder.c_str())) { - _GfxData->mModelIdentifier = 0; - ScanModelFile(_GfxData, fstring("%s/model.inc.c", _Folder.c_str())); - ScanModelFile(_GfxData, fstring("%s/area_1/collision.inc.c", _Folder.c_str())); - ScanModelFile(_GfxData, fstring("%s/area_1/geo.inc.c", _Folder.c_str())); - ScanModelFile(_GfxData, fstring("%s/script.c", _Folder.c_str())); - ScanModelFile(_GfxData, fstring("%s/area_1/macro.inc.c", _Folder.c_str())); - } - } - closedir(aPackDir); - } - - // Generate a binary file for each actor found in the GfxData - DynOS_Lvl_GeneratePack_Internal(aPackFolder, _ActorsFolders, _GfxData); - - DynOS_Gfx_Free(_GfxData); -} diff --git a/data/dynos_gfx_update.cpp b/data/dynos_gfx_update.cpp index ec373a85..6cbe9492 100644 --- a/data/dynos_gfx_update.cpp +++ b/data/dynos_gfx_update.cpp @@ -139,7 +139,7 @@ void DynOS_Gfx_Update() { if (_Enabled[i] && _ActorGfx->mPackIndex == -1) { // Load Gfx data from binary - GfxData *_GfxData = DynOS_Gfx_LoadFromBinary(pDynosPacks[i]->mPath, DynOS_Geo_GetActorName(_ActorIndex)); + GfxData *_GfxData = DynOS_Actor_LoadFromBinary(pDynosPacks[i]->mPath, DynOS_Geo_GetActorName(_ActorIndex)); if (_GfxData) { _ActorGfx->mPackIndex = i; _ActorGfx->mGfxData = _GfxData; diff --git a/data/dynos_gfx_write.cpp b/data/dynos_gfx_write.cpp deleted file mode 100644 index 1697470a..00000000 --- a/data/dynos_gfx_write.cpp +++ /dev/null @@ -1,330 +0,0 @@ -#include "dynos.cpp.h" - -// -// Pointers -// - -typedef Pair PointerData; -static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) { - - // Lights - for (auto& _Node : aGfxData->mLights) { - if (&_Node->mData->l[0] == aPtr) { // Light *, not Lights1 * - return { _Node->mName, 1 }; - } - if (&_Node->mData->a == aPtr) { // Ambient *, not Lights1 * - return { _Node->mName, 2 }; - } - } - - // Textures - for (auto& _Node : aGfxData->mTextures) { - if (_Node == aPtr) { - return { _Node->mName, 0 }; - } - } - - // Display lists - for (auto& _Node : aGfxData->mDisplayLists) { - if (_Node == aPtr) { - return { _Node->mName, 0 }; - } - } - - // Geo layouts - for (auto& _Node : aGfxData->mGeoLayouts) { - if (_Node->mData == aPtr) { - return { _Node->mName, 0 }; - } - } - - // Vertices - String _VtxArrayName = ""; - uintptr_t _VtxArrayStart = 0; - for (auto& _Node : aGfxData->mVertices) { - if (_Node->mData == aPtr) { - return { _Node->mName, 0 }; - } - if ((uintptr_t)_Node->mData <= (uintptr_t)aPtr && - (uintptr_t)_Node->mData >= _VtxArrayStart) { - _VtxArrayName = _Node->mName; - _VtxArrayStart = (uintptr_t)_Node->mData; - } - } - return { _VtxArrayName, (u32)((const Vtx*)aPtr - (const Vtx*)_VtxArrayStart) }; -} - -static void WritePointer(FILE* aFile, const void* aPtr, GfxData* aGfxData) { - - // NULL - if (!aPtr) { - WriteBytes(aFile, 0); - return; - } - - // Geo function - s32 _GeoFunctionIndex = DynOS_Geo_GetFunctionIndex(aPtr); - if (_GeoFunctionIndex != -1) { - WriteBytes(aFile, FUNCTION_CODE); - WriteBytes(aFile, _GeoFunctionIndex); - return; - } - - // Pointer - PointerData _PtrData = GetDataFromPointer(aPtr, aGfxData); - WriteBytes(aFile, POINTER_CODE); - _PtrData.first.Write(aFile); - WriteBytes(aFile, _PtrData.second); -} - -// -// Lights -// - -static void WriteLightData(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { - if (!aNode->mData) return; - - // Header - WriteBytes(aFile, DATA_TYPE_LIGHT); - aNode->mName.Write(aFile); - - // Data - WriteBytes(aFile, *aNode->mData); -} - -// -// Textures -// - -static void WriteTextureData(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { - if (!aNode->mData) return; - - // Header - WriteBytes(aFile, DATA_TYPE_TEXTURE); - aNode->mName.Write(aFile); - - // Data - aNode->mData->mPngData.Write(aFile); -} - -// -// Vertices -// - -static void WriteVertexData(FILE* aFile, GfxData* aGfxData, DataNode *aNode) { - if (!aNode->mData) return; - - // Header - WriteBytes(aFile, DATA_TYPE_VERTEX); - aNode->mName.Write(aFile); - - // Data - WriteBytes(aFile, aNode->mSize); - for (u32 i = 0; i != aNode->mSize; ++i) { - WriteBytes(aFile, aNode->mData[i].n.ob[0]); - WriteBytes(aFile, aNode->mData[i].n.ob[1]); - WriteBytes(aFile, aNode->mData[i].n.ob[2]); - WriteBytes(aFile, aNode->mData[i].n.flag); - WriteBytes(aFile, aNode->mData[i].n.tc[0]); - WriteBytes(aFile, aNode->mData[i].n.tc[1]); - WriteBytes (aFile, aNode->mData[i].n.n[0]); - WriteBytes (aFile, aNode->mData[i].n.n[1]); - WriteBytes (aFile, aNode->mData[i].n.n[2]); - WriteBytes (aFile, aNode->mData[i].n.a); - } -} - -// -// Display lists -// - -static void WriteDisplayListData(FILE *aFile, GfxData *aGfxData, DataNode *aNode) { - if (!aNode->mData) return; - - // Header - WriteBytes(aFile, DATA_TYPE_DISPLAY_LIST); - aNode->mName.Write(aFile); - - // Data - WriteBytes(aFile, aNode->mSize); - for (u32 i = 0; i != aNode->mSize; ++i) { - Gfx *_Head = &aNode->mData[i]; - if (aGfxData->mPointerList.Find((void *) _Head) != -1) { - WriteBytes(aFile, _Head->words.w0); - WritePointer(aFile, (const void *) _Head->words.w1, aGfxData); - } else { - WriteBytes(aFile, _Head->words.w0); - WriteBytes(aFile, _Head->words.w1); - } - } -} - -// -// Geo layouts -// - -static void WriteGeoLayoutData(FILE *aFile, GfxData *aGfxData, DataNode *aNode) { - if (!aNode->mData) return; - - // Header - WriteBytes(aFile, DATA_TYPE_GEO_LAYOUT); - aNode->mName.Write(aFile); - - // Data - WriteBytes(aFile, aNode->mSize); - for (u32 i = 0; i != aNode->mSize; ++i) { - GeoLayout *_Head = &aNode->mData[i]; - if (aGfxData->mPointerList.Find((void *) _Head) != -1) { - WritePointer(aFile, (const void *) (*_Head), aGfxData); - } else { - WriteBytes(aFile, *((u32 *) _Head)); - } - } -} - -// -// Animation data -// - -static void WriteAnimationData(FILE* aFile, GfxData* aGfxData) { - for (auto& _Node : aGfxData->mAnimations) { - - // Value buffer - s32 _ValueBufferIdx = aGfxData->mAnimValues.FindIf([&_Node](const AnimBuffer *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mValues.first; }); - if (_ValueBufferIdx == -1) { - continue; - } - - // Index buffer - s32 _IndexBufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mIndex.first; }); - if (_IndexBufferIdx == -1) { - continue; - } - - // Unk0A buffer - s32 _Unk0ABufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mUnk0A.first; }); - if (_Unk0ABufferIdx == -1) { - continue; - } - - // Header - WriteBytes(aFile, DATA_TYPE_ANIMATION); - _Node->mName.Write(aFile); - - // Data - WriteBytes(aFile, _Node->mData->mFlags); - WriteBytes(aFile, _Node->mData->mUnk02); - WriteBytes(aFile, _Node->mData->mUnk04); - WriteBytes(aFile, _Node->mData->mUnk06); - WriteBytes(aFile, _Node->mData->mUnk08); - WriteBytes(aFile, (aGfxData->mAnimIndices[_Unk0ABufferIdx]->second.Count() / 6) - 1); - WriteBytes(aFile, _Node->mData->mLength); - aGfxData->mAnimValues[_ValueBufferIdx]->second.Write(aFile); - aGfxData->mAnimIndices[_IndexBufferIdx]->second.Write(aFile); - } -} - -// -// Animation table -// - -static void WriteAnimationTable(FILE* aFile, GfxData* aGfxData) { - for (auto& _AnimName : aGfxData->mAnimationTable) { - - // Header - WriteBytes(aFile, DATA_TYPE_ANIMATION_TABLE); - - // Data - _AnimName.first.Write(aFile); - } -} - -// -// Write -// - -bool DynOS_Gfx_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) { - WriteLightData(_File, aGfxData, _Node); - } - } - for (auto &_Node : aGfxData->mTextures) { - if (_Node->mLoadIndex == i) { - WriteTextureData(_File, aGfxData, _Node); - } - } - for (auto &_Node : aGfxData->mVertices) { - if (_Node->mLoadIndex == i) { - WriteVertexData(_File, aGfxData, _Node); - } - } - for (auto &_Node : aGfxData->mDisplayLists) { - if (_Node->mLoadIndex == i) { - WriteDisplayListData(_File, aGfxData, _Node); - } - } - for (auto &_Node : aGfxData->mGeoLayouts) { - if (_Node->mLoadIndex == i) { - WriteGeoLayoutData(_File, aGfxData, _Node); - } - } - } - WriteAnimationData(_File, aGfxData); - WriteAnimationTable(_File, aGfxData); - fclose(_File); - return true; -} - -// -// Free -// - -void DynOS_Gfx_Free(GfxData* aGfxData) { - if (aGfxData) { - for (auto& _Node : aGfxData->mLights) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mTextures) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mVertices) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mDisplayLists) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mGeoLayouts) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mAnimations) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mCollisions) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mLevelScripts) { - Delete(_Node->mData); - Delete(_Node); - } - for (auto& _Node : aGfxData->mMacroObjects) { - Delete(_Node->mData); - Delete(_Node); - } - Delete(aGfxData); - } -} diff --git a/data/dynos_misc.cpp b/data/dynos_misc.cpp index 47853b81..c333ad0c 100644 --- a/data/dynos_misc.cpp +++ b/data/dynos_misc.cpp @@ -352,7 +352,7 @@ void DynOS_Geo_AddActorCustom(const SysPath &aPackFolder, const char *aActorName char* actorName = (char*)calloc(1, sizeof(char) * (actorLen + 1)); strcpy(actorName, aActorName); - GfxData *_GfxData = DynOS_Gfx_LoadFromBinary(aPackFolder, actorName); + GfxData *_GfxData = DynOS_Actor_LoadFromBinary(aPackFolder, actorName); if (!_GfxData) { free(actorName); return;