sm64ex-coop/data/dynos_bin_animation.cpp

258 lines
8.7 KiB
C++

#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 });
}