More DynOS refactoring

This commit is contained in:
MysterD 2022-04-01 19:50:42 -07:00
parent 6ec051c2f9
commit df3618f521
20 changed files with 1404 additions and 1304 deletions

View file

@ -647,15 +647,10 @@ bool DynOS_Gfx_ImportTexture(void **aOutput, void *aPtr, s32 aTile, void *aGfxRA
Array<ActorGfx> &DynOS_Gfx_GetActorList();
Array<PackData *> &DynOS_Gfx_GetPacks();
Array<bool> &DynOS_Gfx_GetPacksEnabled();
void DynOS_Gfx_GeneratePacks(const char* directory);
Array<String> 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<Collision>* _Node);
DataNode<Collision>* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const char *aCollisionName);
//
// Levels
//
bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array<Pair<u64, String>> _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<Collision>* DynOS_Col_Parse(GfxData* aGfxData, DataNode<Collision>* aNode, bool aDisplayPercent);
void DynOS_Col_Write(FILE* aFile, GfxData* aGfxData, DataNode<Collision> *aNode);
DataNode<Collision>* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const char *aCollisionName);
void DynOS_Col_Generate(const SysPath &aPackFolder, Array<Pair<u64, String>> _ActorsFolders, GfxData *_GfxData);
DataNode<GeoLayout>* DynOS_Geo_Parse(GfxData* aGfxData, DataNode<GeoLayout>* aNode, bool aDisplayPercent);
void DynOS_Geo_Write(FILE *aFile, GfxData *aGfxData, DataNode<GeoLayout> *aNode);
void DynOS_Geo_Load(FILE *aFile, GfxData *aGfxData);
DataNode<Gfx>* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode<Gfx>* aNode);
DataNode<Vtx>* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode<Vtx>* aNode);
DataNode<TexData>* DynOS_Tex_Parse(GfxData* aGfxData, DataNode<TexData>* aNode);
void DynOS_Gfx_Write(FILE *aFile, GfxData *aGfxData, DataNode<Gfx> *aNode);
void DynOS_Gfx_Load(FILE *aFile, GfxData *aGfxData);
DataNode<Lights1>* DynOS_Lights_Parse(GfxData* aGfxData, DataNode<Lights1>* aNode);
DataNode<Collision>* DynOS_Col_Parse(GfxData* aGfxData, DataNode<Collision>* aNode, bool aDisplayPercent);
DataNode<LevelScript>* DynOS_Lvl_Parse(GfxData* aGfxData, DataNode<LevelScript>* aNode, bool aDisplayPercent);
void DynOS_Lights_Write(FILE* aFile, GfxData* aGfxData, DataNode<Lights1> *aNode);
void DynOS_Lights_Load(FILE *aFile, GfxData *aGfxData);
DataNode<MacroObject>* DynOS_MacroObject_Parse(GfxData* aGfxData, DataNode<MacroObject>* aNode, bool aDisplayPercent);
// TODO: DynOS_MacroObject_Write
// TODO: DynOS_MacroObject_Load
DataNode<TexData>* DynOS_Tex_Parse(GfxData* aGfxData, DataNode<TexData>* aNode);
void DynOS_Tex_Write(FILE* aFile, GfxData* aGfxData, DataNode<TexData> *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<Vtx>* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode<Vtx>* aNode);
void DynOS_Vtx_Write(FILE* aFile, GfxData* aGfxData, DataNode<Vtx> *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<LevelScript>* DynOS_Lvl_Parse(GfxData* aGfxData, DataNode<LevelScript>* aNode, bool aDisplayPercent);
// TODO: DynOS_Lvl_Write
// TODO: DynOS_Lvl_Load
void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder);
#endif
#endif

232
data/dynos_bin_actor.cpp Normal file
View file

@ -0,0 +1,232 @@
#include "dynos.cpp.h"
// Free data pointers, but keep nodes and tokens intact
// Delete nodes generated from GfxDynCmds
template <typename T>
void ClearGfxDataNodes(DataNodes<T> &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<Pair<const char *, GfxData *>> mGfxData; };
static Array<DynosGfxDataCache *> 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<GfxData>();
for (bool _Done = false; !_Done;) {
switch (ReadBytes<u8>(_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<DynosGfxDataCache>();
_Pack->mPackFolder = aPackFolder;
_Pack->mGfxData.Add({ aActorName, _GfxData });
sDynosGfxDataCache.Add(_Pack);
}
return _GfxData;
}
//////////////
// Generate //
//////////////
static String GetActorFolder(const Array<Pair<u64, String>> &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<Pair<u64, String>> _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<AnimData> *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<Pair<u64, String>> _ActorsFolders;
GfxData *_GfxData = New<GfxData>();
// 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);
}

View file

@ -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<String> _Data;
Array<String> _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<s16> *_AnimValues = New<AnimBuffer<s16>>();
_AnimValues->first = _DataName;
for (const auto &_Value : _Data) {
_AnimValues->second.Add(_Value.ParseInt());
}
aGfxData->mAnimValues.Add(_AnimValues);
} break;
case DATA_TYPE_ANIMATION_INDEX: {
AnimBuffer<u16> *_AnimIndices = New<AnimBuffer<u16>>();
_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<AnimData> *_Node = New<DataNode<AnimData>>();
_Node->mName = _DataName;
_Node->mData = New<AnimData>();
_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<String> _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<s16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mValues.first; });
if (_ValueBufferIdx == -1) {
continue;
}
// Index buffer
s32 _IndexBufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mIndex.first; });
if (_IndexBufferIdx == -1) {
continue;
}
// Unk0A buffer
s32 _Unk0ABufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mUnk0A.first; });
if (_Unk0ABufferIdx == -1) {
continue;
}
// Header
WriteBytes<u8>(aFile, DATA_TYPE_ANIMATION);
_Node->mName.Write(aFile);
// Data
WriteBytes<s16>(aFile, _Node->mData->mFlags);
WriteBytes<s16>(aFile, _Node->mData->mUnk02);
WriteBytes<s16>(aFile, _Node->mData->mUnk04);
WriteBytes<s16>(aFile, _Node->mData->mUnk06);
WriteBytes<s16>(aFile, _Node->mData->mUnk08);
WriteBytes<s16>(aFile, (aGfxData->mAnimIndices[_Unk0ABufferIdx]->second.Count() / 6) - 1);
WriteBytes<u32>(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<u8>(aFile, DATA_TYPE_ANIMATION_TABLE);
// Data
_AnimName.first.Write(aFile);
}
}
/////////////
// Reading //
/////////////
void DynOS_Anim_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<AnimData> *_Node = New<DataNode<AnimData>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<AnimData>();
_Node->mData->mFlags = ReadBytes<s16>(aFile);
_Node->mData->mUnk02 = ReadBytes<s16>(aFile);
_Node->mData->mUnk04 = ReadBytes<s16>(aFile);
_Node->mData->mUnk06 = ReadBytes<s16>(aFile);
_Node->mData->mUnk08 = ReadBytes<s16>(aFile);
_Node->mData->mUnk0A.second = ReadBytes<s16>(aFile);
_Node->mData->mLength = ReadBytes<u32>(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 });
}

View file

@ -9,7 +9,7 @@ extern "C" {
// Free data pointers, but keep nodes and tokens intact
// Delete nodes generated from GfxDynCmds
template <typename T>
static void ClearColDataNodes(DataNodes<T> &aDataNodes) {
void ClearGfxDataNodes(DataNodes<T> &aDataNodes) {
for (s32 i = aDataNodes.Count(); i != 0; --i) {
Delete(aDataNodes[i - 1]->mData);
}
@ -405,7 +405,7 @@ DataNode<Collision>* DynOS_Col_Parse(GfxData* aGfxData, DataNode<Collision>* aNo
// Writing //
/////////////
static void WriteCollisionData(FILE* aFile, GfxData* aGfxData, DataNode<Collision> *aNode) {
void DynOS_Col_Write(FILE* aFile, GfxData* aGfxData, DataNode<Collision> *aNode) {
if (!aNode->mData) return;
// Name
@ -419,14 +419,14 @@ static void WriteCollisionData(FILE* aFile, GfxData* aGfxData, DataNode<Collisio
}
}
bool DynOS_Col_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData, DataNode<Collision>* _Node) {
static bool DynOS_Col_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData, DataNode<Collision>* _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<Collision>* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const
return collisionNode;
}
//////////////
// Generate //
//////////////
void DynOS_Col_Generate(const SysPath &aPackFolder, Array<Pair<u64, String>> _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);
}
}

View file

@ -359,3 +359,53 @@ DataNode<GeoLayout>* DynOS_Geo_Parse(GfxData* aGfxData, DataNode<GeoLayout>* aNo
}
#pragma GCC diagnostic pop
/////////////
// Writing //
/////////////
void DynOS_Geo_Write(FILE *aFile, GfxData *aGfxData, DataNode<GeoLayout> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_GEO_LAYOUT);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(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<u32>(aFile, *((u32 *) _Head));
}
}
}
/////////////
// Reading //
/////////////
void DynOS_Geo_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<GeoLayout> *_Node = New<DataNode<GeoLayout>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<GeoLayout>(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
u32 _Value = ReadBytes<u32>(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);
}

View file

@ -853,3 +853,57 @@ DataNode<Gfx>* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode<Gfx>* aNode) {
}
#pragma GCC diagnostic pop
/////////////
// Writing //
/////////////
void DynOS_Gfx_Write(FILE *aFile, GfxData *aGfxData, DataNode<Gfx> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_DISPLAY_LIST);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
Gfx *_Head = &aNode->mData[i];
if (aGfxData->mPointerList.Find((void *) _Head) != -1) {
WriteBytes<u32>(aFile, _Head->words.w0);
DynOS_Pointer_Write(aFile, (const void *) _Head->words.w1, aGfxData);
} else {
WriteBytes<u32>(aFile, _Head->words.w0);
WriteBytes<u32>(aFile, _Head->words.w1);
}
}
}
/////////////
// Reading //
/////////////
void DynOS_Gfx_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<Gfx> *_Node = New<DataNode<Gfx>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<Gfx>(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
u32 _WordsW0 = ReadBytes<u32>(aFile);
u32 _WordsW1 = ReadBytes<u32>(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);
}

30
data/dynos_bin_legacy.cpp Normal file
View file

@ -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<u32>(aFile);
ReadBytes<u8>(aFile);
}

View file

@ -34,3 +34,36 @@ DataNode<Lights1>* DynOS_Lights_Parse(GfxData* aGfxData, DataNode<Lights1>* aNod
aNode->mLoadIndex = aGfxData->mLoadIndex++;
return aNode;
}
/////////////
// Writing //
/////////////
void DynOS_Lights_Write(FILE* aFile, GfxData* aGfxData, DataNode<Lights1> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_LIGHT);
aNode->mName.Write(aFile);
// Data
WriteBytes<Lights1>(aFile, *aNode->mData);
}
/////////////
// Reading //
/////////////
void DynOS_Lights_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<Lights1> *_Node = New<DataNode<Lights1>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<Lights1>();
*_Node->mData = ReadBytes<Lights1>(aFile);
// Append
aGfxData->mLights.Add(_Node);
}

View file

@ -1478,7 +1478,7 @@ static DataNode<LevelScript> *GetLevelScript(GfxData *aGfxData, const String& aG
return NULL;
}
bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array<Pair<u64, String>> _ActorsFolders, GfxData *_GfxData) {
static bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array<Pair<u64, String>> _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<Pair<u64,
}
return generated;
}
//////////////
// Generate //
//////////////
void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder) {
Print("---------- Level pack folder: \"%s\" ----------", aPackFolder.c_str());
Array<Pair<u64, String>> _ActorsFolders;
GfxData *_GfxData = New<GfxData>();
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);
}

191
data/dynos_bin_pointer.cpp Normal file
View file

@ -0,0 +1,191 @@
#include "dynos.cpp.h"
/////////////
// Writing //
/////////////
typedef Pair<String, u32> 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<u32>(aFile, 0);
return;
}
// Geo function
s32 _GeoFunctionIndex = DynOS_Geo_GetFunctionIndex(aPtr);
if (_GeoFunctionIndex != -1) {
WriteBytes<u32>(aFile, FUNCTION_CODE);
WriteBytes<s32>(aFile, _GeoFunctionIndex);
return;
}
// Pointer
PointerData _PtrData = GetDataFromPointer(aPtr, aGfxData);
WriteBytes<u32>(aFile, POINTER_CODE);
_PtrData.first.Write(aFile);
WriteBytes<u32>(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<s32>(aFile);
return DynOS_Geo_GetFunctionPointerFromIndex(_GeoFunctionIndex);
}
// PNTR
if (aValue == POINTER_CODE) {
String _PtrName; _PtrName.Read(aFile);
u32 _PtrData = ReadBytes<u32>(aFile);
return GetPointerFromData(aGfxData, _PtrName, _PtrData);
}
// Not a pointer
return NULL;
}

276
data/dynos_bin_read.cpp Normal file
View file

@ -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<char>(_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 <typename T>
static void AppendNewNode(GfxData *aGfxData, DataNodes<T> &aNodes, const String &aName, String *&aDataName, Array<String> *&aDataTokens) {
DataNode<T> *_Node = New<DataNode<T>>();
_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<String> *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<String> *) 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());
}

View file

@ -108,3 +108,50 @@ DataNode<TexData>* DynOS_Tex_Parse(GfxData* aGfxData, DataNode<TexData>* aNode)
aNode->mLoadIndex = aGfxData->mLoadIndex++;
return aNode;
}
/////////////
// Writing //
/////////////
void DynOS_Tex_Write(FILE* aFile, GfxData* aGfxData, DataNode<TexData> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_TEXTURE);
aNode->mName.Write(aFile);
// Data
aNode->mData->mPngData.Write(aFile);
}
/////////////
// Reading //
/////////////
void DynOS_Tex_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<TexData> *_Node = New<DataNode<TexData>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<TexData>();
_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<u8>(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4));
free(_RawData);
} else { // Probably a palette
_Node->mData->mRawData = Array<u8>();
_Node->mData->mRawWidth = 0;
_Node->mData->mRawHeight = 0;
_Node->mData->mRawFormat = 0;
_Node->mData->mRawSize = 0;
}
// Append
aGfxData->mTextures.Add(_Node);
}

View file

@ -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 //
///////////////////////

View file

@ -26,3 +26,60 @@ DataNode<Vtx>* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode<Vtx>* aNode) {
aNode->mLoadIndex = aGfxData->mLoadIndex++;
return aNode;
}
/////////////
// Writing //
/////////////
void DynOS_Vtx_Write(FILE* aFile, GfxData* aGfxData, DataNode<Vtx> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_VERTEX);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[0]);
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[1]);
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[2]);
WriteBytes<s16>(aFile, aNode->mData[i].n.flag);
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[0]);
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[1]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[0]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[1]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[2]);
WriteBytes<u8> (aFile, aNode->mData[i].n.a);
}
}
/////////////
// Reading //
/////////////
void DynOS_Vtx_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<Vtx> *_Node = New<DataNode<Vtx>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<Vtx>(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
_Node->mData[i].n.ob[0] = ReadBytes<s16>(aFile);
_Node->mData[i].n.ob[1] = ReadBytes<s16>(aFile);
_Node->mData[i].n.ob[2] = ReadBytes<s16>(aFile);
_Node->mData[i].n.flag = ReadBytes<s16>(aFile);
_Node->mData[i].n.tc[0] = ReadBytes<s16>(aFile);
_Node->mData[i].n.tc[1] = ReadBytes<s16>(aFile);
_Node->mData[i].n.n[0] = ReadBytes<s8> (aFile);
_Node->mData[i].n.n[1] = ReadBytes<s8> (aFile);
_Node->mData[i].n.n[2] = ReadBytes<s8> (aFile);
_Node->mData[i].n.a = ReadBytes<u8>(aFile);
}
// Append
aGfxData->mVertices.Add(_Node);
}

View file

@ -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);

View file

@ -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<s32>(aFile);
return DynOS_Geo_GetFunctionPointerFromIndex(_GeoFunctionIndex);
}
// PNTR
if (aValue == POINTER_CODE) {
String _PtrName; _PtrName.Read(aFile);
u32 _PtrData = ReadBytes<u32>(aFile);
return GetPointerFromData(aGfxData, _PtrName, _PtrData);
}
// Not a pointer
return NULL;
}
//
// Read binary
//
static void LoadLightData(FILE *aFile, GfxData *aGfxData) {
DataNode<Lights1> *_Node = New<DataNode<Lights1>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<Lights1>();
*_Node->mData = ReadBytes<Lights1>(aFile);
// Append
aGfxData->mLights.Add(_Node);
}
static void LoadTextureData(FILE *aFile, GfxData *aGfxData) {
DataNode<TexData> *_Node = New<DataNode<TexData>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<TexData>();
_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<u8>(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4));
free(_RawData);
} else { // Probably a palette
_Node->mData->mRawData = Array<u8>();
_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<Vtx> *_Node = New<DataNode<Vtx>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<Vtx>(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
_Node->mData[i].n.ob[0] = ReadBytes<s16>(aFile);
_Node->mData[i].n.ob[1] = ReadBytes<s16>(aFile);
_Node->mData[i].n.ob[2] = ReadBytes<s16>(aFile);
_Node->mData[i].n.flag = ReadBytes<s16>(aFile);
_Node->mData[i].n.tc[0] = ReadBytes<s16>(aFile);
_Node->mData[i].n.tc[1] = ReadBytes<s16>(aFile);
_Node->mData[i].n.n[0] = ReadBytes<s8> (aFile);
_Node->mData[i].n.n[1] = ReadBytes<s8> (aFile);
_Node->mData[i].n.n[2] = ReadBytes<s8> (aFile);
_Node->mData[i].n.a = ReadBytes<u8>(aFile);
}
// Append
aGfxData->mVertices.Add(_Node);
}
static void LoadDisplayListData(FILE *aFile, GfxData *aGfxData) {
DataNode<Gfx> *_Node = New<DataNode<Gfx>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<Gfx>(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
u32 _WordsW0 = ReadBytes<u32>(aFile);
u32 _WordsW1 = ReadBytes<u32>(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<GeoLayout> *_Node = New<DataNode<GeoLayout>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<GeoLayout>(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
u32 _Value = ReadBytes<u32>(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<u32>(aFile);
ReadBytes<u8>(aFile);
}
static void LoadAnimationData(FILE *aFile, GfxData *aGfxData) {
DataNode<AnimData> *_Node = New<DataNode<AnimData>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<AnimData>();
_Node->mData->mFlags = ReadBytes<s16>(aFile);
_Node->mData->mUnk02 = ReadBytes<s16>(aFile);
_Node->mData->mUnk04 = ReadBytes<s16>(aFile);
_Node->mData->mUnk06 = ReadBytes<s16>(aFile);
_Node->mData->mUnk08 = ReadBytes<s16>(aFile);
_Node->mData->mUnk0A.second = ReadBytes<s16>(aFile);
_Node->mData->mLength = ReadBytes<u32>(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<Pair<const char *, GfxData *>> mGfxData; };
static Array<DynosGfxDataCache *> 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<GfxData>();
for (bool _Done = false; !_Done;) {
switch (ReadBytes<u8>(_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<DynosGfxDataCache>();
_Pack->mPackFolder = aPackFolder;
_Pack->mGfxData.Add({ aActorName, _GfxData });
sDynosGfxDataCache.Add(_Pack);
}
return _GfxData;
}

View file

@ -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<char>(_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 <typename T>
static void AppendNewNode(GfxData *aGfxData, DataNodes<T> &aNodes, const String &aName, String *&aDataName, Array<String> *&aDataTokens) {
DataNode<T> *_Node = New<DataNode<T>>();
_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<String> *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<String> *) 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<String> _Data;
Array<String> _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<s16> *_AnimValues = New<AnimBuffer<s16>>();
_AnimValues->first = _DataName;
for (const auto &_Value : _Data) {
_AnimValues->second.Add(_Value.ParseInt());
}
aGfxData->mAnimValues.Add(_AnimValues);
} break;
case DATA_TYPE_ANIMATION_INDEX: {
AnimBuffer<u16> *_AnimIndices = New<AnimBuffer<u16>>();
_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<AnimData> *_Node = New<DataNode<AnimData>>();
_Node->mName = _DataName;
_Node->mData = New<AnimData>();
_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<String> _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 <typename T>
static void ClearGfxDataNodes(DataNodes<T> &aDataNodes) {
for (s32 i = aDataNodes.Count(); i != 0; --i) {
Delete(aDataNodes[i - 1]->mData);
}
}
static String GetActorFolder(const Array<Pair<u64, String>> &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<Pair<u64, String>> _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<Pair<u64, String>> _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<AnimData> *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<Pair<u64, String>> _ActorsFolders;
GfxData *_GfxData = New<GfxData>();
// 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<Pair<u64, String>> _ActorsFolders;
GfxData *_GfxData = New<GfxData>();
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);
}

View file

@ -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;

View file

@ -1,330 +0,0 @@
#include "dynos.cpp.h"
//
// Pointers
//
typedef Pair<String, u32> 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<u32>(aFile, 0);
return;
}
// Geo function
s32 _GeoFunctionIndex = DynOS_Geo_GetFunctionIndex(aPtr);
if (_GeoFunctionIndex != -1) {
WriteBytes<u32>(aFile, FUNCTION_CODE);
WriteBytes<s32>(aFile, _GeoFunctionIndex);
return;
}
// Pointer
PointerData _PtrData = GetDataFromPointer(aPtr, aGfxData);
WriteBytes<u32>(aFile, POINTER_CODE);
_PtrData.first.Write(aFile);
WriteBytes<u32>(aFile, _PtrData.second);
}
//
// Lights
//
static void WriteLightData(FILE* aFile, GfxData* aGfxData, DataNode<Lights1> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_LIGHT);
aNode->mName.Write(aFile);
// Data
WriteBytes<Lights1>(aFile, *aNode->mData);
}
//
// Textures
//
static void WriteTextureData(FILE* aFile, GfxData* aGfxData, DataNode<TexData> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_TEXTURE);
aNode->mName.Write(aFile);
// Data
aNode->mData->mPngData.Write(aFile);
}
//
// Vertices
//
static void WriteVertexData(FILE* aFile, GfxData* aGfxData, DataNode<Vtx> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_VERTEX);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[0]);
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[1]);
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[2]);
WriteBytes<s16>(aFile, aNode->mData[i].n.flag);
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[0]);
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[1]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[0]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[1]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[2]);
WriteBytes<u8> (aFile, aNode->mData[i].n.a);
}
}
//
// Display lists
//
static void WriteDisplayListData(FILE *aFile, GfxData *aGfxData, DataNode<Gfx> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_DISPLAY_LIST);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
Gfx *_Head = &aNode->mData[i];
if (aGfxData->mPointerList.Find((void *) _Head) != -1) {
WriteBytes<u32>(aFile, _Head->words.w0);
WritePointer(aFile, (const void *) _Head->words.w1, aGfxData);
} else {
WriteBytes<u32>(aFile, _Head->words.w0);
WriteBytes<u32>(aFile, _Head->words.w1);
}
}
}
//
// Geo layouts
//
static void WriteGeoLayoutData(FILE *aFile, GfxData *aGfxData, DataNode<GeoLayout> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_GEO_LAYOUT);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(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<u32>(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<s16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mValues.first; });
if (_ValueBufferIdx == -1) {
continue;
}
// Index buffer
s32 _IndexBufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mIndex.first; });
if (_IndexBufferIdx == -1) {
continue;
}
// Unk0A buffer
s32 _Unk0ABufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mUnk0A.first; });
if (_Unk0ABufferIdx == -1) {
continue;
}
// Header
WriteBytes<u8>(aFile, DATA_TYPE_ANIMATION);
_Node->mName.Write(aFile);
// Data
WriteBytes<s16>(aFile, _Node->mData->mFlags);
WriteBytes<s16>(aFile, _Node->mData->mUnk02);
WriteBytes<s16>(aFile, _Node->mData->mUnk04);
WriteBytes<s16>(aFile, _Node->mData->mUnk06);
WriteBytes<s16>(aFile, _Node->mData->mUnk08);
WriteBytes<s16>(aFile, (aGfxData->mAnimIndices[_Unk0ABufferIdx]->second.Count() / 6) - 1);
WriteBytes<u32>(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<u8>(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);
}
}

View file

@ -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;