mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 05:25:14 +00:00
More DynOS refactoring
This commit is contained in:
parent
6ec051c2f9
commit
df3618f521
20 changed files with 1404 additions and 1304 deletions
|
@ -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
232
data/dynos_bin_actor.cpp
Normal 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);
|
||||
}
|
257
data/dynos_bin_animation.cpp
Normal file
257
data/dynos_bin_animation.cpp
Normal 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 });
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
30
data/dynos_bin_legacy.cpp
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
191
data/dynos_bin_pointer.cpp
Normal 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
276
data/dynos_bin_read.cpp
Normal 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());
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 //
|
||||
///////////////////////
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue