diff --git a/tools/ZAPD/.github/workflows/main.yml b/tools/ZAPD/.github/workflows/main.yml new file mode 100644 index 0000000000..31a0f635a0 --- /dev/null +++ b/tools/ZAPD/.github/workflows/main.yml @@ -0,0 +1,83 @@ +name: Build ZAPD + +on: + push: + pull_request: + branches: + - master + +jobs: + build: + runs-on: self-hosted-runner + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Build ZAPD + run: make -j WERROR=1 + + - name: Checkout Repos + run: echo "Checkout Repos" + + - name: Checkout oot + run: | + git clone https://github.com/zeldaret/oot.git + cd oot + git submodule update --init --recursive + + - name: Checkout mm + run: | + git clone https://github.com/zeldaret/mm.git + cd mm + + - name: Set up repos + run: echo "Set up repos" + + - name: Setup OOT + run: | + cd oot + mkdir -p baseroms/gc-eu-mq-dbg/segments + cp ~/baserom_original.z64 ./baseroms/gc-eu-mq-dbg/baserom.z64 + make venv + make -C tools -j + cp ../ZAPD.out tools/ZAPD/ + .venv/bin/python3 tools/decompress_baserom.py gc-eu-mq-dbg + .venv/bin/python3 tools/extract_baserom.py baseroms/gc-eu-mq-dbg/baserom-decompressed.z64 -o baseroms/gc-eu-mq-dbg/segments --dmadata-start 0x12f70 --dmadata-names baseroms/gc-eu-mq-dbg/dmadata_names.txt + .venv/bin/python3 extract_assets.py -j 4 + .venv/bin/python3 tools/msgdis.py --text-out assets/text/message_data.h --staff-text-out assets/text/message_data_staff.h + + - name: Setup MM + run: | + cd mm + python3 -m venv .mm-env + source .mm-env/bin/activate + python3 -m pip install -r requirements.txt + cp ~/baserom.mm.us.rev1.z64 ./baserom.mm.us.rev1.z64 + make -C tools -j + cp ../ZAPD.out tools/ZAPD/ + python3 tools/fixbaserom.py + python3 tools/extract_baserom.py + python3 tools/decompress_yars.py + python3 extract_assets.py -j $(nproc) + + - name: Build Repos + run: echo "Build Repos" + + - name: Build oot + run: | + cd oot + make venv + make -j + + - name: Build mm + run: | + cd mm + python3 -m venv .mm-env + source .mm-env/bin/activate + python3 -m pip install -r requirements.txt + make -j disasm + make -j + + - name: Clean workspace + run: git clean -fdX diff --git a/tools/ZAPD/.gitrepo b/tools/ZAPD/.gitrepo index 9010e72f76..994cf48d74 100644 --- a/tools/ZAPD/.gitrepo +++ b/tools/ZAPD/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/zeldaret/ZAPD.git branch = master - commit = 2b6f459b9523603168b6869cf03057a0d68d5f89 - parent = 2ab90bc51788c6baac0a94c3acb256be5f39ca12 + commit = b3bfa14cf432115a0a675d243f3a1b3197f17cbd + parent = 59017f201eae4a1bc9212ea2c7dc51d4a036108b method = merge cmdver = 0.4.6 diff --git a/tools/ZAPD/README.md b/tools/ZAPD/README.md index 76dfbd1e95..d51dd05583 100644 --- a/tools/ZAPD/README.md +++ b/tools/ZAPD/README.md @@ -117,6 +117,11 @@ ZAPD also accepts the following list of extra parameters: - `-us` / `--unaccounted-static` : Mark unaccounted data as `static` - `-s` / `--static` : Mark every asset as `static`. - This behaviour can be overridden per asset using `Static=` in the respective XML node. +- `--cs-float` : How cutscene floats should be extracted. +- Valid values: + - `hex` + - `float` + - `both` - `-W...`: warning flags, see below Additionally, you can pass the flag `--version` to see the current ZAPD version. If that flag is passed, ZAPD will ignore any other parameter passed. diff --git a/tools/ZAPD/ZAPD/GameConfig.cpp b/tools/ZAPD/ZAPD/GameConfig.cpp index 7990a60863..2140464ec6 100644 --- a/tools/ZAPD/ZAPD/GameConfig.cpp +++ b/tools/ZAPD/ZAPD/GameConfig.cpp @@ -167,7 +167,7 @@ void GameConfig::ConfigFunc_ExternalFile(const tinyxml2::XMLElement& element) void GameConfig::ConfigFunc_EnumData(const tinyxml2::XMLElement& element) { - std::string path = Path::GetDirectoryName(configFilePath); + std::string path = Path::GetDirectoryName(configFilePath).string(); path = path.append("/").append(element.Attribute("File")); tinyxml2::XMLDocument doc; tinyxml2::XMLError eResult = doc.LoadFile(path.c_str()); @@ -247,6 +247,12 @@ void GameConfig::ConfigFunc_EnumData(const tinyxml2::XMLElement& element) else if (enumKey == "endSfx") enumData.endSfx[itemIndex] = itemID; + + else if (enumKey == "csSplineInterpType") + enumData.interpType[itemIndex] = itemID; + + else if (enumKey == "csSplineRelTo") + enumData.relTo[itemIndex] = itemID; } } } diff --git a/tools/ZAPD/ZAPD/GameConfig.h b/tools/ZAPD/ZAPD/GameConfig.h index 838d2da6d0..4f3b91f8c7 100644 --- a/tools/ZAPD/ZAPD/GameConfig.h +++ b/tools/ZAPD/ZAPD/GameConfig.h @@ -48,6 +48,8 @@ public: std::map rumbleType; std::map spawnFlag; std::map endSfx; + std::map interpType; + std::map relTo; }; class ZFile; diff --git a/tools/ZAPD/ZAPD/Globals.h b/tools/ZAPD/ZAPD/Globals.h index 0bfcaeec72..14bd065841 100644 --- a/tools/ZAPD/ZAPD/Globals.h +++ b/tools/ZAPD/ZAPD/Globals.h @@ -16,6 +16,13 @@ enum class VerbosityLevel VERBOSITY_DEBUG }; +enum class CsFloatType +{ + HexOnly, + FloatOnly, + HexAndFloat, +}; + class Globals { public: @@ -31,6 +38,7 @@ public: ZFileMode fileMode; fs::path baseRomPath, inputPath, outputPath, sourceOutputPath, cfgPath; TextureType texType; + CsFloatType floatType = CsFloatType::FloatOnly; ZGame game; GameConfig cfg; bool verboseUnaccounted = false; diff --git a/tools/ZAPD/ZAPD/Main.cpp b/tools/ZAPD/ZAPD/Main.cpp index 40a38bc601..eb1737d643 100644 --- a/tools/ZAPD/ZAPD/Main.cpp +++ b/tools/ZAPD/ZAPD/Main.cpp @@ -36,6 +36,7 @@ void Arg_SetExporter(int& i, char* argv[]); void Arg_EnableGCCCompat(int& i, char* argv[]); void Arg_ForceStatic(int& i, char* argv[]); void Arg_ForceUnaccountedStatic(int& i, char* argv[]); +void Arg_CsFloatMode(int& i, char* argv[]); int main(int argc, char* argv[]); @@ -252,6 +253,7 @@ void ParseArgs(int& argc, char* argv[]) {"--static", &Arg_ForceStatic}, {"-us", &Arg_ForceUnaccountedStatic}, {"--unaccounted-static", &Arg_ForceUnaccountedStatic}, + {"--cs-float", &Arg_CsFloatMode}, }; for (int32_t i = 2; i < argc; i++) @@ -392,6 +394,32 @@ void Arg_ForceUnaccountedStatic([[maybe_unused]] int& i, [[maybe_unused]] char* Globals::Instance->forceUnaccountedStatic = true; } +void Arg_CsFloatMode([[maybe_unused]] int& i, [[maybe_unused]] char* argv[]) +{ + i++; + if (std::strcmp(argv[i], "hex") == 0) + { + Globals::Instance->floatType = CsFloatType::HexOnly; + } + else if (std::strcmp(argv[i], "float") == 0) + { + Globals::Instance->floatType = CsFloatType::FloatOnly; + } + else if (std::strcmp(argv[i], "both") == 0) + { + Globals::Instance->floatType = CsFloatType::HexAndFloat; + } + else + { + Globals::Instance->floatType = CsFloatType::FloatOnly; + HANDLE_WARNING( + WarningType::Always, "Invalid CS Float Type", + StringHelper::Sprintf("Invalid CS float type entered. Expected \"hex\", \"float\", or " + "\"both\". Got %s.\n Defaulting to \"float\".", + argv[i])); + } +} + int HandleExtract(ZFileMode fileMode, ExporterSet* exporterSet) { bool procFileModeSuccess = false; diff --git a/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.cpp b/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.cpp index f18e313085..960404e598 100644 --- a/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.cpp +++ b/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.cpp @@ -4,6 +4,9 @@ #include "Globals.h" #include "Utils/BitConverter.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" + +#include "ZCutscene.h" /**** GENERIC ****/ @@ -126,42 +129,163 @@ std::string CutsceneMMCommand_GenericCmd::GetCommandMacro() const /**** CAMERA ****/ -CutsceneSubCommandEntry_Camera::CutsceneSubCommandEntry_Camera(const std::vector& rawData, - offset_t rawDataIndex) +CutsceneSubCommandEntry_SplineCamPoint::CutsceneSubCommandEntry_SplineCamPoint( + const std::vector& rawData, offset_t rawDataIndex) : CutsceneSubCommandEntry(rawData, rawDataIndex) { + interpType = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0); + weight = BitConverter::ToUInt8BE(rawData, rawDataIndex + 1); + duration = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2); + posX = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4); + posY = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6); + posZ = BitConverter::ToUInt16BE(rawData, rawDataIndex + 8); + relTo = BitConverter::ToUInt16BE(rawData, rawDataIndex + 10); } -std::string CutsceneSubCommandEntry_Camera::GetBodySourceCode() const +std::string CutsceneSubCommandEntry_SplineCamPoint::GetBodySourceCode() const { - return StringHelper::Sprintf("CMD_HH(0x%04X, 0x%04X)", base, startFrame); + const auto interpTypeMap = &Globals::Instance->cfg.enumData.interpType; + const auto relToMap = &Globals::Instance->cfg.enumData.relTo; + + return StringHelper::Sprintf("CS_CAM_POINT(%s, 0x%02X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, %s)", + interpTypeMap->at(interpType).c_str(), weight, duration, posX, + posY, posZ, relToMap->at(relTo).c_str()); } -size_t CutsceneSubCommandEntry_Camera::GetRawSize() const +size_t CutsceneSubCommandEntry_SplineCamPoint::GetRawSize() const +{ + return 0x0C; +} + +CutsceneSubCommandEntry_SplineMiscPoint::CutsceneSubCommandEntry_SplineMiscPoint( + const std::vector& rawData, offset_t rawDataIndex) + : CutsceneSubCommandEntry(rawData, rawDataIndex) +{ + unused0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0); + roll = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2); + fov = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4); + unused1 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6); +} + +std::string CutsceneSubCommandEntry_SplineMiscPoint::GetBodySourceCode() const +{ + return StringHelper::Sprintf("CS_CAM_MISC(0x%04X, 0x%04X, 0x%04X, 0x%04X)", unused0, roll, fov, + unused1); +} + +size_t CutsceneSubCommandEntry_SplineMiscPoint::GetRawSize() const +{ + return 0x08; +} + +CutsceneSubCommandEntry_SplineHeader::CutsceneSubCommandEntry_SplineHeader( + const std::vector& rawData, offset_t rawDataIndex) + : CutsceneSubCommandEntry(rawData, rawDataIndex) +{ + numEntries = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0); + unused0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2); + unused1 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4); + duration = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6); +} + +std::string CutsceneSubCommandEntry_SplineHeader::GetBodySourceCode() const +{ + return StringHelper::Sprintf("CS_CAM_SPLINE(0x%04X, 0x%04X, 0x%04X, 0x%04X)", numEntries, + unused0, unused1, duration); +} + +size_t CutsceneSubCommandEntry_SplineHeader::GetRawSize() const +{ + return 0x08; +} + +CutsceneSubCommandEntry_SplineFooter::CutsceneSubCommandEntry_SplineFooter( + const std::vector& rawData, offset_t rawDataIndex) + : CutsceneSubCommandEntry(rawData, rawDataIndex) +{ + uint16_t firstHalfWord = BitConverter::ToUInt16BE(rawData, rawDataIndex); + uint16_t secondHalfWord = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2); + + if (firstHalfWord != 0xFFFF || secondHalfWord != 4) + { + HANDLE_ERROR(WarningType::InvalidExtractedData, "Invalid Spline Footer", + StringHelper::Sprintf( + "Invalid Spline footer. Was expecting 0xFFFF, 0x0004. Got 0x%04X, 0x%04X", + firstHalfWord, secondHalfWord)); + } +} + +std::string CutsceneSubCommandEntry_SplineFooter::GetBodySourceCode() const +{ + return "CS_CAM_END()"; +} + +size_t CutsceneSubCommandEntry_SplineFooter::GetRawSize() const { return 0x04; } -CutsceneMMCommand_Camera::CutsceneMMCommand_Camera(const std::vector& rawData, +CutsceneMMCommand_Spline::CutsceneMMCommand_Spline(const std::vector& rawData, offset_t rawDataIndex) : CutsceneCommand(rawData, rawDataIndex) { + numHeaders = 0; + totalCommands = 0; rawDataIndex += 4; - entries.reserve(numEntries); - for (size_t i = 0; i < numEntries / 4; i++) + while (1) { - auto* entry = new CutsceneSubCommandEntry_Camera(rawData, rawDataIndex); - entries.push_back(entry); - rawDataIndex += entry->GetRawSize(); + if (BitConverter::ToUInt16BE(rawData, rawDataIndex) == 0xFFFF) + { + break; + } + numHeaders++; + + auto* header = new CutsceneSubCommandEntry_SplineHeader(rawData, rawDataIndex); + rawDataIndex += header->GetRawSize(); + entries.push_back(header); + + totalCommands += header->numEntries; + + for (uint32_t i = 0; i < header->numEntries; i++) + { + auto* entry = new CutsceneSubCommandEntry_SplineCamPoint(rawData, rawDataIndex); + entries.push_back(entry); + rawDataIndex += entry->GetRawSize(); + } + + for (uint32_t i = 0; i < header->numEntries; i++) + { + auto* entry = new CutsceneSubCommandEntry_SplineCamPoint(rawData, rawDataIndex); + entries.push_back(entry); + rawDataIndex += entry->GetRawSize(); + } + + for (uint32_t i = 0; i < header->numEntries; i++) + { + auto* entry = new CutsceneSubCommandEntry_SplineMiscPoint(rawData, rawDataIndex); + entries.push_back(entry); + rawDataIndex += entry->GetRawSize(); + } } + + auto* footer = new CutsceneSubCommandEntry_SplineFooter(rawData, rawDataIndex); + entries.push_back(footer); + rawDataIndex += footer->GetRawSize(); } -std::string CutsceneMMCommand_Camera::GetCommandMacro() const +std::string CutsceneMMCommand_Spline::GetCommandMacro() const { return StringHelper::Sprintf("CS_CAM_SPLINE_LIST(%i)", numEntries); } +size_t CutsceneMMCommand_Spline::GetCommandSize() const +{ + // 8 Bytes once for the spline command, 8 Bytes per spline the header, two groups of size 12, 1 + // group of size 8, 4 bytes for the footer. + return 8 + (8 * numHeaders) + ((totalCommands * 2) * 0xC) + (totalCommands * 8) + 4; +} + /**** TRANSITION GENERAL ****/ CutsceneSubCommandEntry_TransitionGeneral::CutsceneSubCommandEntry_TransitionGeneral( @@ -434,22 +558,29 @@ CutsceneMMSubCommandEntry_ActorCue::CutsceneMMSubCommandEntry_ActorCue( std::string CutsceneMMSubCommandEntry_ActorCue::GetBodySourceCode() const { EnumData* enumData = &Globals::Instance->cfg.enumData; + std::string normalXStr = + ZCutscene::GetCsEncodedFloat(normalX, Globals::Instance->floatType, true); + std::string normalYStr = + ZCutscene::GetCsEncodedFloat(normalY, Globals::Instance->floatType, true); + std::string normalZStr = + ZCutscene::GetCsEncodedFloat(normalZ, Globals::Instance->floatType, true); if (static_cast(commandID) == CutsceneMM_CommandType::CS_CMD_PLAYER_CUE) { return StringHelper::Sprintf("CS_PLAYER_CUE(%s, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, " - "%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)", + "%i, %i, %i, %i, %s, %s, %s)", enumData->playerCueId[base].c_str(), startFrame, endFrame, rotX, rotY, rotZ, startPosX, startPosY, startPosZ, endPosX, - endPosY, endPosZ, normalX, normalY, normalZ); + endPosY, endPosZ, normalXStr.c_str(), normalYStr.c_str(), + normalZStr.c_str()); } else { return StringHelper::Sprintf("CS_ACTOR_CUE(%i, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, " - "%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)", + "%i, %i, %i, %i, %s, %s, %s)", base, startFrame, endFrame, rotX, rotY, rotZ, startPosX, - startPosY, startPosZ, endPosX, endPosY, endPosZ, normalX, - normalY, normalZ); + startPosY, startPosZ, endPosX, endPosY, endPosZ, + normalXStr.c_str(), normalYStr.c_str(), normalZStr.c_str()); } } diff --git a/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.h b/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.h index fb2f772752..597f6788bc 100644 --- a/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.h +++ b/tools/ZAPD/ZAPD/OtherStructs/CutsceneMM_Commands.h @@ -268,24 +268,79 @@ public: // TODO: MM cutscene camera command is implemented as a placeholder until we better understand how // it works -class CutsceneSubCommandEntry_Camera : public CutsceneSubCommandEntry + +class CutsceneSubCommandEntry_SplineCamPoint : public CutsceneSubCommandEntry { public: - uint32_t unk_08; + uint8_t interpType; + uint8_t weight; + uint16_t duration; - CutsceneSubCommandEntry_Camera(const std::vector& rawData, offset_t rawDataIndex); + uint16_t posX; + uint16_t posY; + + uint16_t posZ; + uint16_t relTo; + + CutsceneSubCommandEntry_SplineCamPoint(const std::vector& rawData, + offset_t rawDataIndex); std::string GetBodySourceCode() const override; size_t GetRawSize() const override; }; -class CutsceneMMCommand_Camera : public CutsceneCommand +class CutsceneSubCommandEntry_SplineMiscPoint : public CutsceneSubCommandEntry { public: - CutsceneMMCommand_Camera(const std::vector& rawData, offset_t rawDataIndex); + uint16_t unused0; + uint16_t roll; + uint16_t fov; + uint16_t unused1; + + CutsceneSubCommandEntry_SplineMiscPoint(const std::vector& rawData, + offset_t rawDataIndex); + + std::string GetBodySourceCode() const override; + + size_t GetRawSize() const override; +}; + +class CutsceneSubCommandEntry_SplineFooter : public CutsceneSubCommandEntry +{ +public: + CutsceneSubCommandEntry_SplineFooter(const std::vector& rawData, + offset_t rawDataIndex); + + std::string GetBodySourceCode() const override; + + size_t GetRawSize() const override; +}; + +class CutsceneSubCommandEntry_SplineHeader : public CutsceneSubCommandEntry +{ +public: + uint16_t numEntries; + uint16_t unused0; + uint16_t unused1; + uint16_t duration; + CutsceneSubCommandEntry_SplineHeader(const std::vector& rawData, + offset_t rawDataIndex); + + std::string GetBodySourceCode() const override; + + size_t GetRawSize() const override; +}; + +class CutsceneMMCommand_Spline : public CutsceneCommand +{ +public: + uint32_t numHeaders; + uint32_t totalCommands; + CutsceneMMCommand_Spline(const std::vector& rawData, offset_t rawDataIndex); std::string GetCommandMacro() const override; + size_t GetCommandSize() const override; }; /**** TRANSITION GENERAL ****/ diff --git a/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp b/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp index 8c530f796e..f9a5c4f2d5 100644 --- a/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp +++ b/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp @@ -6,6 +6,8 @@ #include "Utils/BitConverter.h" #include "Utils/StringHelper.h" +#include "ZCutscene.h" + /**** GENERIC ****/ // Specific for command lists where each entry has size 0x30 bytes @@ -139,9 +141,11 @@ std::string CutsceneOoTCommand_CameraPoint::GetBodySourceCode() const if (continueFlag != 0) continueMacro = "CS_CAM_STOP"; - return StringHelper::Sprintf("CS_CAM_POINT(%s, 0x%02X, %i, %ff, %i, %i, %i, 0x%04X)", - continueMacro.c_str(), cameraRoll, nextPointFrame, viewAngle, posX, - posY, posZ, unused); + return StringHelper::Sprintf( + "CS_CAM_POINT(%s, 0x%02X, %i, %s, %i, %i, %i, 0x%04X)", continueMacro.c_str(), cameraRoll, + nextPointFrame, + ZCutscene::GetCsEncodedFloat(viewAngle, Globals::Instance->floatType, false).c_str(), posX, + posY, posZ, unused); } size_t CutsceneOoTCommand_CameraPoint::GetRawSize() const @@ -334,27 +338,34 @@ CutsceneOoTSubCommandEntry_ActorCue::CutsceneOoTSubCommandEntry_ActorCue( normalY = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x28); normalZ = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x2C); } - std::string CutsceneOoTSubCommandEntry_ActorCue::GetBodySourceCode() const { EnumData* enumData = &Globals::Instance->cfg.enumData; + std::string normalXStr = + ZCutscene::GetCsEncodedFloat(normalX, Globals::Instance->floatType, true); + std::string normalYStr = + ZCutscene::GetCsEncodedFloat(normalY, Globals::Instance->floatType, true); + std::string normalZStr = + ZCutscene::GetCsEncodedFloat(normalZ, Globals::Instance->floatType, true); + if (static_cast(commandID) == CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE) { return StringHelper::Sprintf("CS_PLAYER_CUE(%s, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, " - "%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)", + "%i, %i, %i, %i, %s, %s, %s)", enumData->playerCueId[base].c_str(), startFrame, endFrame, rotX, rotY, rotZ, startPosX, startPosY, startPosZ, endPosX, - endPosY, endPosZ, normalX, normalY, normalZ); + endPosY, endPosZ, normalXStr.c_str(), normalYStr.c_str(), + normalZStr.c_str()); } else { return StringHelper::Sprintf("CS_ACTOR_CUE(%i, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, " - "%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)", + "%i, %i, %i, %i, %s, %s, %s)", base, startFrame, endFrame, rotX, rotY, rotZ, startPosX, - startPosY, startPosZ, endPosX, endPosY, endPosZ, normalX, - normalY, normalZ); + startPosY, startPosZ, endPosX, endPosY, endPosZ, + normalXStr.c_str(), normalYStr.c_str(), normalZStr.c_str()); } } diff --git a/tools/ZAPD/ZAPD/ZAPD.vcxproj b/tools/ZAPD/ZAPD/ZAPD.vcxproj index 77d0bd16eb..26a0b70363 100644 --- a/tools/ZAPD/ZAPD/ZAPD.vcxproj +++ b/tools/ZAPD/ZAPD/ZAPD.vcxproj @@ -45,6 +45,7 @@ true v142 MultiByte + false Application @@ -52,6 +53,7 @@ v142 true MultiByte + false @@ -186,21 +188,24 @@ mkdir build\ZAPD - + + + + - + @@ -278,7 +283,8 @@ mkdir build\ZAPD - + + @@ -287,6 +293,8 @@ mkdir build\ZAPD + + @@ -296,9 +304,9 @@ mkdir build\ZAPD - + diff --git a/tools/ZAPD/ZAPD/ZAPD.vcxproj.filters b/tools/ZAPD/ZAPD/ZAPD.vcxproj.filters index eac471961c..51723306b4 100644 --- a/tools/ZAPD/ZAPD/ZAPD.vcxproj.filters +++ b/tools/ZAPD/ZAPD/ZAPD.vcxproj.filters @@ -228,9 +228,6 @@ Source Files\Z64\ZRoom\Commands - - Source Files\Z64\ZRoom\Commands - Source Files\Z64\ZRoom\Commands @@ -279,9 +276,6 @@ Source Files\Z64 - - Source Files\Z64 - Source Files\Z64 @@ -297,6 +291,21 @@ Source Files\Z64 + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64 + + + Source Files\Z64 + @@ -497,9 +506,6 @@ Header Files\Z64\ZRoom\Commands - - Header Files\Z64\ZRoom\Commands - Header Files\Z64\ZRoom\Commands @@ -548,9 +554,6 @@ Header Files\Z64 - - Header Files\Z64 - Header Files\Z64 @@ -569,6 +572,21 @@ Header Files + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64 + + + Header Files\Z64 + diff --git a/tools/ZAPD/ZAPD/ZCKeyFrame.cpp b/tools/ZAPD/ZAPD/ZCKeyFrame.cpp new file mode 100644 index 0000000000..387f8ad2f2 --- /dev/null +++ b/tools/ZAPD/ZAPD/ZCKeyFrame.cpp @@ -0,0 +1,302 @@ +#include "ZCKeyFrame.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" + +REGISTER_ZFILENODE(KeyFrameSkel, ZKeyFrameSkel); +REGISTER_ZFILENODE(KeyFrameLimbList, ZKeyFrameLimbList); + +ZKeyFrameSkel::ZKeyFrameSkel(ZFile* nParent) : ZResource(nParent) +{ + RegisterRequiredAttribute("LimbType"); +} + +ZKeyFrameSkel::~ZKeyFrameSkel() +{ +} + +ZKeyFrameLimb::ZKeyFrameLimb(ZFile* nParent) : ZResource(nParent) +{ +} + +ZKeyFrameStandardLimb::ZKeyFrameStandardLimb(ZFile* nParent) : ZKeyFrameLimb(nParent) +{ +} + +ZKeyFrameFlexLimb::ZKeyFrameFlexLimb(ZFile* nParent) : ZKeyFrameLimb(nParent) +{ +} + +ZKeyFrameLimbList::ZKeyFrameLimbList(ZFile* nParent) : ZResource(nParent) +{ + RegisterRequiredAttribute("LimbType"); + RegisterRequiredAttribute("LimbCount"); +} + +ZKeyFrameLimbList::ZKeyFrameLimbList(ZFile* nParent, uint32_t limbCount, ZKeyframeSkelType type) + : ZResource(nParent) +{ + numLimbs = limbCount; + limbType = type; +} + +ZKeyFrameLimbList::~ZKeyFrameLimbList() +{ + for (const auto l : limbs) + delete l; +} + +void ZKeyFrameSkel::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + std::string limbTypeStr = registeredAttributes.at("LimbType").value; + + limbType = ZKeyFrameLimbList::ParseLimbTypeStr(limbTypeStr); + if (limbType == ZKeyframeSkelType::Error) + HANDLE_ERROR_RESOURCE( + WarningType::InvalidXML, parent, this, rawDataIndex, "Invalid limb type", + StringHelper::Sprintf("Invalid limb type. Was expecting 'Flex' or 'Normal'. Got %s.", + limbTypeStr.c_str())); +} +void ZKeyFrameLimbList::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + std::string limbTypeStr = registeredAttributes.at("LimbType").value; + std::string numLimbStr = registeredAttributes.at("LimbCount").value; + + limbType = ParseLimbTypeStr(limbTypeStr); + + if (limbType == ZKeyframeSkelType::Error) + HANDLE_ERROR_RESOURCE( + WarningType::InvalidXML, parent, this, rawDataIndex, "Invalid limb type", + StringHelper::Sprintf("Invalid limb type. Was expecting 'Flex' or 'Normal'. Got %s.", + limbTypeStr.c_str())); + + numLimbs = (uint8_t)StringHelper::StrToL(numLimbStr); +} + +void ZKeyFrameSkel::ParseRawData() +{ + ZResource::ParseRawData(); + + const auto& rawData = parent->GetRawData(); + limbCount = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0); + dListCount = BitConverter::ToUInt8BE(rawData, rawDataIndex + 1); + limbsPtr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4); + + limbList = std::make_unique(parent, limbCount, limbType); + limbList->SetRawDataIndex(GETSEGOFFSET(limbsPtr)); + limbList->ParseRawData(); +} + +void ZKeyFrameSkel::DeclareReferences(const std::string& prefix) +{ + std::string defaultPrefix = name; + std::string declaration; + + if (defaultPrefix == "") + defaultPrefix = prefix; + + ZResource::DeclareReferences(defaultPrefix); + declaration += limbList->GetBodySourceCode(); + parent->AddDeclarationArray( + GETSEGOFFSET(limbsPtr), DeclarationAlignment::Align4, limbList->GetRawDataSize(), + limbList->GetSourceTypeName(), + StringHelper::Sprintf("%s_KeyFrameLimbs_%06X", prefix.c_str(), rawDataIndex), + limbList->limbs.size(), declaration); +} + +std::string ZKeyFrameSkel::GetBodySourceCode() const +{ + std::string limbStr; + + if (limbType == ZKeyframeSkelType::Normal) + Globals::Instance->GetSegmentedPtrName(limbsPtr, parent, "KeyFrameStandardLimb", limbStr); + else + Globals::Instance->GetSegmentedPtrName(limbsPtr, parent, "KeyFrameFlexLimb", limbStr); + + return StringHelper::Sprintf("\n\t0x%02X, 0x%02X, %s\n", limbCount, dListCount, + limbStr.c_str()); +} + +size_t ZKeyFrameSkel::GetRawDataSize() const +{ + return 0x8; +} + +std::string ZKeyFrameSkel::GetSourceTypeName() const +{ + return "KeyFrameSkeleton"; +} + +ZResourceType ZKeyFrameSkel::GetResourceType() const +{ + return ZResourceType::KeyFrameSkel; +} + +size_t ZKeyFrameStandardLimb::GetRawDataSize() const +{ + return 0xC; +} + +size_t ZKeyFrameFlexLimb::GetRawDataSize() const +{ + return 0x8; +} + +size_t ZKeyFrameLimbList::GetRawDataSize() const +{ + size_t limbSize; + if (limbType == ZKeyframeSkelType::Flex) + limbSize = 0x8; + else + limbSize = 0xC; + + return limbSize * numLimbs; +} + +ZKeyframeSkelType ZKeyFrameLimbList::ParseLimbTypeStr(const std::string& typeStr) +{ + if (typeStr == "Flex") + return ZKeyframeSkelType::Flex; + else if (typeStr == "Normal") + return ZKeyframeSkelType::Normal; + else + return ZKeyframeSkelType::Error; +} + +void ZKeyFrameLimb::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + dlist = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0); + numChildren = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x4); + flags = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x5); +} + +void ZKeyFrameStandardLimb::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + ZKeyFrameLimb::ParseRawData(); + translation.x = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x6); + translation.y = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x8); + translation.z = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0xA); +} + +void ZKeyFrameFlexLimb::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + ZKeyFrameLimb::ParseRawData(); + callbackIndex = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x6); +} + +void ZKeyFrameLimbList::ParseRawData() +{ + limbs.reserve(numLimbs); + rawDataIndex = GetRawDataIndex(); + + for (uint32_t i = 0; i < numLimbs; i++) + { + ZKeyFrameLimb* limb; + if (limbType == ZKeyframeSkelType::Flex) + limb = new ZKeyFrameFlexLimb(parent); + else + limb = new ZKeyFrameStandardLimb(parent); + + limb->SetRawDataIndex(rawDataIndex + (offset_t)(i * limb->GetRawDataSize())); + limb->ParseRawData(); + limbs.push_back(limb); + } +} + +std::string ZKeyFrameLimbList::GetBodySourceCode() const +{ + std::string declaration; + + for (const auto l : limbs) + declaration += StringHelper::Sprintf("\t{ %s },\n", l->GetBodySourceCode().c_str()); + // Remove last newline + return declaration.substr(0, declaration.length() - 1); +} + +std::string ZKeyFrameStandardLimb::GetBodySourceCode() const +{ + std::string declaration; + std::string dlString; + + Globals::Instance->GetSegmentedArrayIndexedName(dlist, 8, parent, "Gfx", dlString); + + declaration += + StringHelper::Sprintf("%s, 0x%02X, 0x%02X, { 0x%04X, 0x%04X, 0x%04X},", dlString.c_str(), + numChildren, flags, translation.x, translation.y, translation.z); + return declaration; +} + +std::string ZKeyFrameFlexLimb::GetBodySourceCode() const +{ + std::string declaration; + + std::string dlString; + + Globals::Instance->GetSegmentedArrayIndexedName(dlist, 8, parent, "Gfx", dlString); + + declaration += StringHelper::Sprintf("%s, 0x%02X, 0x%02X, 0x%02X", dlString.c_str(), + numChildren, flags, callbackIndex); + return declaration; +} + +std::string ZKeyFrameStandardLimb::GetSourceTypeName() const +{ + return "KeyFrameStandardLimb"; +} + +std::string ZKeyFrameFlexLimb::GetSourceTypeName() const +{ + return "KeyFrameFlexLimb"; +} + +std::string ZKeyFrameLimbList::GetSourceTypeName() const +{ + switch (limbType) + { + case ZKeyframeSkelType::Flex: + return "KeyFrameFlexLimb"; + case ZKeyframeSkelType::Normal: + return "KeyFrameStandardLimb"; + default: + HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, + "Invalid limb type", ""); + break; + } +} + +ZResourceType ZKeyFrameStandardLimb::GetResourceType() const +{ + return ZResourceType::KeyFrameStandardLimb; +} + +ZResourceType ZKeyFrameFlexLimb::GetResourceType() const +{ + return ZResourceType::KeyFrameFlexLimb; +} + +ZResourceType ZKeyFrameLimbList::GetResourceType() const +{ + switch (limbType) + { + case ZKeyframeSkelType::Flex: + return ZResourceType::KeyFrameFlexLimb; + case ZKeyframeSkelType::Normal: + return ZResourceType::KeyFrameStandardLimb; + default: + HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, + "Invalid limb type", ""); + break; + } +} diff --git a/tools/ZAPD/ZAPD/ZCKeyFrame.h b/tools/ZAPD/ZAPD/ZCKeyFrame.h new file mode 100644 index 0000000000..417d7cc686 --- /dev/null +++ b/tools/ZAPD/ZAPD/ZCKeyFrame.h @@ -0,0 +1,121 @@ +#pragma once + +#include +#include +#include +#include + +#include "ZFile.h" + +class ZKeyFrameLimb; + +struct Vec3s +{ + int16_t x; + int16_t y; + int16_t z; +}; + +enum class ZKeyframeSkelType +{ + Normal, + Flex, + Error, +}; + +class ZKeyFrameLimbList : public ZResource +{ +public: + ZKeyFrameLimbList(); + ZKeyFrameLimbList(ZFile* nParent); + ZKeyFrameLimbList(ZFile* nParent, uint32_t limbCount, ZKeyframeSkelType type); + + ~ZKeyFrameLimbList(); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + void ParseXML(tinyxml2::XMLElement* reader) override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; + + static ZKeyframeSkelType ParseLimbTypeStr(const std::string& typeStr); + + std::vector limbs; + ZKeyframeSkelType limbType; + uint8_t numLimbs; +}; + +class ZKeyFrameLimb : public ZResource +{ +public: + segptr_t dlist; + uint8_t numChildren; + uint8_t flags; + + ZKeyFrameLimb(ZFile* nParent); + void ParseRawData() override; +}; + +class ZKeyFrameStandardLimb : public ZKeyFrameLimb +{ +public: + Vec3s translation; + + ZKeyFrameStandardLimb(ZFile* nParent); + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; +}; + +class ZKeyFrameFlexLimb : public ZKeyFrameLimb +{ +public: + uint8_t callbackIndex; + + ZKeyFrameFlexLimb(ZFile* nParent); + // void ParseXML(tinyxml2::XMLElement* reader) override; + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + // std::string GetSourceOutputHeader(const std::string& prefix) override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; +}; + +class ZKeyFrameSkel : public ZResource +{ +public: + std::unique_ptr limbList; + segptr_t limbsPtr; + ZKeyframeSkelType limbType; + uint8_t limbCount; + uint8_t dListCount; + + ZKeyFrameSkel(ZFile* nParent); + ~ZKeyFrameSkel(); + + void ParseXML(tinyxml2::XMLElement* reader) override; + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; +}; diff --git a/tools/ZAPD/ZAPD/ZCKeyFrameAnim.cpp b/tools/ZAPD/ZAPD/ZCKeyFrameAnim.cpp new file mode 100644 index 0000000000..0b07471333 --- /dev/null +++ b/tools/ZAPD/ZAPD/ZCKeyFrameAnim.cpp @@ -0,0 +1,219 @@ +#include "ZCkeyFrameAnim.h" +#include "ZCKeyFrame.h" +#include "Globals.h" + +#include "Utils/BitConverter.h" + +REGISTER_ZFILENODE(KeyFrameAnimation, ZKeyFrameAnim); + +ZKeyFrameAnim::ZKeyFrameAnim(ZFile* nParent) : ZResource(nParent) +{ + RegisterRequiredAttribute("Skel"); +} + +ZKeyFrameAnim::~ZKeyFrameAnim() +{ +} + +void ZKeyFrameAnim::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + std::string skelAddrStr = registeredAttributes.at("Skel").value; + skelOffset = (offset_t)StringHelper::StrToL(skelAddrStr, 16); +} + +void ZKeyFrameAnim::DeclareReferencesLate(const std::string& prefix) +{ + std::string defaultPrefix = name; + std::string declaration; + + if (defaultPrefix == "") + defaultPrefix = prefix; + + ZResource::DeclareReferences(defaultPrefix); + + declaration += "\t"; + + if (skel->limbType == ZKeyframeSkelType::Normal) + { + for (const auto b : bitFlags) + { + declaration += StringHelper::Sprintf("0x%02X, ", b); + parent->AddDeclarationArray( + GETSEGOFFSET(bitFlagsAddr), DeclarationAlignment::Align4, bitFlags.size(), "u8", + StringHelper::Sprintf("%s_bitFlags_%06X", prefix.c_str(), rawDataIndex), + bitFlags.size(), declaration); + } + } + else + { + for (const auto b : bitFlagsFlex) + { + declaration += StringHelper::Sprintf("0x%04X, ", b); + parent->AddDeclarationArray( + GETSEGOFFSET(bitFlagsAddr), DeclarationAlignment::Align4, bitFlagsFlex.size() * 2, + "u16", StringHelper::Sprintf("%s_flexBitFlags_%06X", prefix.c_str(), rawDataIndex), + bitFlagsFlex.size(), declaration); + } + } + declaration.clear(); + + for (const auto kf : keyFrames) + { + declaration += + StringHelper::Sprintf(" \t { %i, %i, %i, },\n", kf.frame, kf.value, kf.velocity); + } + // Remove last new line to prevent an extra line after the last element + declaration = declaration.substr(0, declaration.length() - 1); + parent->AddDeclarationArray( + GETSEGOFFSET(keyFramesAddr), DeclarationAlignment::Align4, keyFrames.size() * 6, "KeyFrame", + StringHelper::Sprintf("%s_KeyFrame_%06X", prefix.c_str(), rawDataIndex), keyFrames.size(), + declaration); + + declaration.clear(); + + declaration += "\t"; + + for (const auto kfNum : kfNums) + { + declaration += StringHelper::Sprintf("0x%04X, ", kfNum); + } + + parent->AddDeclarationArray( + GETSEGOFFSET(kfNumsAddr), DeclarationAlignment::Align4, kfNums.size() * 2, "s16", + StringHelper::Sprintf("%s_kfNums_%06X", prefix.c_str(), rawDataIndex), kfNums.size(), + declaration); + declaration += "\n"; + + declaration.clear(); + + declaration += "\t"; + + for (const auto pv : presetValues) + { + declaration += StringHelper::Sprintf("0x%04X, ", pv); + } + declaration += "\n"; + parent->AddDeclarationArray( + GETSEGOFFSET(presentValuesAddr), DeclarationAlignment::Align4, presetValues.size() * 2, + "s16", StringHelper::Sprintf("%s_presetValues_%06X", prefix.c_str(), rawDataIndex), + presetValues.size(), declaration); + +} + +// ParseRawDataLate is used because we need to make sure the flex skel has been processed first. +void ZKeyFrameAnim::ParseRawDataLate() +{ + const auto& rawData = parent->GetRawData(); + + skel = static_cast(parent->FindResource(skelOffset)); + size_t numLimbs = skel->limbCount; + + bitFlagsAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0); + keyFramesAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x4); + kfNumsAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x8); + presentValuesAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0xC); + + uint32_t kfNumsSize = 0; + uint32_t presetValuesSize = 0; + uint32_t keyFramesCount = 0; + if (skel->limbType == ZKeyframeSkelType::Normal) + { + bitFlags.reserve(numLimbs); + for (size_t i = 0; i < numLimbs; i++) + { + uint8_t e = BitConverter::ToUInt8BE(rawData, GETSEGOFFSET(bitFlagsAddr) + i); + bitFlags.push_back(e); + kfNumsSize += GetSetBits((uint8_t)(e & 0b111111)); + presetValuesSize += GetSetBits((uint8_t)((e ^ 0xFF) & 0b111111)); + } + } + else + { + bitFlagsFlex.reserve(numLimbs); + for (size_t i = 0; i < numLimbs; i++) + { + uint16_t e = BitConverter::ToUInt16BE(rawData, GETSEGOFFSET(bitFlagsAddr) + (i * 2)); + bitFlagsFlex.push_back(e); + kfNumsSize += GetSetBits((uint16_t)(e & 0b111111111)); + presetValuesSize += GetSetBits((uint16_t)((e ^ 0xFFFF) & 0b111111111)); + } + } + + kfNums.reserve(kfNumsSize); + for (uint32_t i = 0; i < kfNumsSize; i++) + { + int16_t kfNum = BitConverter::ToUInt16BE(rawData, GETSEGOFFSET(kfNumsAddr) + (i * 2)); + keyFramesCount += kfNum; + kfNums.push_back(kfNum); + } + + keyFrames.reserve(keyFramesCount); + for (uint32_t i = 0; i < keyFramesCount; i++) + { + KeyFrame kf; + kf.frame = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 0) + (i * 6)); + kf.value = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 2) + (i * 6)); + kf.velocity = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 4) + (i * 6)); + keyFrames.push_back(kf); + } + + presetValues.reserve(presetValuesSize); + for (uint32_t i = 0; i < presetValuesSize; i++) + { + presetValues.push_back( + BitConverter::ToInt16BE(rawData, GETSEGOFFSET(presentValuesAddr) + (i * 2))); + } + + unk_10 = BitConverter::ToInt16BE(rawData, GETSEGOFFSET(rawDataIndex) + 0x10); + duration = BitConverter::ToInt16BE(rawData, GETSEGOFFSET(rawDataIndex) + 0x12); +} + +std::string ZKeyFrameAnim::GetBodySourceCode() const +{ + std::string declaration; + + std::string bitFlagsStr; + std::string keyFrameStr; + std::string kfNumsStr; + std::string presetValuesStr; + + Globals::Instance->GetSegmentedPtrName(bitFlagsAddr, parent, "", bitFlagsStr); + Globals::Instance->GetSegmentedPtrName(keyFramesAddr, parent, "", keyFrameStr); + Globals::Instance->GetSegmentedPtrName(kfNumsAddr, parent, "", kfNumsStr); + Globals::Instance->GetSegmentedPtrName(presentValuesAddr, parent, "", presetValuesStr); + + return StringHelper::Sprintf("\n\t%s, %s, %s, %s, 0x%04X, 0x%04X\n", bitFlagsStr.c_str(), + keyFrameStr.c_str(), kfNumsStr.c_str(), presetValuesStr.c_str(), + unk_10, duration); +} + +std::string ZKeyFrameAnim::GetSourceTypeName() const +{ + return "KeyFrameAnimation"; +} + +ZResourceType ZKeyFrameAnim::GetResourceType() const +{ + return ZResourceType::KeyFrameAnimation; +} + +size_t ZKeyFrameAnim::GetRawDataSize() const +{ + return 0x14; +} + +template +uint32_t ZKeyFrameAnim::GetSetBits(T data) const +{ + uint32_t num = 0; + + for (size_t i = 0; i < sizeof(T) * 8; i++) + { + if ((data >> i) & 1) + num++; + } + + return num; +} \ No newline at end of file diff --git a/tools/ZAPD/ZAPD/ZCkeyFrameAnim.h b/tools/ZAPD/ZAPD/ZCkeyFrameAnim.h new file mode 100644 index 0000000000..64f95b13ae --- /dev/null +++ b/tools/ZAPD/ZAPD/ZCkeyFrameAnim.h @@ -0,0 +1,52 @@ +#pragma once +#include +#include +#include +#include + +#include "ZFile.h" + +class ZKeyFrameSkel; + +typedef struct +{ + int16_t frame; + int16_t value; + int16_t velocity; +} KeyFrame; + +class ZKeyFrameAnim : public ZResource +{ +public: + ZKeyFrameSkel* skel; + std::vector bitFlags; // Standard only + std::vector bitFlagsFlex; // Flex only + + std::vector keyFrames; + std::vector kfNums; + std::vector presetValues; + + uint16_t unk_10; + int16_t duration; + + ZKeyFrameAnim(ZFile* nParent); + ~ZKeyFrameAnim(); + void ParseXML(tinyxml2::XMLElement* reader) override; + void DeclareReferencesLate(const std::string& prefix) override; + void ParseRawDataLate() override; + std::string GetBodySourceCode() const override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; + +private: + offset_t skelOffset; + segptr_t bitFlagsAddr; + segptr_t keyFramesAddr; + segptr_t kfNumsAddr; + segptr_t presentValuesAddr; + template + uint32_t GetSetBits(T data) const; +}; diff --git a/tools/ZAPD/ZAPD/ZCutscene.cpp b/tools/ZAPD/ZAPD/ZCutscene.cpp index ea723b2953..4cf375997a 100644 --- a/tools/ZAPD/ZAPD/ZCutscene.cpp +++ b/tools/ZAPD/ZAPD/ZCutscene.cpp @@ -323,7 +323,7 @@ CutsceneCommand* ZCutscene::GetCommandMM(uint32_t id, offset_t currentPtr) const return new CutsceneMMCommand_Text(rawData, currentPtr); case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE: - return new CutsceneMMCommand_Camera(rawData, currentPtr); + return new CutsceneMMCommand_Spline(rawData, currentPtr); case CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL: return new CutsceneMMCommand_TransitionGeneral(rawData, currentPtr); @@ -372,3 +372,36 @@ ZResourceType ZCutscene::GetResourceType() const { return ZResourceType::Cutscene; } + +std::string ZCutscene::GetCsEncodedFloat(float f, CsFloatType type, bool useSciNotation) +{ + switch (type) + { + default: + // This default case will NEVER be reached, but GCC still gives a warning. + case CsFloatType::HexOnly: + { + uint32_t i; + std::memcpy(&i, &f, sizeof(i)); + return StringHelper::Sprintf("0x%08X", i); + } + case CsFloatType::FloatOnly: + { + if (useSciNotation) + { + return StringHelper::Sprintf("%.8ef", f); + } + return StringHelper::Sprintf("%ff", f); + } + case CsFloatType::HexAndFloat: + { + uint32_t i; + std::memcpy(&i, &f, sizeof(i)); + if (useSciNotation) + { + return StringHelper::Sprintf("CS_FLOAT(0x%08X, %.8ef)", i, f); + } + return StringHelper::Sprintf("CS_FLOAT(0x%08X, %ff)", i, f); + } + } +} diff --git a/tools/ZAPD/ZAPD/ZCutscene.h b/tools/ZAPD/ZAPD/ZCutscene.h index 5b54426cea..5dbf475c33 100644 --- a/tools/ZAPD/ZAPD/ZCutscene.h +++ b/tools/ZAPD/ZAPD/ZCutscene.h @@ -10,6 +10,8 @@ #include "ZFile.h" #include "ZResource.h" +enum class CsFloatType; + class ZCutscene : public ZResource { public: @@ -27,6 +29,8 @@ public: std::string GetSourceTypeName() const override; ZResourceType GetResourceType() const override; + static std::string GetCsEncodedFloat(float f, CsFloatType type, bool useSciNotation); + int32_t numCommands; int32_t endFrame; std::vector commands; diff --git a/tools/ZAPD/ZAPD/ZResource.h b/tools/ZAPD/ZAPD/ZResource.h index 9754013984..768b785441 100644 --- a/tools/ZAPD/ZAPD/ZResource.h +++ b/tools/ZAPD/ZAPD/ZResource.h @@ -55,6 +55,10 @@ enum class ZResourceType Vector, Vertex, Waterbox, + KeyFrameFlexLimb, + KeyFrameStandardLimb, + KeyFrameSkel, + KeyFrameAnimation, }; class ResourceAttribute