Plugins agregados

This commit is contained in:
2026-03-30 15:33:19 -06:00
parent df2b257d93
commit eefc67e50a
766 changed files with 107667 additions and 0 deletions

84
ZAPDTR/.clang-format Normal file
View File

@@ -0,0 +1,84 @@
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 100
CommentPragmas: '^ (IWYU pragma:|NOLINT)'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ ]
IncludeCategories:
- Regex: '^<[Ww]indows\.h>$'
Priority: 1
- Regex: '^<'
Priority: 2
- Regex: '^"'
Priority: 3
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
TabWidth: 4
UseTab: AlignWithSpaces
...

83
ZAPDTR/.github/workflows/main.yml vendored Normal file
View File

@@ -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
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 extract_baserom.py
.venv/bin/python3 extract_assets.py -j 4
- name: Install Python dependencies
run: |
cd mm
python3 -m venv .mm-env
source .mm-env/bin/activate
python3 -m pip install -r requirements.txt
- name: Setup MM
run: |
cd mm
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
make -j disasm
make -j
- name: Clean workspace
run: git clean -fdX

341
ZAPDTR/.gitignore vendored Normal file
View File

@@ -0,0 +1,341 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
*.out
*.o
*.d
lib/libgfxd/libgfxd.a
ExporterTest/ExporterTest.a
ZAPDUtils/ZAPDUtils.a
.vscode/
build/
ZAPDUtils/build/
ZAPD/BuildInfo.h

View File

@@ -0,0 +1,76 @@
#include "CollisionExporter.h"
void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath,
BinaryWriter* writer)
{
ZCollisionHeader* col = (ZCollisionHeader*)res;
writer->Write(col->absMinX);
writer->Write(col->absMinY);
writer->Write(col->absMinZ);
writer->Write(col->absMaxX);
writer->Write(col->absMaxY);
writer->Write(col->absMaxZ);
writer->Write(col->numVerts);
writer->Write(col->vtxAddress);
writer->Write(col->numPolygons);
writer->Write(col->polyAddress);
writer->Write(col->polyTypeDefAddress);
writer->Write(col->camDataAddress);
writer->Write(col->numWaterBoxes);
writer->Write(col->waterBoxAddress);
writer->Write(col->vtxSegmentOffset);
writer->Write(col->polySegmentOffset);
writer->Write(col->polyTypeDefSegmentOffset);
writer->Write(col->camDataSegmentOffset);
writer->Write(col->waterBoxSegmentOffset);
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(col->vtxSegmentOffset, SeekOffsetType::Start);
for (uint16_t i = 0; i < col->vertices.size(); i++)
{
for (uint32_t j = 0; j < col->vertices[i].dimensions; j++)
{
writer->Write(col->vertices[i].scalars[j].scalarData.s16);
}
}
writer->Seek(col->polySegmentOffset, SeekOffsetType::Start);
for (uint16_t i = 0; i < col->polygons.size(); i++)
{
writer->Write(col->polygons[i].type);
writer->Write(col->polygons[i].vtxA);
writer->Write(col->polygons[i].vtxB);
writer->Write(col->polygons[i].vtxC);
writer->Write(col->polygons[i].normX);
writer->Write(col->polygons[i].normY);
writer->Write(col->polygons[i].normZ);
writer->Write(col->polygons[i].dist);
}
writer->Seek(col->polyTypeDefSegmentOffset, SeekOffsetType::Start);
for (const auto& poly : col->polygonTypes)
{
writer->Write(poly.data[0]);
writer->Write(poly.data[1]);
}
writer->Seek(col->camDataSegmentOffset, SeekOffsetType::Start);
for (auto entry : col->camData->entries)
{
writer->Write(entry.cameraSType);
writer->Write(entry.numData);
writer->Write(entry.cameraPosDataSeg);
}
writer->Seek(oldOffset, SeekOffsetType::Start);
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "ZCollision.h"
#include "ZResource.h"
class ExporterExample_Collision : public ZResourceExporter
{
public:
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

View File

@@ -0,0 +1,79 @@
#include "CollisionExporter.h"
#include "Globals.h"
#include "RoomExporter.h"
#include "TextureExporter.h"
enum class ExporterFileMode
{
ModeExample1 = (int)ZFileMode::Custom + 1,
ModeExample2 = (int)ZFileMode::Custom + 2,
ModeExample3 = (int)ZFileMode::Custom + 3,
};
static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileMode)
{
if (buildMode == "me1")
fileMode = (ZFileMode)ExporterFileMode::ModeExample1;
else if (buildMode == "me2")
fileMode = (ZFileMode)ExporterFileMode::ModeExample2;
else if (buildMode == "me3")
fileMode = (ZFileMode)ExporterFileMode::ModeExample3;
}
static void ExporterParseArgs([[maybe_unused]] int argc, char* argv[], int& i)
{
std::string arg = argv[i];
if (arg == "--do-x")
{
}
else if (arg == "--do-y")
{
}
}
static bool ExporterProcessFileMode(ZFileMode fileMode)
{
// Do whatever work is associated with these custom file modes...
// Return true to indicate one of our own file modes is being processed
if (fileMode == (ZFileMode)ExporterFileMode::ModeExample1)
return true;
else if (fileMode == (ZFileMode)ExporterFileMode::ModeExample2)
return true;
else if (fileMode == (ZFileMode)ExporterFileMode::ModeExample3)
return true;
return false;
}
static void ExporterFileBegin(ZFile* file)
{
printf("ExporterFileBegin() called on ZFile %s.\n", file->GetName().c_str());
}
static void ExporterFileEnd(ZFile* file)
{
printf("ExporterFileEnd() called on ZFile %s.\n", file->GetName().c_str());
}
static void ImportExporters()
{
// In this example we set up a new exporter called "EXAMPLE".
// By running ZAPD with the argument -se EXAMPLE, we tell it that we want to use this exporter
// for our resources.
ExporterSet* exporterSet = new ExporterSet();
exporterSet->processFileModeFunc = ExporterProcessFileMode;
exporterSet->parseFileModeFunc = ExporterParseFileMode;
exporterSet->parseArgsFunc = ExporterParseArgs;
exporterSet->beginFileFunc = ExporterFileBegin;
exporterSet->endFileFunc = ExporterFileEnd;
exporterSet->exporters[ZResourceType::Texture] = new ExporterExample_Texture();
exporterSet->exporters[ZResourceType::Room] = new ExporterExample_Room();
exporterSet->exporters[ZResourceType::CollisionHeader] = new ExporterExample_Collision();
Globals::AddExporter("EXAMPLE", exporterSet);
}
// When ZAPD starts up, it will automatically call the below function, which in turn sets up our
// exporters.
REGISTER_EXPORTER(ImportExporters);

View File

@@ -0,0 +1,372 @@
#include "RoomExporter.h"
#include "CollisionExporter.h"
#include "Utils/BinaryWriter.h"
#include <Utils/DiskFile.h>
#include "Utils/MemoryStream.h"
#include "ZRoom/Commands/SetCameraSettings.h"
#include "ZRoom/Commands/SetCollisionHeader.h"
#include "ZRoom/Commands/SetCsCamera.h"
#include "ZRoom/Commands/SetEchoSettings.h"
#include "ZRoom/Commands/SetEntranceList.h"
#include "ZRoom/Commands/SetLightingSettings.h"
#include "ZRoom/Commands/SetMesh.h"
#include "ZRoom/Commands/SetRoomBehavior.h"
#include "ZRoom/Commands/SetRoomList.h"
#include "ZRoom/Commands/SetSkyboxModifier.h"
#include "ZRoom/Commands/SetSkyboxSettings.h"
#include "ZRoom/Commands/SetSoundSettings.h"
#include "ZRoom/Commands/SetSpecialObjects.h"
#include "ZRoom/Commands/SetStartPositionList.h"
#include "ZRoom/Commands/SetTimeSettings.h"
#include "ZRoom/Commands/SetWind.h"
void ExporterExample_Room::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
{
ZRoom* room = dynamic_cast<ZRoom*>(res);
// MemoryStream* memStream = new MemoryStream();
// BinaryWriter* writer = new BinaryWriter(memStream);
for (size_t i = 0; i < room->commands.size() * 8; i++)
writer->Write((uint8_t)0);
for (size_t i = 0; i < room->commands.size(); i++)
{
ZRoomCommand* cmd = room->commands[i];
writer->Seek(i * 8, SeekOffsetType::Start);
writer->Write((uint8_t)cmd->cmdID);
switch (cmd->cmdID)
{
case RoomCommand::SetWind:
{
SetWind* cmdSetWind = (SetWind*)cmd;
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(cmdSetWind->windWest); // 0x04
writer->Write(cmdSetWind->windVertical); // 0x05
writer->Write(cmdSetWind->windSouth); // 0x06
writer->Write(cmdSetWind->clothFlappingStrength); // 0x07
}
break;
case RoomCommand::SetTimeSettings:
{
SetTimeSettings* cmdTime = (SetTimeSettings*)cmd;
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(cmdTime->hour); // 0x04
writer->Write(cmdTime->min); // 0x05
writer->Write(cmdTime->unk); // 0x06
writer->Write((uint8_t)0); // 0x07
}
break;
case RoomCommand::SetSkyboxModifier:
{
SetSkyboxModifier* cmdSkybox = (SetSkyboxModifier*)cmd;
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(cmdSkybox->disableSky); // 0x04
writer->Write(cmdSkybox->disableSunMoon); // 0x05
writer->Write((uint8_t)0); // 0x06
writer->Write((uint8_t)0); // 0x07
}
break;
case RoomCommand::SetEchoSettings:
{
SetEchoSettings* cmdEcho = (SetEchoSettings*)cmd;
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write((uint8_t)0); // 0x04
writer->Write((uint8_t)0); // 0x05
writer->Write((uint8_t)0); // 0x06
writer->Write((uint8_t)cmdEcho->echo); // 0x07
}
break;
case RoomCommand::SetSoundSettings:
{
SetSoundSettings* cmdSound = (SetSoundSettings*)cmd;
writer->Write((uint8_t)cmdSound->reverb); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write((uint8_t)0); // 0x04
writer->Write((uint8_t)0); // 0x05
writer->Write(cmdSound->nightTimeSFX); // 0x06
writer->Write(cmdSound->musicSequence); // 0x07
}
break;
case RoomCommand::SetSkyboxSettings:
{
SetSkyboxSettings* cmdSkybox = (SetSkyboxSettings*)cmd;
writer->Write((uint8_t)cmdSkybox->unk1); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write((uint8_t)cmdSkybox->skyboxNumber); // 0x04
writer->Write((uint8_t)cmdSkybox->cloudsType); // 0x05
writer->Write((uint8_t)cmdSkybox->isIndoors); // 0x06
}
break;
case RoomCommand::SetRoomBehavior:
{
SetRoomBehavior* cmdRoom = (SetRoomBehavior*)cmd;
writer->Write((uint8_t)cmdRoom->gameplayFlags); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(cmdRoom->gameplayFlags2); // 0x04
}
break;
case RoomCommand::SetCsCamera:
{
SetCsCamera* cmdCsCam = (SetCsCamera*)cmd;
writer->Write((uint8_t)cmdCsCam->cameras.size()); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(cmdCsCam->segmentOffset); // 0x04
}
break;
case RoomCommand::SetMesh:
{
SetMesh* cmdMesh = (SetMesh*)cmd;
int baseStreamEnd = writer->GetStream().get()->GetLength();
writer->Write((uint8_t)cmdMesh->data); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
// TODO: NOT DONE
writer->Write(cmdMesh->meshHeaderType);
if (cmdMesh->meshHeaderType == 0)
{
// writer->Write(cmdMesh->)
}
else if (cmdMesh->meshHeaderType == 1)
{
}
else if (cmdMesh->meshHeaderType == 2)
{
}
writer->Seek(oldOffset, SeekOffsetType::Start);
}
break;
case RoomCommand::SetCameraSettings:
{
SetCameraSettings* cmdCam = (SetCameraSettings*)cmd;
writer->Write((uint8_t)cmdCam->cameraMovement); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(cmdCam->mapHighlight); // 0x04
}
break;
case RoomCommand::SetLightingSettings:
{
SetLightingSettings* cmdLight = (SetLightingSettings*)cmd;
writer->Write((uint8_t)cmdLight->settings.size()); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(cmdLight->segmentOffset); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(cmdLight->segmentOffset, SeekOffsetType::Start);
for (LightingSettings setting : cmdLight->settings)
{
writer->Write(setting.ambientClrR);
writer->Write(setting.ambientClrG);
writer->Write(setting.ambientClrB);
writer->Write(setting.diffuseClrA_R);
writer->Write(setting.diffuseClrA_G);
writer->Write(setting.diffuseClrA_B);
writer->Write(setting.diffuseDirA_X);
writer->Write(setting.diffuseDirA_Y);
writer->Write(setting.diffuseDirA_Z);
writer->Write(setting.diffuseClrB_R);
writer->Write(setting.diffuseClrB_G);
writer->Write(setting.diffuseClrB_B);
writer->Write(setting.diffuseDirB_X);
writer->Write(setting.diffuseDirB_Y);
writer->Write(setting.diffuseDirB_Z);
writer->Write(setting.fogClrR);
writer->Write(setting.fogClrG);
writer->Write(setting.fogClrB);
writer->Write(setting.unk);
writer->Write(setting.drawDistance);
}
writer->Seek(oldOffset, SeekOffsetType::Start);
}
break;
case RoomCommand::SetRoomList:
{
SetRoomList* cmdRoom = (SetRoomList*)cmd;
writer->Write((uint8_t)cmdRoom->romfile->rooms.size()); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
auto baseStreamEnd = writer->GetLength();
writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
for (const auto& entry : cmdRoom->romfile->rooms)
{
writer->Write(entry.virtualAddressStart);
writer->Write(entry.virtualAddressEnd);
}
writer->Seek(oldOffset, SeekOffsetType::Start);
}
break;
case RoomCommand::SetCollisionHeader:
{
SetCollisionHeader* cmdCollHeader = (SetCollisionHeader*)cmd;
int streamEnd = writer->GetStream().get()->GetLength();
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(streamEnd); // 0x04
// TODO: NOT DONE
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(streamEnd, SeekOffsetType::Start);
ExporterExample_Collision colExp = ExporterExample_Collision();
colExp.Save(cmdCollHeader->collisionHeader, outPath, writer);
writer->Seek(oldOffset, SeekOffsetType::Start);
}
break;
case RoomCommand::SetEntranceList:
{
SetEntranceList* cmdEntrance = (SetEntranceList*)cmd;
uint32_t baseStreamEnd = writer->GetStream().get()->GetLength();
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
for (Spawn entry : cmdEntrance->entrances)
{
writer->Write((uint8_t)entry.startPositionIndex);
writer->Write((uint8_t)entry.roomToLoad);
}
writer->Seek(oldOffset, SeekOffsetType::Start);
}
break;
case RoomCommand::SetSpecialObjects:
{
SetSpecialObjects* cmdSpecObj = (SetSpecialObjects*)cmd;
writer->Write((uint8_t)cmdSpecObj->elfMessage); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write((uint8_t)0); // 0x04
writer->Write((uint8_t)0); // 0x05
writer->Write((uint16_t)cmdSpecObj->globalObject); // 0x06
}
break;
case RoomCommand::SetStartPositionList:
{
SetStartPositionList* cmdStartPos = (SetStartPositionList*)cmd;
uint32_t baseStreamEnd = writer->GetStream().get()->GetLength();
writer->Write((uint8_t)cmdStartPos->actors.size()); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
for (ActorSpawnEntry entry : cmdStartPos->actors)
{
writer->Write(entry.actorNum);
writer->Write(entry.posX);
writer->Write(entry.posY);
writer->Write(entry.posZ);
writer->Write(entry.rotX);
writer->Write(entry.rotY);
writer->Write(entry.rotZ);
writer->Write(entry.params);
}
writer->Seek(oldOffset, SeekOffsetType::Start);
}
break;
case RoomCommand::EndMarker:
{
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write((uint8_t)0); // 0x04
writer->Write((uint8_t)0); // 0x05
writer->Write((uint8_t)0); // 0x06
writer->Write((uint8_t)0); // 0x07
}
break;
default:
printf("UNIMPLEMENTED COMMAND: %i\n", (int)cmd->cmdID);
writer->Write((uint8_t)0); // 0x01
writer->Write((uint8_t)0); // 0x02
writer->Write((uint8_t)0); // 0x03
writer->Write((uint8_t)0); // 0x04
writer->Write((uint8_t)0); // 0x05
writer->Write((uint8_t)0); // 0x06
writer->Write((uint8_t)0); // 0x07
break;
}
}
// writer->Close();
// DiskFile::WriteAllBytes(StringHelper::Sprintf("%s", res->GetName().c_str()),
// memStream->ToVector());
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "ZResource.h"
#include "ZRoom/ZRoom.h"
class ExporterExample_Room : public ZResourceExporter
{
public:
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

View File

@@ -0,0 +1,14 @@
#include "TextureExporter.h"
#include "../ZAPD/ZFile.h"
void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath,
BinaryWriter* writer)
{
ZTexture* tex = (ZTexture*)res;
auto data = tex->parent->GetRawData();
for (offset_t i = tex->GetRawDataIndex(); i < tex->GetRawDataIndex() + tex->GetRawDataSize();
i++)
writer->Write(data[i]);
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "Utils/BinaryWriter.h"
#include "ZResource.h"
#include "ZTexture.h"
class ExporterExample_Texture : public ZResourceExporter
{
public:
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

21
ZAPDTR/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Zelda Reverse Engineering Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

164
ZAPDTR/README.md Normal file
View File

@@ -0,0 +1,164 @@
# ZAPD: Zelda Asset Processor for Decomp
## Compiling
### Dependencies
ZAPD needs a compiler with C++17 support.
ZAPD has the following library dependencies:
- `libpng`
In a Debian/Ubuntu based environment, those could be installed with the following command:
```bash
sudo apt install libpng-dev
```
On a Mac, you will need to install libpng with Homebrew or MacPorts; we currently only support Homebrew. You can run
```bash
brew install libpng
```
to install it via Homebrew.
### Building
#### Linux / *nix
ZAPD uses the classic `Makefile` approach. To build just run `make` (or even better `make -j` for faster compilations).
You can configure a bit your ZAPD build with the following options:
- `OPTIMIZATION_ON`: If set to `0` optimizations will be disabled (compile with `-O0`). Any other value compiles with `-O2`. Defaults to `1`.
- `ASAN`: If it is set to a non-zero then ZAPD will be compiled with Address Sanitizer enabled (`-fsanitize=address`). Defaults to `0`.
- `DEPRECATION_ON`: If it is set to a zero then deprecation warnings will be disabled. Defaults to `1`.
- `DEBUG`: If non-zero, ZAPD will be compiled in _development mode_. This implies the following:
- Debugging symbols enabled (`-g3`). They are disabled by default.
- `OPTIMIZATION_ON=0`: Disables optimizations (`-O0`).
- `DEPRECATION_ON=0`: Disables deprecation warnings.
- `LLD=1`: builds with the LLVM linker `ld.lld` instead of the system default.
As an example, if you want to build ZAPD with optimizations disabled and use the address sanitizer, you could use the following command:
```bash
make -j OPTIMIZATION_ON=0 ASAN=1
```
#### Windows
This repository contains `vcxproj` files for compiling under Visual Studio environments. See `ZAPD/ZAPD.vcxproj`.
## Invoking ZAPD
ZAPD needs a _File parsing mode_ to be passed as first parameter. The options are:
- `e`: "Extraction" mode.
- In this mode, ZAPD expects a XML file as input, a folder as ouput and a path to the baserom files.
- ZAPD will read the XML and use it as a guide to extract the contents of the specified asset file from the baserom folder.
- For more info of the format of those XMLs, see the [ZAPD extraction XML reference](docs/zapd_extraction_xml_reference.md).
- `bsf`: "Build source file" mode.
- This is an experimental mode.
- It was going to be used to let you have XMLs that aren't just for extraction. Might get used, might not. Still need to experiment on that.
- `btex`: "Build texture" mode.
- In this mode, ZAPD expects a PNG file as input, a filename as ouput and a texture type parameter (`-tt`).
- ZAPD will try to convert the given PNG into the contents of a `uint64_t` C array.
- `bren`: "Build (render) background" mode.
- In this mode, ZAPD expects a JPG file as input and a filename as ouput.
- ZAPD will try to convert the given JPG into the contents of a `uint64_t` C array.
- `blb`: "Build blob" mode.
- In this mode, ZAPD expects a BIN file as input and a filename as ouput.
- ZAPD will try to convert the given BIN into the contents of a `uint8_t` C array.
ZAPD also accepts the following list of extra parameters:
- `-i PATH` / `--inputpath PATH`: Set input path.
- `-o PATH` / `--outputpath PATH`: Set output path.
- `-b PATH` / `--baserompath`: Set baserom path.
- Can be used only in `e` or `bsf` modes.
- `-osf PATH`: Set source output path. This is the path where the `.c` and `.h` files will be extracted to. If omitted, it will use the value passed to `--outputpath` parameter.
- `-gsf MODE`: Generate source file during extraction. If `MODE` is `1`, C source files will be generated.
- Can be used only in `e` mode.
- `-crc` / `--output-crc`: Outputs a CRC file for each extracted texture.
- Can be used only in `e` or `bsf` modes.
- `-ulzdl MODE`: Use "Legacy ZDisplayList" instead of `libgfxd`. Set `MODE` to `1` to enable it.
- Can be used only in `e` or `bsf` modes.
- `-profile MODE`: Enable profiling. Set `MODE` to `1` to enable it.
- `-uer MODE`: Split resources into their individual components (enabled by default). Set `MODE` to non-`1` to disable it.
- `-tt TYPE`: Set texture type.
- Can be used only in mode `btex`.
- Valid values:
- `rgba32`
- `rgb5a1`
- `i4`
- `i8`
- `ia4`
- `ia8`
- `ia16`
- `ci4`
- `ci8`
- `-rconf PATH` Read Config File.
- `-eh`: Enable error handler.
- Only available in non-Windows environments.
- `-v MODE`: Enable verbosity. Currently there are 3 possible values:
- `0`: Default. Completely silent (except for warnings and errors).
- `1`: Information.
- `2` (and higher): Debug.
- `-wu` / `--warn-unaccounted`: Enable warnings for each unaccounted block of data found.
- Can be used only in `e` or `bsf` modes.
- `-vu` / `--verbose-unaccounted`: Changes how unaccounteds are outputted. Max 4 bytes per line (a word) and add a comment with the offset of each of those lines.
- Could be useful for looking at raw data or testing.
- Can be used only in `e` or `bsf` modes.
- `-tm MODE`: Test Mode (enables certain experimental features). To enable it, set `MODE` to `1`.
- `-se` / `--set-exporter` : Sets which exporter to use.
- `--gcc-compat` : Enables GCC compatibly mode. Slower.
- `-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.
- `-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.
### Warning flags
ZAPD contains a variety of warning types, with similar syntax to GCC or Clang's compiler warnings. Warnings can have three levels:
- Off (does not display anything)
- Warn (print a warning but continue processing)
- Err (behave like an error, i.e. print and throw an exception to crash ZAPD when occurs)
Each warning type uses one of these by default, but can be modified with flags, similarly to GCC or Clang:
- `-Wfoo` enables warnings of type `foo`
- `-Wno-foo` disables warnings of type `foo`
- `-Werror=foo` escalates `foo` to behave like an error
- `-Weverything` enables all warnings (they may be turned off using `-Wno-` flags afterwards)
- `-Werror` escalates all enabled warnings to errors
All warning types currently implemented, with their default levels:
| Warning type | Default level | Description |
| ----------------------------- | ------------- | ------------------------------------------------------------------------ |
| `-Wdeprecated` | Warn | Deprecated features |
| `-Whardcoded-generic-pointer` | Off | A generic segmented pointer must be produced |
| `-Whardcoded-pointer` | Warn | ZAPD lacks the info to make a symbol, so must output a hardcoded pointer |
| `-Wintersection` | Warn | Two assets intersect |
| `-Winvalid-attribute-value` | Err | Attribute declared in XML is wrong |
| `-Winvalid-extracted-data` | Err | Extracted data does not have correct form |
| `-Winvalid-jpeg` | Err | JPEG file does not conform to the game's format requirements |
| `-Winvalid-png` | Err | Issues arising when processing PNG data |
| `-Winvalid-xml` | Err | XML has syntax errors |
| `-Wmissing-attribute` | Warn | Required attribute missing in XML tag |
| `-Wmissing-offsets` | Warn | Offset attribute missing in XML tag |
| `-Wmissing-segment` | Warn | Segment not given in File tag in XML |
| `-Wnot-implemented` | Warn | ZAPD does not currently support this feature |
| `-Wunaccounted` | Off | Large blocks of unaccounted |
| `-Wunknown-attribute` | Warn | Unknown attribute in XML entry tag |
There are also errors that do not have a type, and cannot be disabled.
For example, here we have invoked ZAPD in the usual way to extract using a (rather badly-written) XML, but escalating `-Wintersection` to an error:
![ZAPD warnings example](docs/zapd_warning_example.png?raw=true)

454
ZAPDTR/ZAPD/CMakeLists.txt Normal file
View File

@@ -0,0 +1,454 @@
set(PROJECT_NAME ZAPDLib)
set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
#set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use")
set(CMAKE_C_STANDARD 11)
################################################################################
# Source groups
################################################################################
set(Header_Files
"../lib/tinyxml2/tinyxml2.h"
"CRC32.h"
"Declaration.h"
"FileWorker.h"
"GameConfig.h"
"Globals.h"
"ImageBackend.h"
"OutputFormatter.h"
"WarningHandler.h"
"CrashHandler.h"
)
source_group("Header Files" FILES ${Header_Files})
set(Header_Files__Libraries
"ctpl_stl.h"
)
source_group("Header Files\\Libraries" FILES ${Header_Files__Libraries})
set(Header_Files__Libraries__libgfxd
"../lib/libgfxd/gbi.h"
"../lib/libgfxd/gfxd.h"
"../lib/libgfxd/priv.h"
)
source_group("Header Files\\Libraries\\libgfxd" FILES ${Header_Files__Libraries__libgfxd})
set(Header_Files__Yaz0
"yaz0/readwrite.h"
"yaz0/yaz0.h"
)
source_group("Header Files\\Yaz0" FILES ${Header_Files__Yaz0})
set(Header_Files__Z64
"OtherStructs/Cutscene_Common.h"
"OtherStructs/CutsceneMM_Commands.h"
"OtherStructs/CutsceneOoT_Commands.h"
"OtherStructs/SkinLimbStructs.h"
"ZAnimation.h"
"ZActorList.h"
"ZArray.h"
"ZAudio.h"
"ZBackground.h"
"ZBlob.h"
"ZCollision.h"
"ZCollisionPoly.h"
"ZCKeyFrame.h"
"ZCkeyFrameAnim.h"
"ZCutscene.h"
"ZDisplayList.h"
"ZFile.h"
"ZLimb.h"
"ZMtx.h"
"ZPath.h"
"ZPlayerAnimationData.h"
"ZPointer.h"
"ZResource.h"
"ZRom.h"
"ZScalar.h"
"ZSkeleton.h"
"ZSurfaceType.h"
"ZString.h"
"ZSymbol.h"
"ZText.h"
"ZTextMM.cpp"
"ZTexture.h"
"ZTextureAnimation.h"
"ZVector.h"
"ZWaterbox.h"
"ZVtx.h"
)
source_group("Header Files\\Z64" FILES ${Header_Files__Z64})
set(Header_Files__Z64__ZRoom
"ZRoom/ZRoom.h"
"ZRoom/ZRoomCommand.h"
)
source_group("Header Files\\Z64\\ZRoom" FILES ${Header_Files__Z64__ZRoom})
set(Header_Files__Z64__ZRoom__Commands
"ZRoom/Commands/EndMarker.h"
"ZRoom/Commands/SetActorList.h"
"ZRoom/Commands/SetAlternateHeaders.h"
"ZRoom/Commands/SetAnimatedMaterialList.h"
"ZRoom/Commands/SetCameraSettings.h"
"ZRoom/Commands/SetCollisionHeader.h"
"ZRoom/Commands/SetCsCamera.h"
"ZRoom/Commands/SetCutscenes.h"
"ZRoom/Commands/SetCutsceneEntryList.cpp"
"ZRoom/Commands/SetEchoSettings.h"
"ZRoom/Commands/SetEntranceList.h"
"ZRoom/Commands/SetExitList.h"
"ZRoom/Commands/SetLightingSettings.h"
"ZRoom/Commands/SetLightList.h"
"ZRoom/Commands/SetMesh.h"
"ZRoom/Commands/SetMinimapChests.h"
"ZRoom/Commands/SetMinimapList.h"
"ZRoom/Commands/SetObjectList.h"
"ZRoom/Commands/SetPathways.h"
"ZRoom/Commands/SetRoomBehavior.h"
"ZRoom/Commands/SetRoomList.h"
"ZRoom/Commands/SetSkyboxModifier.h"
"ZRoom/Commands/SetSkyboxSettings.h"
"ZRoom/Commands/SetSoundSettings.h"
"ZRoom/Commands/SetSpecialObjects.h"
"ZRoom/Commands/SetStartPositionList.h"
"ZRoom/Commands/SetTimeSettings.h"
"ZRoom/Commands/SetTransitionActorList.h"
"ZRoom/Commands/SetWind.h"
"ZRoom/Commands/SetWorldMapVisited.h"
"ZRoom/Commands/Unused09.h"
"ZRoom/Commands/Unused1D.h"
"ZRoom/Commands/ZRoomCommandUnk.h"
)
source_group("Header Files\\Z64\\ZRoom\\Commands" FILES ${Header_Files__Z64__ZRoom__Commands})
set(Source_Files
"CrashHandler.cpp"
"Declaration.cpp"
"FileWorker.cpp"
"GameConfig.cpp"
"Globals.cpp"
"ImageBackend.cpp"
"Main.cpp"
"OutputFormatter.cpp"
"WarningHandler.cpp"
)
source_group("Source Files" FILES ${Source_Files})
set(Source_Files__Libraries__libgfxd
"../lib/libgfxd/gfxd.c"
"../lib/libgfxd/uc.c"
"../lib/libgfxd/uc_f3dex2.c"
)
source_group("Source Files\\Libraries\\libgfxd" FILES ${Source_Files__Libraries__libgfxd})
set(Source_Files__Yaz0
"yaz0/yaz0.cpp"
)
source_group("Source Files\\Yaz0" FILES ${Source_Files__Yaz0})
set(Source_Files__Z64
"OtherStructs/Cutscene_Common.cpp"
"OtherStructs/CutsceneMM_Commands.cpp"
"OtherStructs/CutsceneOoT_Commands.cpp"
"OtherStructs/SkinLimbStructs.cpp"
"ZAnimation.cpp"
"ZActorList.cpp"
"ZArray.cpp"
"ZAudio.cpp"
"ZAudioDecode.cpp"
"ZBackground.cpp"
"ZBlob.cpp"
"ZCollision.cpp"
"ZCollisionPoly.cpp"
"ZCKeyFrame.cpp"
"ZCKeyFrameAnim.cpp"
"ZCutscene.cpp"
"ZDisplayList.cpp"
"ZFile.cpp"
"ZLimb.cpp"
"ZMtx.cpp"
"ZPath.cpp"
"ZPlayerAnimationData.cpp"
"ZPointer.cpp"
"ZResource.cpp"
"ZRom.cpp"
"ZScalar.cpp"
"ZSkeleton.cpp"
"ZSurfaceType.cpp"
"ZString.cpp"
"ZSymbol.cpp"
"ZText.cpp"
"ZTextMM.cpp"
"ZTexture.cpp"
"ZTextureAnimation.cpp"
"ZVector.cpp"
"ZWaterbox.cpp"
"ZVtx.cpp"
)
source_group("Source Files\\Z64" FILES ${Source_Files__Z64})
set(Source_Files__Z64__ZRoom
"ZRoom/ZRoom.cpp"
"ZRoom/ZRoomCommand.cpp"
)
source_group("Source Files\\Z64\\ZRoom" FILES ${Source_Files__Z64__ZRoom})
set(Source_Files__Z64__ZRoom__Commands
"ZRoom/Commands/EndMarker.cpp"
"ZRoom/Commands/SetActorList.cpp"
"ZRoom/Commands/SetAlternateHeaders.cpp"
"ZRoom/Commands/SetAnimatedMaterialList.cpp"
"ZRoom/Commands/SetCameraSettings.cpp"
"ZRoom/Commands/SetCollisionHeader.cpp"
"ZRoom/Commands/SetCsCamera.cpp"
"ZRoom/Commands/SetCutscenes.cpp"
"ZRoom/Commands/SetCutsceneEntryList.cpp"
"ZRoom/Commands/SetEchoSettings.cpp"
"ZRoom/Commands/SetEntranceList.cpp"
"ZRoom/Commands/SetExitList.cpp"
"ZRoom/Commands/SetLightingSettings.cpp"
"ZRoom/Commands/SetLightList.cpp"
"ZRoom/Commands/SetMesh.cpp"
"ZRoom/Commands/SetMinimapChests.cpp"
"ZRoom/Commands/SetMinimapList.cpp"
"ZRoom/Commands/SetObjectList.cpp"
"ZRoom/Commands/SetPathways.cpp"
"ZRoom/Commands/SetRoomBehavior.cpp"
"ZRoom/Commands/SetRoomList.cpp"
"ZRoom/Commands/SetSkyboxModifier.cpp"
"ZRoom/Commands/SetSkyboxSettings.cpp"
"ZRoom/Commands/SetSoundSettings.cpp"
"ZRoom/Commands/SetSpecialObjects.cpp"
"ZRoom/Commands/SetStartPositionList.cpp"
"ZRoom/Commands/SetTimeSettings.cpp"
"ZRoom/Commands/SetTransitionActorList.cpp"
"ZRoom/Commands/SetWind.cpp"
"ZRoom/Commands/SetWorldMapVisited.cpp"
"ZRoom/Commands/Unused09.cpp"
"ZRoom/Commands/Unused1D.cpp"
"ZRoom/Commands/ZRoomCommandUnk.cpp"
)
source_group("Source Files\\Z64\\ZRoom\\Commands" FILES ${Source_Files__Z64__ZRoom__Commands})
file(GLOB Source_Files__Utils RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "Utils/*.c" "Utils/*.cpp")
source_group("Source Files\\Utils" FILES ${Source_Files__Utils})
file(GLOB Header_Files__Utils RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "Utils/*.h")
source_group("Header Files\\Utils" FILES ${Header_Files__Utils})
set(ALL_FILES
${Header_Files}
${Header_Files__Libraries}
${Header_Files__Libraries__libgfxd}
${Header_Files__Yaz0}
${Header_Files__Z64}
${Header_Files__Z64__ZRoom}
${Header_Files__Z64__ZRoom__Commands}
${Header_Files__Utils}
${Source_Files}
${Source_Files__Libraries__libgfxd}
${Source_Files__Yaz0}
${Source_Files__Z64}
${Source_Files__Z64__ZRoom}
${Source_Files__Z64__ZRoom__Commands}
${Source_Files__Utils}
${any__any}
)
################################################################################
# Target
################################################################################
add_library(${PROJECT_NAME} STATIC ${ALL_FILES})
add_executable(ZAPD ExecutableMain.cpp)
target_link_libraries(ZAPD ${PROJECT_NAME})
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
use_props(${PROJECT_NAME} "${CMAKE_CONFIGURATION_TYPES}" "${DEFAULT_CXX_PROPS}")
use_props(ZAPD "${CMAKE_CONFIGURATION_TYPES}" "${DEFAULT_CXX_PROPS}")
endif()
################################################################################
# Includes for CMake from *.props
################################################################################
set(ROOT_NAMESPACE ZAPD)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set_target_properties(${PROJECT_NAME} PROPERTIES
INTERPROCEDURAL_OPTIMIZATION_RELEASE "TRUE"
)
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
set_target_properties(ZAPD PROPERTIES
OUTPUT_NAME "ZAPD.out"
)
endif()
################################################################################
# MSVC runtime library
################################################################################
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
foreach(ZTarget ${PROJECT_NAME} ZAPD)
get_property(MSVC_RUNTIME_LIBRARY_DEFAULT TARGET ${ZTarget} PROPERTY MSVC_RUNTIME_LIBRARY)
string(CONCAT "MSVC_RUNTIME_LIBRARY_STR"
$<$<CONFIG:Debug>:
MultiThreadedDebug
>
$<$<CONFIG:Release>:
MultiThreaded
>
$<$<NOT:$<OR:$<CONFIG:Debug>,$<CONFIG:Release>>>:${MSVC_RUNTIME_LIBRARY_DEFAULT}>
)
set_target_properties(${ZTarget} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR})
endforeach()
endif()
################################################################################
# Compile definitions
################################################################################
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(${PROJECT_NAME} PRIVATE
"_CRT_SECURE_NO_WARNINGS;"
"_MBCS"
STORMLIB_NO_AUTO_LINK
)
endif()
################################################################################
# Compile and link options
################################################################################
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(CMAKE_FIND_FRAMEWORK LAST)
endif()
find_package(PNG REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/include
${CMAKE_CURRENT_SOURCE_DIR}/../../ZAPDTR/lib/libgfxd
${PNG_PNG_INCLUDE_DIR}/
.
)
if(MSVC)
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Debug>:
/Od;
/RTC1
>
$<$<CONFIG:Release>:
/O2;
/Oi;
/Gy
>
/permissive-;
/sdl;
/W3;
${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT};
${DEFAULT_CXX_EXCEPTION_HANDLING}
)
target_link_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Debug>:
/PROFILE
>
$<$<CONFIG:Release>:
/OPT:REF;
/OPT:ICF
>
/DEBUG:FULL
)
endif()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
target_compile_options(${PROJECT_NAME} PUBLIC
-Wall -Wextra -Wno-error
-Wno-unused-parameter
-Wno-unused-function
-Wno-unused-variable
-Wno-missing-field-initializers
-Wno-parentheses
-Wno-narrowing
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion>
-pthread
)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
target_link_options(${PROJECT_NAME} PUBLIC
-pthread
)
else()
target_link_options(${PROJECT_NAME} PUBLIC
-pthread
-Wl,-export-dynamic
)
endif()
endif()
################################################################################
# Dependencies
################################################################################
add_dependencies(${PROJECT_NAME}
OTRExporter
libultraship
)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"-WHOLEARCHIVE:$<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter>"
"libultraship;"
storm
PNG::PNG
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
-Wl,-force_load $<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter>
"libultraship;"
PNG::PNG
${CMAKE_DL_LIBS}
Threads::Threads
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
-Wl,--whole-archive $<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter> -Wl,--no-whole-archive
"libultraship;"
PNG::PNG
Threads::Threads
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
PNG::PNG
)
else()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
-Wl,--whole-archive $<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter> -Wl,--no-whole-archive
"libultraship;"
PNG::PNG
${CMAKE_DL_LIBS}
Threads::Threads
)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
add_library(pathconf OBJECT pathconf.c)
target_link_libraries(${PROJECT_NAME} PUBLIC "${ADDITIONAL_LIBRARY_DEPENDENCIES}" $<TARGET_OBJECTS:pathconf> )
else()
target_link_libraries(${PROJECT_NAME} PUBLIC "${ADDITIONAL_LIBRARY_DEPENDENCIES}")
endif()
if (GAME_STR STREQUAL "MM")
target_compile_definitions(${PROJECT_NAME} PRIVATE GAME_MM)
else()
target_compile_definitions(${PROJECT_NAME} PRIVATE GAME_OOT)
endif()

23
ZAPDTR/ZAPD/CRC32.h Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
static uint32_t CRC32B(const unsigned char* message, int32_t size)
{
int32_t byte, crc;
int32_t mask;
crc = 0xFFFFFFFF;
for (int32_t i = 0; i < size; i++)
{
byte = message[i];
crc = crc ^ byte;
for (int32_t j = 7; j >= 0; j--)
{
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
return ~(uint32_t)(crc);
}

View File

@@ -0,0 +1,208 @@
#include "CrashHandler.h"
#include "Utils/StringHelper.h"
#if __has_include(<unistd.h>)
#define HAS_POSIX 1
#else
#define HAS_POSIX 0
#endif
#include <array>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#if HAS_POSIX == 1
#include <csignal>
#include <cxxabi.h> // for __cxa_demangle
#include <dlfcn.h> // for dladdr
#include <execinfo.h>
#include <unistd.h>
#elif defined(_MSC_VER)
#include <Windows.h>
#include <DbgHelp.h>
#include <inttypes.h>
#pragma comment(lib, "Dbghelp.lib")
#endif
// Feel free to add more crash messages.
static std::array<const char* const, 14> crashEasterEgg = {
"\tYou've met with a terrible fate, haven't you?",
"\tSEA BEARS FOAM. SLEEP BEARS DREAMS. \n\tBOTH END IN THE SAME WAY: CRASSSH!",
"\tZAPD has fallen and cannot get up.",
"\tIT'S A SECRET TO EVERYBODY. \n\tBut it shouldn't be, you'd better ask about it!",
"\tI AM ERROR.",
"\tGRUMBLE,GRUMBLE...",
"\tDODONGO DISLIKES SMOKE \n\tAnd ZAPD dislikes whatever you fed it.",
"\tMay the way of the Hero lead \n\tto the debugger.",
"\tTHE WIND FISH SLUMBERS LONG... \n\tTHE HERO'S LIFE GONE... ",
"\tSEA BEARS FOAM, SLEEP BEARS DREAMS. \n\tBOTH END IN THE SAME WAY CRASSSH!",
"\tYou've met with a terrible fate, haven't you?",
"\tMaster, I calculate a 100% probability that ZAPD has crashed. \n\tAdditionally, the "
"batteries in your Wii Remote are nearly depleted.",
"\t CONGRATURATIONS! \n"
"\tAll Pages are displayed.\n"
"\t THANK YOU! \n"
"\t You are great debugger!",
"\tRCP is HUNG UP!!\n"
"\tOh! MY GOD!!",
};
#if HAS_POSIX == 1
void ErrorHandler(int sig)
{
std::array<void*, 4096> arr;
constexpr size_t nMaxFrames = arr.size();
size_t size = backtrace(arr.data(), nMaxFrames);
char** symbols = backtrace_symbols(arr.data(), nMaxFrames);
fprintf(stderr, "\nZAPD crashed. (Signal: %i)\n", sig);
srand(time(nullptr));
auto easterIndex = rand() % crashEasterEgg.size();
fprintf(stderr, "\n%s\n\n", crashEasterEgg[easterIndex]);
fprintf(stderr, "Traceback:\n");
for (size_t i = 1; i < size; i++)
{
Dl_info info;
uint32_t gotAddress = dladdr(arr[i], &info);
std::string functionName(symbols[i]);
if (gotAddress != 0 && info.dli_sname != nullptr)
{
int32_t status;
char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
const char* nameFound = info.dli_sname;
if (status == 0)
{
nameFound = demangled;
}
functionName = StringHelper::Sprintf("%s (+0x%X)", nameFound,
(char*)arr[i] - (char*)info.dli_saddr);
free(demangled);
}
fprintf(stderr, "%-3zd %s\n", i, functionName.c_str());
}
fprintf(stderr, "\n");
free(symbols);
exit(1);
}
#elif defined(_MSC_VER)
void printStack(CONTEXT* ctx)
{
BOOL result;
HANDLE process;
HANDLE thread;
HMODULE hModule;
ULONG frame;
DWORD64 displacement;
DWORD disp;
srand(time(nullptr));
auto easterIndex = rand() % crashEasterEgg.size();
fprintf(stderr, "\n%s\n\n", crashEasterEgg[easterIndex]);
#if defined(_M_AMD64)
STACKFRAME64 stack;
memset(&stack, 0, sizeof(STACKFRAME64));
#else
STACKFRAME stack;
memset(&stack, 0, sizeof(STACKFRAME));
#endif
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME + sizeof(TCHAR)];
char module[512];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
CONTEXT ctx2;
memcpy(&ctx2, ctx, sizeof(CONTEXT));
process = GetCurrentProcess();
thread = GetCurrentThread();
SymInitialize(process, nullptr, TRUE);
constexpr DWORD machineType =
#if defined(_M_AMD64)
IMAGE_FILE_MACHINE_AMD64;
#else
IMAGE_FILE_MACHINE_I386;
#endif
displacement = 0;
for (frame = 0;; frame++)
{
result = StackWalk(machineType, process, thread, &stack, &ctx2, nullptr,
SymFunctionTableAccess, SymGetModuleBase, nullptr);
if (!result)
{
break;
}
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
SymFromAddr(process, (ULONG64)stack.AddrPC.Offset, &displacement, symbol);
#if defined(_M_AMD64)
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
#else
IMAGEHLP_LINE line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
#endif
if (SymGetLineFromAddr(process, stack.AddrPC.Offset, &disp, &line))
{
fprintf(stderr, "%u\t %s in %s: line: %lu: \n", frame, symbol->Name, line.FileName,
line.LineNumber);
}
else
{
fprintf(stderr, "%u\tat % s\n", frame, symbol->Name);
hModule = nullptr;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR)(stack.AddrPC.Offset), &hModule);
if (hModule != nullptr)
{
GetModuleFileNameA(hModule, module, 512 - 1);
}
fprintf(stderr, "%u\tIn %s\n", frame, module);
}
}
}
LONG seh_filter(_EXCEPTION_POINTERS* ex)
{
fprintf(stderr, "EXCEPTION 0x%x occured\n", ex->ExceptionRecord->ExceptionCode);
printStack(ex->ContextRecord);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
void CrashHandler_Init()
{
#if 0
#if HAS_POSIX == 1
signal(SIGSEGV, ErrorHandler);
signal(SIGABRT, ErrorHandler);
#elif defined(_MSC_VER)
SetUnhandledExceptionFilter(seh_filter);
#else
HANDLE_WARNING(WarningType::Always,
"tried to set error handler, but this ZAPD build lacks support for one", "");
#endif
#endif
}

View File

@@ -0,0 +1,6 @@
#ifndef CRASH_HANDLER_H
#define CRASH_HANDLER_H
void CrashHandler_Init();
#endif

248
ZAPDTR/ZAPD/Declaration.cpp Normal file
View File

@@ -0,0 +1,248 @@
#include "Declaration.h"
#include "Globals.h"
#include "ZVtx.h"
#include "Utils/StringHelper.h"
Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
const std::string& nBody)
{
address = nAddress;
alignment = nAlignment;
size = nSize;
declBody = nBody;
}
Declaration* Declaration::Create(offset_t declAddr, DeclarationAlignment declAlign, size_t declSize,
const std::string& declType, const std::string& declName,
const std::string& declBody)
{
Declaration* decl = new Declaration(declAddr, declAlign, declSize, declBody);
decl->declType = declType;
decl->declName = declName;
decl->declBody = declBody;
return decl;
}
Declaration* Declaration::CreateArray(offset_t declAddr, DeclarationAlignment declAlign,
size_t declSize, const std::string& declType,
const std::string& declName, const std::string& declBody,
size_t declArrayItemCnt, bool isDeclExternal)
{
Declaration* decl = new Declaration(declAddr, declAlign, declSize, declBody);
decl->declName = declName;
decl->declType = declType;
decl->arrayItemCnt = declArrayItemCnt;
decl->isExternal = isDeclExternal;
decl->isArray = true;
return decl;
}
Declaration* Declaration::CreateArray(offset_t declAddr, DeclarationAlignment declAlign,
size_t declSize, const std::string& declType,
const std::string& declName, const std::string& declBody,
const std::string& declArrayItemCntStr, bool isDeclExternal)
{
Declaration* decl = new Declaration(declAddr, declAlign, declSize, declBody);
decl->declName = declName;
decl->declType = declType;
decl->arrayItemCntStr = declArrayItemCntStr;
decl->isExternal = isDeclExternal;
decl->isArray = true;
return decl;
}
Declaration* Declaration::CreateInclude(offset_t declAddr, const std::string& includePath,
size_t declSize, const std::string& declType,
const std::string& declName, const std::string& defines)
{
Declaration* decl = new Declaration(declAddr, DeclarationAlignment::Align4, declSize, "");
decl->includePath = includePath;
decl->declType = declType;
decl->declName = declName;
decl->defines = defines;
return decl;
}
Declaration* Declaration::CreatePlaceholder(offset_t declAddr, const std::string& declName)
{
Declaration* decl = new Declaration(declAddr, DeclarationAlignment::Align4, 0, "");
decl->declName = declName;
decl->isPlaceholder = true;
return decl;
}
Declaration::~Declaration()
{
//for (auto item : vertexHack)
//delete item;
}
bool Declaration::IsStatic() const
{
switch (staticConf)
{
case StaticConfig::Off:
return false;
case StaticConfig::Global:
return Globals::Instance->forceStatic;
case StaticConfig::On:
return true;
}
return false;
}
std::string Declaration::GetNormalDeclarationStr() const
{
std::string output;
if (IsStatic())
{
output += "static ";
}
if (isArray)
{
bool includeArraySize = (IsStatic() || forceArrayCnt);
if (includeArraySize)
{
if (arrayItemCntStr != "")
output += StringHelper::Sprintf("%s %s[%s];\n", declType.c_str(), declName.c_str(),
arrayItemCntStr.c_str());
else
output += StringHelper::Sprintf("%s %s[%i] = {\n", declType.c_str(),
declName.c_str(), arrayItemCnt);
}
else
{
output += StringHelper::Sprintf("%s %s[] = {\n", declType.c_str(), declName.c_str());
}
output += declBody + "\n";
}
else
{
output += StringHelper::Sprintf("%s %s = { ", declType.c_str(), declName.c_str());
output += declBody;
}
if (output.back() == '\n')
output += "};";
else
output += " };";
output += "\n";
output += "\n";
return output;
}
std::string Declaration::GetExternalDeclarationStr() const
{
std::string output;
if (IsStatic())
output += "static ";
bool includeArraySize = (IsStatic() || forceArrayCnt);
if (includeArraySize)
{
if (arrayItemCntStr != "")
output += StringHelper::Sprintf("%s %s[%s] = ", declType.c_str(), declName.c_str(),
arrayItemCntStr.c_str());
else
output += StringHelper::Sprintf("%s %s[%i] = ", declType.c_str(), declName.c_str(),
arrayItemCnt);
}
else
{
output += StringHelper::Sprintf("%s %s[] = ", declType.c_str(), declName.c_str());
}
output += StringHelper::Sprintf("{\n#include \"%s\"\n};", includePath.c_str());
output += "\n\n";
return output;
}
std::string Declaration::GetExternStr() const
{
if (IsStatic() || declType == "" || isUnaccounted)
{
return "";
}
if (Globals::Instance->otrMode) /* && (varType == "Gfx" || varType == "u64" || varType == "AnimationHeader" || varType == "LinkAnimationHeader" ||
varType == "StandardLimb" || varType == "JointIndex" || varType == "Vtx" || varType == "FlexSkeletonHeader" || varType == "SkeletonHeader") ||
varType == "CollisionHeader") */
return "";
if (isArray)
{
if (arrayItemCntStr != "" && (IsStatic() || forceArrayCnt))
{
return StringHelper::Sprintf("extern %s %s[%s];\n", declType.c_str(), declName.c_str(),
arrayItemCntStr.c_str());
}
else if (arrayItemCnt != 0 && (IsStatic() || forceArrayCnt))
{
return StringHelper::Sprintf("extern %s %s[%i];\n", declType.c_str(), declName.c_str(),
arrayItemCnt);
}
else
return StringHelper::Sprintf("extern %s %s[];\n", declType.c_str(), declName.c_str());
}
return StringHelper::Sprintf("extern %s %s;\n", declType.c_str(), declName.c_str());
}
std::string Declaration::GetDefinesStr() const
{
if (IsStatic() || (declType == ""))
{
return "";
}
return StringHelper::Sprintf("%s", defines.c_str());
}
std::string Declaration::GetStaticForwardDeclarationStr() const
{
if (!IsStatic() || isUnaccounted)
return "";
if (isArray)
{
if (arrayItemCntStr == "" && arrayItemCnt == 0)
{
// Forward declaring static arrays without specifying the size is not allowed.
return "";
}
if (arrayItemCntStr != "")
{
return StringHelper::Sprintf("static %s %s[%s];\n", declType.c_str(), declName.c_str(),
arrayItemCntStr.c_str());
}
else
{
return StringHelper::Sprintf("static %s %s[%i];\n", declType.c_str(), declName.c_str(),
arrayItemCnt);
}
}
return StringHelper::Sprintf("static %s %s;\n", declType.c_str(), declName.c_str());
}

188
ZAPDTR/ZAPD/Declaration.h Normal file
View File

@@ -0,0 +1,188 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
// TODO: should we drop the `_t` suffix because of UNIX compliance?
typedef uint32_t segptr_t;
typedef uint32_t offset_t;
#define SEGMENTED_NULL ((segptr_t)0)
enum class DeclarationAlignment
{
Align4,
Align8
};
enum class StaticConfig
{
Off,
Global,
On
};
class ZVtx;
/// <summary>
/// A declaration is contains the C contents of a symbol for a file.
/// It contains at a minimum the address where the symbol would be in the binary file, alignment
/// settings, the size of the binary data, and the C code that makes it up. Optionally it can also
/// contain comments.
/// </summary>
class Declaration
{
public:
// Where in the binary file (segment) will this C code end up being?
offset_t address = 0;
// How is this C code aligned?
DeclarationAlignment alignment = DeclarationAlignment::Align4;
// How many bytes will this C code take up in the resulting binary when compiled?
size_t size = 0;
// The C type of this declaration
std::string declType = "";
// The C variable name of this declaration
std::string declName = "";
// The body of the declaration containing the data.
// In "int j = 7;", "7" would be text.
std::string declBody = "";
// #define's to be included in the header
std::string defines = "";
std::string includePath = "";
std::vector<ZVtx*> vertexHack;
// Is this declaration in an external file? (ie. a gameplay_keep reference being found in
// another file that wishes to use its data)
bool isExternal = false;
bool isArray = false;
// If true, will ensure that the arrays size is included in the declaration
bool forceArrayCnt = false;
// If this declaration is an array, how many items make it up?
size_t arrayItemCnt = 0;
// Overrides the brackets for the arrays size with a custom string
std::string arrayItemCntStr = "";
std::vector<segptr_t> references;
// If true, this declaration represents data inside the file which we do not understand it's
// purpose for. It will be outputted as just a byte array.
bool isUnaccounted = false;
// Is this declaration a placeholder that will be replaced later?
bool isPlaceholder = false;
// Does this declaration come straight from the XML?
// If false, this means that the declaration was created by ZAPD when it was parsing the
// resources.
bool declaredInXml = false;
StaticConfig staticConf = StaticConfig::Global;
/// <summary>
/// Creates a regular declaration.
/// </summary>
/// <param name="declAddr">The address inside a binary file this declaration will be in when
/// compiled.</param> <param name="declAlign">The alignment of this declaration in the compiled
/// binary file.</param> <param name="declSize">The size of this declaration when it is compiled
/// to binary data.</param> <param name="declType">The C variable type this declaration will be
/// declared as.</param> <param name="declName">The C variable name this declaration will be
/// declared as.</param> <param name="declBody">The contents of the C variable
/// declaration.</param> <returns></returns>
static Declaration* Create(offset_t declAddr, DeclarationAlignment declAlign, size_t declSize,
const std::string& declType, const std::string& declName,
const std::string& declBody);
/// <summary>
/// Creates an array declaration.
/// </summary>
/// <param name="declAddr">The address inside a binary file this declaration will be in when
/// compiled.</param> <param name="declAlign">The alignment of this declaration in the compiled
/// binary file.</param> <param name="declSize">The size of this declaration when it is compiled
/// to binary data.</param> <param name="declType">The C variable type this declaration will be
/// declared as.</param> <param name="declName">The C variable name this declaration will be
/// declared as.</param> <param name="declBody">The contents of the C variable
/// declaration.</param> <param name="declArrayItemCnt">The number of items in the
/// array.</param> <param name="isDeclExternal">(Optional) Is this declaration from another
/// segment?</param> <returns></returns>
static Declaration* CreateArray(offset_t declAddr, DeclarationAlignment declAlign,
size_t declSize, const std::string& declType,
const std::string& declName, const std::string& declBody,
size_t declArrayItemCnt = 0, bool isDeclExternal = false);
/// <summary>
/// Creates an array declaration who's size in the C code uses a custom string.
/// </summary>
/// <param name="declAddr">The address inside a binary file this declaration will be in when
/// compiled.</param> <param name="declAlign">The alignment of this declaration in the compiled
/// binary file.</param> <param name="declSize">The size of this declaration when it is compiled
/// to binary data.</param> <param name="declType">The C variable type this declaration will be
/// declared as.</param> <param name="declName">The C variable name this declaration will be
/// declared as.</param> <param name="declBody">The contents of the C variable
/// declaration.</param> <param name="declArrayItemCntStr">The string to be put in the C array's
/// size inbetween the brackets.</param> <param name="isDeclExternal">(Optional) Is this
/// declaration from another segment?</param> <returns></returns>
static Declaration* CreateArray(offset_t declAddr, DeclarationAlignment declAlign,
size_t declSize, const std::string& declType,
const std::string& declName, const std::string& declBody,
const std::string& declArrayItemCntStr,
bool isDeclExternal = false);
/// <summary>
/// Creates a declaration who's body uses a #include to include another file
/// </summary>
/// <param name="declAddr">The address inside a binary file this declaration will be in when
/// compiled.</param> <param name="includePath">The path to the file this declaration will be
/// #including.</param> <param name="declSize">The size of this declaration when it is compiled
/// to binary data.</param> <param name="declType">The C variable type this declaration will be
/// declared as.</param> <param name="declName">The C variable name this declaration will be
/// declared as.</param> <param name="defines">(Optional) Any #define's we want to have
/// outputted by this declaration.</param> <returns></returns>
static Declaration* CreateInclude(offset_t declAddr, const std::string& includePath,
size_t declSize, const std::string& declType,
const std::string& declName, const std::string& defines = "");
/// <summary>
/// Creates a placeholder declaration to be replaced later.
/// </summary>
/// <param name="declAddr">The address inside a binary file this declaration will be in when
/// compiled.</param> <param name="declName">The C variable name this declaration will be
/// declared as.</param> <returns></returns>
static Declaration* CreatePlaceholder(offset_t declAddr, const std::string& declName);
~Declaration();
bool IsStatic() const;
// Returns the declaration as C code as it would be in the code file when the body contains the
// needed data
std::string GetNormalDeclarationStr() const;
// Returns the declaration as C code as it would be in the code file when the body #include's
// another file
std::string GetExternalDeclarationStr() const;
// Generates the extern for this item to be placed in header files.
std::string GetExternStr() const;
// Generates any #define's needed
std::string GetDefinesStr() const;
std::string GetStaticForwardDeclarationStr() const;
protected:
Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
const std::string& nBody);
};

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include <atomic>
extern "C" int zapd_main(int argc, char* argv[]);
extern "C" int zapd_report(int argc, char* argv[], std::atomic<size_t>* extractCount, std::atomic<size_t>* totalExtract);
int main(int argc, char* argv[]) {
return zapd_report(argc, argv, nullptr, nullptr);
}

27
ZAPDTR/ZAPD/ExporterSet.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
typedef void (*ExporterSetFunc)(ZFile*);
typedef bool (*ExporterSetFuncBool)(ZFileMode fileMode);
typedef void (*ExporterSetFuncVoid)(int argc, char* argv[], int& i);
typedef void (*ExporterSetFuncVoid2)(const std::string& buildMode, ZFileMode& fileMode);
typedef void (*ExporterSetFuncVoid3)();
typedef void (*ExporterSetFuncVoid4)(tinyxml2::XMLElement* reader);
typedef void (*ExporterSetResSave)(ZResource* res, BinaryWriter& writer);
//processCompilableFunc
class ExporterSet
{
public:
~ExporterSet();
std::map<ZResourceType, ZResourceExporter*> exporters;
ExporterSetFuncVoid parseArgsFunc = nullptr;
ExporterSetFuncVoid2 parseFileModeFunc = nullptr;
ExporterSetFuncBool processFileModeFunc = nullptr;
ExporterSetFunc beginFileFunc = nullptr;
ExporterSetFunc endFileFunc = nullptr;
ExporterSetFuncVoid3 beginXMLFunc = nullptr;
ExporterSetFuncVoid3 endXMLFunc = nullptr;
ExporterSetResSave resSaveFunc = nullptr;
ExporterSetFuncVoid3 endProgramFunc = nullptr;
ExporterSetFuncVoid4 processCompilableFunc = nullptr;
};

View File

16
ZAPDTR/ZAPD/FileWorker.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include "ZFile.h"
class FileWorker
{
public:
std::vector<ZFile*> files;
std::vector<ZFile*> externalFiles;
std::vector<int32_t> segments;
std::vector<ZFile*> segmentFiles;
std::map<int32_t, std::vector<ZFile*>> segmentRefFiles;
};

301
ZAPDTR/ZAPD/GameConfig.cpp Normal file
View File

@@ -0,0 +1,301 @@
#include "GameConfig.h"
#include <functional>
#include <string_view>
#include <unordered_map>
#include "Utils/Directory.h"
#include <Utils/DiskFile.h>
#include "Utils/Path.h"
#include "ZFile.h"
#include "tinyxml2.h"
using ConfigFunc = void (GameConfig::*)(const tinyxml2::XMLElement&);
GameConfig::~GameConfig()
{
for (auto& declPair : segmentRefFiles)
{
for (auto& file : declPair.second)
{
delete file;
}
}
}
void GameConfig::ReadTexturePool(const fs::path& texturePoolXmlPath)
{
tinyxml2::XMLDocument doc;
tinyxml2::XMLError eResult = doc.LoadFile(texturePoolXmlPath.string().c_str());
if (eResult != tinyxml2::XML_SUCCESS)
{
fprintf(stderr, "Warning: Unable to read texture pool XML with error code %i\n", eResult);
return;
}
tinyxml2::XMLNode* root = doc.FirstChild();
if (root == nullptr)
return;
for (tinyxml2::XMLElement* child = root->FirstChildElement(); child != nullptr;
child = child->NextSiblingElement())
{
if (std::string_view(child->Name()) == "Texture")
{
std::string crcStr = child->Attribute("CRC");
fs::path texPath = child->Attribute("Path");
std::string texName;
uint32_t crc = strtoul(crcStr.c_str(), nullptr, 16);
texturePool[crc].path = texPath;
}
}
}
void GameConfig::GenSymbolMap(const fs::path& symbolMapPath)
{
auto symbolLines = DiskFile::ReadAllLines(symbolMapPath);
for (std::string& symbolLine : symbolLines)
{
auto split = StringHelper::Split(symbolLine, " ");
uint32_t addr = strtoul(split[0].c_str(), nullptr, 16);
std::string symbolName = split[1];
symbolMap[addr] = std::move(symbolName);
}
}
void GameConfig::ConfigFunc_SymbolMap(const tinyxml2::XMLElement& element)
{
std::string fileName = element.Attribute("File");
GenSymbolMap(Path::GetDirectoryName(configFilePath) / fileName);
}
void GameConfig::ConfigFunc_ActorList(const tinyxml2::XMLElement& element)
{
std::string fileName = element.Attribute("File");
std::vector<std::string> lines =
DiskFile::ReadAllLines(Path::GetDirectoryName(configFilePath) / fileName);
for (auto& line : lines)
actorList.emplace_back(std::move(line));
}
void GameConfig::ConfigFunc_ObjectList(const tinyxml2::XMLElement& element)
{
std::string fileName = element.Attribute("File");
std::vector<std::string> lines =
DiskFile::ReadAllLines(Path::GetDirectoryName(configFilePath) / fileName);
for (auto& line : lines)
objectList.emplace_back(std::move(line));
}
void GameConfig::ConfigFunc_EntranceList(const tinyxml2::XMLElement& element)
{
std::string fileName = element.Attribute("File");
std::vector<std::string> lines =
DiskFile::ReadAllLines(Path::GetDirectoryName(configFilePath) / fileName);
for (auto& line : lines)
entranceList.emplace_back(std::move(line));
}
void GameConfig::ConfigFunc_specialEntranceList(const tinyxml2::XMLElement& element)
{
std::string fileName = element.Attribute("File");
std::vector<std::string> lines =
DiskFile::ReadAllLines(Path::GetDirectoryName(configFilePath) / fileName);
for (auto& line : lines)
specialEntranceList.emplace_back(std::move(line));
}
void GameConfig::ConfigFunc_TexturePool(const tinyxml2::XMLElement& element)
{
std::string fileName = element.Attribute("File");
ReadTexturePool(Path::GetDirectoryName(configFilePath) / fileName);
}
void GameConfig::ConfigFunc_BGConfig(const tinyxml2::XMLElement& element)
{
bgScreenWidth = element.IntAttribute("ScreenWidth", 320);
bgScreenHeight = element.IntAttribute("ScreenHeight", 240);
useScreenWidthHeightConstants = element.BoolAttribute("UseScreenWidthHeightConstants", true);
}
void GameConfig::ConfigFunc_ExternalXMLFolder(const tinyxml2::XMLElement& element)
{
const char* pathValue = element.Attribute("Path");
if (pathValue == nullptr)
{
throw std::runtime_error(
StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
"\t Missing 'Path' attribute in `ExternalXMLFolder` element.\n"));
}
if (externalXmlFolder != "")
{
throw std::runtime_error(StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
"\t `ExternalXMLFolder` is duplicated.\n"));
}
externalXmlFolder = pathValue;
}
void GameConfig::ConfigFunc_ExternalFile(const tinyxml2::XMLElement& element)
{
const char* xmlPathValue = element.Attribute("XmlPath");
if (xmlPathValue == nullptr)
{
throw std::runtime_error(
StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
"\t Missing 'XmlPath' attribute in `ExternalFile` element.\n"));
}
const char* outPathValue = element.Attribute("OutPath");
if (outPathValue == nullptr)
{
throw std::runtime_error(
StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
"\t Missing 'OutPath' attribute in `ExternalFile` element.\n"));
}
externalFiles.push_back(ExternalFile(fs::path(xmlPathValue), fs::path(outPathValue)));
}
void GameConfig::ConfigFunc_EnumData(const tinyxml2::XMLElement& element)
{
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());
if (eResult != tinyxml2::XML_SUCCESS)
{
throw std::runtime_error("Error: Unable to read enum data.");
}
tinyxml2::XMLNode* root = doc.FirstChild();
if (root == nullptr)
return;
for (tinyxml2::XMLElement* csEnum = root->FirstChildElement(); csEnum != nullptr;
csEnum = csEnum->NextSiblingElement())
{
for (tinyxml2::XMLElement* item = csEnum->FirstChildElement(); item != nullptr;
item = item->NextSiblingElement())
{
std::string enumKey = csEnum->Attribute("Key");
uint16_t itemIndex = atoi(item->Attribute("Index"));
const char* itemID = item->Attribute("ID");
// Common
if (enumKey == "cmd")
enumData.cutsceneCmd[itemIndex] = itemID;
else if (enumKey == "miscType")
enumData.miscType[itemIndex] = itemID;
else if (enumKey == "textType")
enumData.textType[itemIndex] = itemID;
else if (enumKey == "fadeOutSeqPlayer")
enumData.fadeOutSeqPlayer[itemIndex] = itemID;
else if (enumKey == "transitionType")
enumData.transitionType[itemIndex] = itemID;
else if (enumKey == "destination")
enumData.destination[itemIndex] = itemID;
else if (enumKey == "naviQuestHintType")
enumData.naviQuestHintType[itemIndex] = itemID;
else if (enumKey == "ocarinaSongActionId")
enumData.ocarinaSongActionId[itemIndex] = itemID;
else if (enumKey == "seqId")
enumData.seqId[itemIndex] = itemID;
else if (enumKey == "playerCueId")
enumData.playerCueId[itemIndex] = itemID;
// MM
else if (enumKey == "modifySeqType")
enumData.modifySeqType[itemIndex] = itemID;
else if (enumKey == "chooseCreditsSceneType")
enumData.chooseCreditsSceneType[itemIndex] = itemID;
else if (enumKey == "destinationType")
enumData.destinationType[itemIndex] = itemID;
else if (enumKey == "motionBlurType")
enumData.motionBlurType[itemIndex] = itemID;
else if (enumKey == "transitionGeneralType")
enumData.transitionGeneralType[itemIndex] = itemID;
else if (enumKey == "rumbleType")
enumData.rumbleType[itemIndex] = itemID;
else if (enumKey == "spawnFlag")
enumData.spawnFlag[itemIndex] = itemID;
else if (enumKey == "endSfx")
enumData.endSfx[itemIndex] = itemID;
else if (enumKey == "csSplineInterpType")
enumData.interpType[itemIndex] = itemID;
else if (enumKey == "csSplineRelTo")
enumData.relTo[itemIndex] = itemID;
}
}
}
void GameConfig::ReadConfigFile(const fs::path& argConfigFilePath)
{
static const std::unordered_map<std::string, ConfigFunc> ConfigFuncDictionary = {
{"SymbolMap", &GameConfig::ConfigFunc_SymbolMap},
{"ActorList", &GameConfig::ConfigFunc_ActorList},
{"ObjectList", &GameConfig::ConfigFunc_ObjectList},
{"EntranceList", &GameConfig::ConfigFunc_EntranceList},
{"SpecialEntranceList", &GameConfig::ConfigFunc_specialEntranceList},
{"TexturePool", &GameConfig::ConfigFunc_TexturePool},
{"BGConfig", &GameConfig::ConfigFunc_BGConfig},
{"EnumData", &GameConfig::ConfigFunc_EnumData},
{"ExternalXMLFolder", &GameConfig::ConfigFunc_ExternalXMLFolder},
{"ExternalFile", &GameConfig::ConfigFunc_ExternalFile},
};
configFilePath = argConfigFilePath.string();
tinyxml2::XMLDocument doc;
tinyxml2::XMLError eResult = doc.LoadFile(configFilePath.c_str());
if (eResult != tinyxml2::XML_SUCCESS)
{
throw std::runtime_error("Error: Unable to read config file.");
}
tinyxml2::XMLNode* root = doc.FirstChild();
if (root == nullptr)
return;
for (tinyxml2::XMLElement* child = root->FirstChildElement(); child != nullptr;
child = child->NextSiblingElement())
{
auto it = ConfigFuncDictionary.find(child->Name());
if (it == ConfigFuncDictionary.end())
{
fprintf(stderr, "Unsupported configuration variable: %s\n", child->Name());
continue;
}
std::invoke(it->second, *this, *child);
}
}

97
ZAPDTR/ZAPD/GameConfig.h Normal file
View File

@@ -0,0 +1,97 @@
#pragma once
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include "Utils/Directory.h"
#include "tinyxml2.h"
struct TexturePoolEntry
{
fs::path path = ""; // Path to Shared Texture
};
class ExternalFile
{
public:
fs::path xmlPath, outPath;
ExternalFile(fs::path nXmlPath, fs::path nOutPath);
};
// Stores data from the XML file, the integer is the index (via ATOI) and the string is the value
class EnumData
{
public:
// Common
std::map<uint16_t, std::string> cutsceneCmd;
std::map<uint16_t, std::string> miscType;
std::map<uint16_t, std::string> fadeOutSeqPlayer;
std::map<uint16_t, std::string> transitionType;
std::map<uint16_t, std::string> naviQuestHintType;
std::map<uint16_t, std::string> ocarinaSongActionId;
std::map<uint16_t, std::string> seqId;
// OoT
std::map<uint16_t, std::string> textType;
std::map<uint16_t, std::string> destination;
std::map<uint16_t, std::string> playerCueId;
// MM
std::map<uint16_t, std::string> modifySeqType;
std::map<uint16_t, std::string> chooseCreditsSceneType;
std::map<uint16_t, std::string> destinationType;
std::map<uint16_t, std::string> motionBlurType;
std::map<uint16_t, std::string> transitionGeneralType;
std::map<uint16_t, std::string> rumbleType;
std::map<uint8_t, std::string> spawnFlag;
std::map<uint8_t, std::string> endSfx;
std::map<uint8_t, std::string> interpType;
std::map<uint16_t, std::string> relTo;
};
class ZFile;
class GameConfig
{
public:
std::string configFilePath;
std::map<int32_t, std::vector<ZFile*>> segmentRefFiles;
std::map<uint32_t, std::string> symbolMap;
std::vector<std::string> actorList;
std::vector<std::string> objectList;
std::vector<std::string> entranceList;
std::vector<std::string> specialEntranceList;
std::map<uint32_t, TexturePoolEntry> texturePool; // Key = CRC
EnumData enumData;
// ZBackground
uint32_t bgScreenWidth = 320, bgScreenHeight = 240;
bool useScreenWidthHeightConstants = true; // If true, ZBackground's will be declared with
// SCREEN_WIDTH * SCREEN_HEIGHT in the C file
// ExternalFile
fs::path externalXmlFolder;
std::vector<ExternalFile> externalFiles;
GameConfig() = default;
~GameConfig();
void ReadTexturePool(const fs::path& texturePoolXmlPath);
void GenSymbolMap(const fs::path& symbolMapPath);
void ConfigFunc_SymbolMap(const tinyxml2::XMLElement& element);
void ConfigFunc_ActorList(const tinyxml2::XMLElement& element);
void ConfigFunc_ObjectList(const tinyxml2::XMLElement& element);
void ConfigFunc_EntranceList(const tinyxml2::XMLElement& element);
void ConfigFunc_specialEntranceList(const tinyxml2::XMLElement& element);
void ConfigFunc_TexturePool(const tinyxml2::XMLElement& element);
void ConfigFunc_BGConfig(const tinyxml2::XMLElement& element);
void ConfigFunc_ExternalXMLFolder(const tinyxml2::XMLElement& element);
void ConfigFunc_ExternalFile(const tinyxml2::XMLElement& element);
void ConfigFunc_EnumData(const tinyxml2::XMLElement& element);
void ReadConfigFile(const fs::path& configFilePath);
};

363
ZAPDTR/ZAPD/Globals.cpp Normal file
View File

@@ -0,0 +1,363 @@
#include "Globals.h"
#include <algorithm>
#include <string_view>
#include <Utils/DiskFile.h>
#include "Utils/Path.h"
#include "WarningHandler.h"
#include "tinyxml2.h"
Globals* Globals::Instance;
Globals::Globals()
{
Instance = this;
game = ZGame::OOT_RETAIL;
genSourceFile = true;
testMode = false;
profile = false;
useLegacyZDList = false;
useExternalResources = true;
singleThreaded = false;
verbosity = VerbosityLevel::VERBOSITY_SILENT;
outputPath = Directory::GetCurrentDirectory();
}
Globals::~Globals()
{
for (const auto& w : workerData)
{
delete w.second;
}
if (rom != nullptr)
{
delete rom;
}
}
void Globals::AddSegment(int32_t segment, ZFile* file, int workerID)
{
if (!Globals::Instance->singleThreaded)
{
auto worker = workerData[workerID];
if (std::find(worker->segments.begin(), worker->segments.end(), segment) ==
worker->segments.end())
{
worker->segments.push_back(segment);
worker->segmentFiles.push_back(file);
}
if (worker->segmentRefFiles.find(segment) == worker->segmentRefFiles.end())
worker->segmentRefFiles[segment] = std::vector<ZFile*>();
worker->segmentRefFiles[segment].push_back(file);
}
else
{
if (std::find(segments.begin(), segments.end(), segment) == segments.end())
{
segments.push_back(segment);
segmentFiles.push_back(file);
}
if (cfg.segmentRefFiles.find(segment) == cfg.segmentRefFiles.end())
cfg.segmentRefFiles[segment] = std::vector<ZFile*>();
cfg.segmentRefFiles[segment].push_back(file);
}
}
bool Globals::HasSegment(int32_t segment, int workerID)
{
if (!Globals::Instance->singleThreaded)
return std::find(workerData[workerID]->segments.begin(),
workerData[workerID]->segments.end(), segment) != workerData[workerID]->segments.end();
else
return std::find(segments.begin(), segments.end(), segment) != segments.end();
}
ZFile* Globals::GetSegment(int32_t segment, int workerID)
{
if (!Globals::Instance->singleThreaded)
{
if (HasSegment(segment, workerID))
{
int idx = std::find(workerData[workerID]->segments.begin(),
workerData[workerID]->segments.end(), segment) -
workerData[workerID]->segments.begin();
return workerData[workerID]->segmentFiles[idx];
}
else
return nullptr;
}
else
{
if (HasSegment(segment, workerID))
{
int idx = std::find(segments.begin(), segments.end(), segment) - segments.begin();
return segmentFiles[idx];
}
else
return nullptr;
}
}
std::map<int32_t, std::vector<ZFile*>> Globals::GetSegmentRefFiles(int workerID)
{
if (!Globals::Instance->singleThreaded)
return workerData[workerID]->segmentRefFiles;
else
return cfg.segmentRefFiles;
}
void Globals::AddFile(ZFile* file, int workerID)
{
if (singleThreaded)
files.push_back(file);
else
workerData[workerID]->files.push_back(file);
}
void Globals::AddExternalFile(ZFile* file, int workerID)
{
if (singleThreaded)
externalFiles.push_back(file);
else
workerData[workerID]->externalFiles.push_back(file);
}
void Globals::BuildAssetTexture(const fs::path& pngFilePath, TextureType texType, const fs::path& outPath)
{
std::string name = outPath.stem().string();
ZTexture tex(nullptr);
if (name.find("u32") != std::string::npos)
tex.dWordAligned = false;
tex.FromPNG(pngFilePath.string(), texType);
std::string cfgPath = StringHelper::Split(pngFilePath.string(), ".")[0] + ".cfg";
if (DiskFile::Exists(cfgPath))
name = DiskFile::ReadAllText(cfgPath);
std::string src = tex.GetBodySourceCode();
DiskFile::WriteAllBytes(outPath.string(), src.c_str(), src.size());
}
std::map<std::string, ExporterSet*>& Globals::GetExporterMap()
{
static std::map<std::string, ExporterSet*> exporters;
return exporters;
}
void Globals::AddExporter(std::string exporterName, ExporterSet* exporterSet)
{
auto& exporters = GetExporterMap();
exporters[exporterName] = exporterSet;
}
ZResourceExporter* Globals::GetExporter(ZResourceType resType)
{
auto& exporters = GetExporterMap();
if (currentExporter != "" && exporters[currentExporter]->exporters.find(resType) !=
exporters[currentExporter]->exporters.end())
return exporters[currentExporter]->exporters[resType];
else
return nullptr;
}
ExporterSet* Globals::GetExporterSet()
{
auto& exporters = GetExporterMap();
if (currentExporter != "")
return exporters[currentExporter];
else
return nullptr;
}
std::vector<uint8_t> Globals::GetBaseromFile(std::string fileName)
{
if (fileMode == ZFileMode::ExtractDirectory)
{
if (StringHelper::Contains(fileName, "baserom/"))
fileName = StringHelper::Split(fileName, "baserom/")[1];
return rom->GetFile(fileName);
}
else
return DiskFile::ReadAllBytes(fileName);
}
bool Globals::GetSegmentedPtrName(segptr_t segAddress, ZFile* currentFile,
const std::string& expectedType, std::string& declName,
int workerID, bool warnIfNotFound)
{
if (segAddress == SEGMENTED_NULL)
{
declName = "NULL";
return true;
}
uint8_t segment = GETSEGNUM(segAddress);
uint32_t offset = Seg2Filespace(segAddress, currentFile->baseAddress);
ZSymbol* sym;
sym = currentFile->GetSymbolResource(offset);
if (sym != nullptr)
{
if (expectedType == "" || expectedType == sym->GetSourceTypeName())
{
declName = sym->GetName();
return true;
}
}
sym = currentFile->GetSymbolResource(segAddress);
if (sym != nullptr)
{
if (expectedType == "" || expectedType == sym->GetSourceTypeName())
{
declName = sym->GetName();
return true;
}
}
if (currentFile->IsSegmentedInFilespaceRange(segAddress))
{
if (currentFile->GetDeclarationPtrName(segAddress, expectedType, declName))
return true;
}
else if (HasSegment(segment, workerID))
{
// OTRTODO: Multithreading
auto segs = GetSegmentRefFiles(workerID);
for (auto file : segs[segment])
{
offset = Seg2Filespace(segAddress, file->baseAddress);
sym = file->GetSymbolResource(offset);
if (sym != nullptr)
{
if (expectedType == "" || expectedType == sym->GetSourceTypeName())
{
declName = sym->GetName();
return true;
}
}
sym = file->GetSymbolResource(segAddress);
if (sym != nullptr)
{
if (expectedType == "" || expectedType == sym->GetSourceTypeName())
{
declName = sym->GetName();
return true;
}
}
if (file->IsSegmentedInFilespaceRange(segAddress))
{
if (file->GetDeclarationPtrName(segAddress, expectedType, declName))
return true;
}
}
}
const auto& symbolFromMap = Globals::Instance->cfg.symbolMap.find(segAddress);
if (symbolFromMap != Globals::Instance->cfg.symbolMap.end())
{
declName = "&" + symbolFromMap->second;
return true;
}
declName = StringHelper::Sprintf("0x%08X", segAddress);
if (warnIfNotFound)
{
WarnHardcodedPointer(segAddress, currentFile, nullptr, -1);
}
return false;
}
bool Globals::GetSegmentedArrayIndexedName(segptr_t segAddress, size_t elementSize,
ZFile* currentFile, const std::string& expectedType,
std::string& declName, int workerID, bool warnIfNotFound)
{
if (segAddress == SEGMENTED_NULL)
{
declName = "NULL";
return true;
}
uint8_t segment = GETSEGNUM(segAddress);
if (currentFile->IsSegmentedInFilespaceRange(segAddress))
{
bool addressFound = currentFile->GetDeclarationArrayIndexedName(segAddress, elementSize,
expectedType, declName);
if (addressFound)
return true;
}
else if (HasSegment(segment, workerID))
{
// OTRTODO: Multithreading
auto segs = GetSegmentRefFiles(workerID);
for (auto file : segs[segment])
{
if (file->IsSegmentedInFilespaceRange(segAddress))
{
bool addressFound = file->GetDeclarationArrayIndexedName(segAddress, elementSize,
expectedType, declName);
if (addressFound)
return true;
}
}
}
declName = StringHelper::Sprintf("0x%08X", segAddress);
if (warnIfNotFound)
{
WarnHardcodedPointer(segAddress, currentFile, nullptr, -1);
}
return false;
}
void Globals::WarnHardcodedPointer(segptr_t segAddress, ZFile* currentFile, ZResource* res,
offset_t currentOffset)
{
uint8_t segment = GETSEGNUM(segAddress);
if ((segment >= 2 && segment <= 6) || segment == 0x80)
{
std::string errorHeader = "A hardcoded pointer was found";
std::string errorBody = StringHelper::Sprintf("Pointer: 0x%08X", segAddress);
HANDLE_WARNING_RESOURCE(WarningType::HardcodedPointer, currentFile, res, currentOffset,
errorHeader, errorBody);
}
else
{
std::string errorHeader = "A general purpose hardcoded pointer was found";
std::string errorBody = StringHelper::Sprintf("Pointer: 0x%08X", segAddress);
HANDLE_WARNING_RESOURCE(WarningType::HardcodedGenericPointer, currentFile, res,
currentOffset, errorHeader, errorBody);
}
}
ExternalFile::ExternalFile(fs::path nXmlPath, fs::path nOutPath)
: xmlPath{nXmlPath}, outPath{nOutPath}
{
}
ExporterSet::~ExporterSet()
{
for (auto& it : exporters)
{
delete it.second;
}
}

103
ZAPDTR/ZAPD/Globals.h Normal file
View File

@@ -0,0 +1,103 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include "GameConfig.h"
#include "ZFile.h"
#include "ZRom.h"
#include "FileWorker.h"
#include "ExporterSet.h"
class ZRoom;
enum class VerbosityLevel
{
VERBOSITY_SILENT,
VERBOSITY_INFO,
VERBOSITY_DEBUG
};
enum class XMLModeShift : int
{
SoundFont,
Sample,
Sequence,
// Add more as more assets support XML exporting.
};
class Globals
{
public:
static Globals* Instance;
bool genSourceFile; // Used for extraction
bool useExternalResources;
bool testMode; // Enables certain experimental features
bool outputCrc = false;
bool profile; // Measure performance of certain operations
bool useLegacyZDList;
bool singleThreaded;
VerbosityLevel verbosity; // ZAPD outputs additional information
ZFileMode fileMode = ZFileMode::Invalid;
fs::path baseRomPath, inputPath, outputPath, sourceOutputPath, cfgPath, fileListPath;
TextureType texType;
ZGame game;
GameConfig cfg;
bool verboseUnaccounted = false;
bool gccCompat = false;
bool forceStatic = false;
bool forceUnaccountedStatic = false;
bool otrMode = true;
bool buildRawTexture = false;
bool onlyGenCustomOtr = false;
uint32_t xmlExtractModes = 0;
ZRom* rom = nullptr;
std::vector<ZFile*> files;
std::vector<ZFile*> externalFiles;
std::vector<int32_t> segments;
std::vector<ZFile*> segmentFiles;
std::map<int, FileWorker*> workerData;
std::string currentExporter;
static std::map<std::string, ExporterSet*>& GetExporterMap();
static void AddExporter(std::string exporterName, ExporterSet* exporterSet);
Globals();
~Globals();
void AddSegment(int32_t segment, ZFile* file, int workerID);
bool HasSegment(int32_t segment, int workerID);
ZFile* GetSegment(int32_t segment, int workerID);
std::map<int32_t, std::vector<ZFile*>> GetSegmentRefFiles(int workerID);
void AddFile(ZFile* file, int workerID);
void AddExternalFile(ZFile* file, int workerID);
void BuildAssetTexture(const fs::path& pngFilePath, TextureType texType, const fs::path& outPath);
ZResourceExporter* GetExporter(ZResourceType resType);
ExporterSet* GetExporterSet();
std::vector<uint8_t> GetBaseromFile(std::string fileName);
/**
* Search in every file (and the symbol map) for the `segAddress` passed as parameter.
* If the segment of `currentFile` is the same segment of `segAddress`, then that file will be
* used only, otherwise, the search will be performed in every other file.
* The name of that variable will be stored in the `declName` parameter.
* Returns `true` if the address is found. `false` otherwise,
* in which case `declName` will be set to the address formatted as a pointer.
*/
bool GetSegmentedPtrName(segptr_t segAddress, ZFile* currentFile,
const std::string& expectedType, std::string& declName,
int workerID, bool warnIfNotFound = true);
bool GetSegmentedArrayIndexedName(segptr_t segAddress, size_t elementSize, ZFile* currentFile,
const std::string& expectedType, std::string& declName,
int workerID, bool warnIfNotFound = true);
// TODO: consider moving to another place
void WarnHardcodedPointer(segptr_t segAddress, ZFile* currentFile, ZResource* res,
offset_t currentOffset);
};

View File

@@ -0,0 +1,507 @@
#define _CRT_SECURE_NO_WARNINGS
#include "ImageBackend.h"
#include <cassert>
#include <cstdlib>
#include <png.h>
#include <stdexcept>
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
/* ImageBackend */
ImageBackend::~ImageBackend()
{
FreeImageData();
}
void ImageBackend::ReadPng(const char* filename)
{
FreeImageData();
FILE* fp = fopen(filename, "rb");
if (fp == nullptr)
{
std::string errorHeader = StringHelper::Sprintf("could not open file '%s'", filename);
HANDLE_ERROR(WarningType::InvalidPNG, errorHeader, "");
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (png == nullptr)
{
HANDLE_ERROR(WarningType::InvalidPNG, "could not create png struct", "");
}
png_infop info = png_create_info_struct(png);
if (info == nullptr)
{
HANDLE_ERROR(WarningType::InvalidPNG, "could not create png info", "");
}
if (setjmp(png_jmpbuf(png)))
{
// TODO: better warning explanation
HANDLE_ERROR(WarningType::InvalidPNG, "setjmp(png_jmpbuf(png))", "");
}
png_init_io(png, fp);
png_read_info(png, info);
width = png_get_image_width(png, info);
height = png_get_image_height(png, info);
colorType = png_get_color_type(png, info);
bitDepth = png_get_bit_depth(png, info);
#ifdef TEXTURE_DEBUG
printf("Width: %u\n", width);
printf("Height: %u\n", height);
printf("ColorType: ");
switch (colorType)
{
case PNG_COLOR_TYPE_RGBA:
printf("PNG_COLOR_TYPE_RGBA\n");
break;
case PNG_COLOR_TYPE_RGB:
printf("PNG_COLOR_TYPE_RGB\n");
break;
case PNG_COLOR_TYPE_PALETTE:
printf("PNG_COLOR_TYPE_PALETTE\n");
break;
default:
printf("%u\n", colorType);
break;
}
printf("BitDepth: %u\n", bitDepth);
printf("\n");
#endif
// Read any color_type into 8bit depth, RGBA format.
// See http://www.libpng.org/pub/png/libpng-manual.txt
if (bitDepth == 16)
png_set_strip_16(png);
if (colorType == PNG_COLOR_TYPE_PALETTE)
{
// png_set_palette_to_rgb(png);
isColorIndexed = true;
}
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
png_set_expand_gray_1_2_4_to_8(png);
/*if (png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);*/
// These color_type don't have an alpha channel then fill it with 0xff.
/*if(*color_type == PNG_COLOR_TYPE_RGB ||
*color_type == PNG_COLOR_TYPE_GRAY ||
*color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);*/
if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
size_t rowBytes = png_get_rowbytes(png, info);
pixelMatrix = (uint8_t**)malloc(sizeof(uint8_t*) * height);
for (size_t y = 0; y < height; y++)
{
pixelMatrix[y] = (uint8_t*)malloc(rowBytes);
}
png_read_image(png, pixelMatrix);
#ifdef TEXTURE_DEBUG
printf("rowBytes: %zu\n", rowBytes);
size_t bytePerPixel = GetBytesPerPixel();
printf("imgData\n");
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
for (size_t z = 0; z < bytePerPixel; z++)
{
printf("%02X ", pixelMatrix[y][x * bytePerPixel + z]);
}
printf(" ");
}
printf("\n");
}
printf("\n");
#endif
fclose(fp);
png_destroy_read_struct(&png, &info, nullptr);
hasImageData = true;
}
void ImageBackend::ReadPng(const fs::path& filename)
{
ReadPng(filename.string().c_str());
}
void ImageBackend::WritePng(const char* filename)
{
assert(hasImageData);
FILE* fp = fopen(filename, "wb");
if (fp == nullptr)
{
std::string errorHeader =
StringHelper::Sprintf("could not open file '%s' in write mode", filename);
HANDLE_ERROR(WarningType::InvalidPNG, errorHeader, "");
}
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (png == nullptr)
{
HANDLE_ERROR(WarningType::InvalidPNG, "could not create png struct", "");
}
png_infop info = png_create_info_struct(png);
if (info == nullptr)
{
HANDLE_ERROR(WarningType::InvalidPNG, "could not create png info", "");
}
if (setjmp(png_jmpbuf(png)))
{
// TODO: better warning description
HANDLE_ERROR(WarningType::InvalidPNG, "setjmp(png_jmpbuf(png))", "");
}
png_init_io(png, fp);
png_set_IHDR(png, info, width, height,
bitDepth, // 8,
colorType, // PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
if (isColorIndexed)
{
png_set_PLTE(png, info, static_cast<png_color*>(colorPalette), paletteSize);
#ifdef TEXTURE_DEBUG
printf("palette\n");
png_color* aux = (png_color*)colorPalette;
for (size_t y = 0; y < paletteSize; y++)
{
printf("#%02X%02X%02X ", aux[y].red, aux[y].green, aux[y].blue);
if ((y + 1) % 8 == 0)
printf("\n");
}
printf("\n");
#endif
png_set_tRNS(png, info, alphaPalette, paletteSize, nullptr);
}
png_write_info(png, info);
// To remove the alpha channel for PNG_COLOR_TYPE_RGB format,
// Use png_set_filler().
// png_set_filler(png, 0, PNG_FILLER_AFTER);
#ifdef TEXTURE_DEBUG
size_t bytePerPixel = GetBytesPerPixel();
printf("imgData\n");
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width * bytePerPixel; x++)
{
printf("%02X ", pixelMatrix[y][x]);
}
printf("\n");
}
printf("\n");
#endif
png_write_image(png, pixelMatrix);
png_write_end(png, nullptr);
fclose(fp);
png_destroy_write_struct(&png, &info);
}
void ImageBackend::WritePng(const fs::path& filename)
{
// Note: The .string() is necessary for MSVC, due to the implementation of std::filesystem
// differing from GCC. Do not remove!
WritePng(filename.string().c_str());
}
void ImageBackend::SetTextureData(const std::vector<std::vector<RGBAPixel>>& texData,
uint32_t nWidth, uint32_t nHeight, uint8_t nColorType,
uint8_t nBitDepth)
{
FreeImageData();
width = nWidth;
height = nHeight;
colorType = nColorType;
bitDepth = nBitDepth;
size_t bytePerPixel = GetBytesPerPixel();
pixelMatrix = static_cast<uint8_t**>(malloc(sizeof(uint8_t*) * height));
for (size_t y = 0; y < height; y++)
{
pixelMatrix[y] = static_cast<uint8_t*>(malloc(sizeof(uint8_t*) * width * bytePerPixel));
for (size_t x = 0; x < width; x++)
{
pixelMatrix[y][x * bytePerPixel + 0] = texData.at(y).at(x).r;
pixelMatrix[y][x * bytePerPixel + 1] = texData.at(y).at(x).g;
pixelMatrix[y][x * bytePerPixel + 2] = texData.at(y).at(x).b;
if (colorType == PNG_COLOR_TYPE_RGBA)
pixelMatrix[y][x * bytePerPixel + 3] = texData.at(y).at(x).a;
}
}
hasImageData = true;
}
void ImageBackend::InitEmptyRGBImage(uint32_t nWidth, uint32_t nHeight, bool alpha)
{
FreeImageData();
width = nWidth;
height = nHeight;
colorType = PNG_COLOR_TYPE_RGB;
if (alpha)
colorType = PNG_COLOR_TYPE_RGBA;
bitDepth = 8; // nBitDepth;
size_t bytePerPixel = GetBytesPerPixel();
pixelMatrix = static_cast<uint8_t**>(malloc(sizeof(uint8_t*) * height));
for (size_t y = 0; y < height; y++)
{
pixelMatrix[y] = static_cast<uint8_t*>(calloc(width * bytePerPixel, sizeof(uint8_t*)));
}
hasImageData = true;
}
void ImageBackend::InitEmptyPaletteImage(uint32_t nWidth, uint32_t nHeight)
{
FreeImageData();
width = nWidth;
height = nHeight;
colorType = PNG_COLOR_TYPE_PALETTE;
bitDepth = 8;
size_t bytePerPixel = GetBytesPerPixel();
pixelMatrix = (uint8_t**)malloc(sizeof(uint8_t*) * height);
for (size_t y = 0; y < height; y++)
{
pixelMatrix[y] = static_cast<uint8_t*>(calloc(width * bytePerPixel, sizeof(uint8_t*)));
}
colorPalette = calloc(paletteSize, sizeof(png_color));
alphaPalette = static_cast<uint8_t*>(calloc(paletteSize, sizeof(uint8_t)));
hasImageData = true;
isColorIndexed = true;
}
RGBAPixel ImageBackend::GetPixel(size_t y, size_t x) const
{
assert(y < height);
assert(x < width);
assert(!isColorIndexed);
RGBAPixel pixel;
size_t bytePerPixel = GetBytesPerPixel();
pixel.r = pixelMatrix[y][x * bytePerPixel + 0];
pixel.g = pixelMatrix[y][x * bytePerPixel + 1];
pixel.b = pixelMatrix[y][x * bytePerPixel + 2];
if (colorType == PNG_COLOR_TYPE_RGBA)
pixel.a = pixelMatrix[y][x * bytePerPixel + 3];
return pixel;
}
uint8_t ImageBackend::GetIndexedPixel(size_t y, size_t x) const
{
assert(y < height);
assert(x < width);
assert(isColorIndexed);
return pixelMatrix[y][x];
}
void ImageBackend::SetRGBPixel(size_t y, size_t x, uint8_t nR, uint8_t nG, uint8_t nB, uint8_t nA)
{
assert(hasImageData);
assert(y < height);
assert(x < width);
size_t bytePerPixel = GetBytesPerPixel();
pixelMatrix[y][x * bytePerPixel + 0] = nR;
pixelMatrix[y][x * bytePerPixel + 1] = nG;
pixelMatrix[y][x * bytePerPixel + 2] = nB;
if (colorType == PNG_COLOR_TYPE_RGBA)
pixelMatrix[y][x * bytePerPixel + 3] = nA;
}
void ImageBackend::SetGrayscalePixel(size_t y, size_t x, uint8_t grayscale, uint8_t alpha)
{
assert(hasImageData);
assert(y < height);
assert(x < width);
size_t bytePerPixel = GetBytesPerPixel();
pixelMatrix[y][x * bytePerPixel + 0] = grayscale;
pixelMatrix[y][x * bytePerPixel + 1] = grayscale;
pixelMatrix[y][x * bytePerPixel + 2] = grayscale;
if (colorType == PNG_COLOR_TYPE_RGBA)
pixelMatrix[y][x * bytePerPixel + 3] = alpha;
}
void ImageBackend::SetIndexedPixel(size_t y, size_t x, uint8_t index, uint8_t grayscale)
{
assert(hasImageData);
assert(y < height);
assert(x < width);
size_t bytePerPixel = GetBytesPerPixel();
pixelMatrix[y][x * bytePerPixel + 0] = index;
assert(index < paletteSize);
png_color* pal = static_cast<png_color*>(colorPalette);
pal[index].red = grayscale;
pal[index].green = grayscale;
pal[index].blue = grayscale;
alphaPalette[index] = 255;
}
void ImageBackend::SetPaletteIndex(size_t index, uint8_t nR, uint8_t nG, uint8_t nB, uint8_t nA)
{
assert(isColorIndexed);
assert(index < paletteSize);
png_color* pal = static_cast<png_color*>(colorPalette);
pal[index].red = nR;
pal[index].green = nG;
pal[index].blue = nB;
alphaPalette[index] = nA;
}
void ImageBackend::SetPalette(const ImageBackend& pal, uint32_t offset)
{
assert(isColorIndexed);
size_t bytePerPixel = pal.GetBytesPerPixel();
for (size_t y = 0; y < pal.height; y++)
{
for (size_t x = 0; x < pal.width; x++)
{
size_t index = y * pal.width + x;
if (index >= paletteSize)
{
/*
* Some TLUTs are bigger than 256 colors.
* For those cases, we will only take the first 256
* to colorize this CI texture.
*/
return;
}
uint8_t r = pal.pixelMatrix[y][x * bytePerPixel + 0];
uint8_t g = pal.pixelMatrix[y][x * bytePerPixel + 1];
uint8_t b = pal.pixelMatrix[y][x * bytePerPixel + 2];
uint8_t a = pal.pixelMatrix[y][x * bytePerPixel + 3];
SetPaletteIndex(index + offset, r, g, b, a);
}
}
}
uint32_t ImageBackend::GetWidth() const
{
return width;
}
uint32_t ImageBackend::GetHeight() const
{
return height;
}
uint8_t ImageBackend::GetColorType() const
{
return colorType;
}
uint8_t ImageBackend::GetBitDepth() const
{
return bitDepth;
}
double ImageBackend::GetBytesPerPixel() const
{
switch (colorType)
{
case PNG_COLOR_TYPE_RGBA:
return 4 * bitDepth / 8;
case PNG_COLOR_TYPE_RGB:
return 3 * bitDepth / 8;
case PNG_COLOR_TYPE_PALETTE:
return 1 * bitDepth / 8;
default:
HANDLE_ERROR(WarningType::InvalidPNG, "invalid color type", "");
}
}
void ImageBackend::FreeImageData()
{
if (hasImageData)
{
for (size_t y = 0; y < height; y++)
free(pixelMatrix[y]);
free(pixelMatrix);
pixelMatrix = nullptr;
}
if (isColorIndexed)
{
free(colorPalette);
free(alphaPalette);
colorPalette = nullptr;
alphaPalette = nullptr;
isColorIndexed = false;
}
hasImageData = false;
}
/* RGBAPixel */
void RGBAPixel::SetRGBA(uint8_t nR, uint8_t nG, uint8_t nB, uint8_t nA)
{
r = nR;
g = nG;
b = nB;
a = nA;
}
void RGBAPixel::SetGrayscale(uint8_t grayscale, uint8_t alpha)
{
r = grayscale;
g = grayscale;
b = grayscale;
a = alpha;
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include <cstdint>
#include <vector>
#include "Utils/Directory.h"
class RGBAPixel
{
public:
RGBAPixel() = default;
void SetRGBA(uint8_t nR, uint8_t nG, uint8_t nB, uint8_t nA);
void SetGrayscale(uint8_t grayscale, uint8_t alpha = 0);
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
uint8_t a = 0;
};
class ImageBackend
{
public:
ImageBackend() = default;
~ImageBackend();
void ReadPng(const char* filename);
void ReadPng(const fs::path& filename);
void WritePng(const char* filename);
void WritePng(const fs::path& filename);
void SetTextureData(const std::vector<std::vector<RGBAPixel>>& texData, uint32_t nWidth,
uint32_t nHeight, uint8_t nColorType, uint8_t nBitDepth);
void InitEmptyRGBImage(uint32_t nWidth, uint32_t nHeight, bool alpha);
void InitEmptyPaletteImage(uint32_t nWidth, uint32_t nHeight);
RGBAPixel GetPixel(size_t y, size_t x) const;
uint8_t GetIndexedPixel(size_t y, size_t x) const;
void SetRGBPixel(size_t y, size_t x, uint8_t nR, uint8_t nG, uint8_t nB, uint8_t nA = 0);
void SetGrayscalePixel(size_t y, size_t x, uint8_t grayscale, uint8_t alpha = 0);
void SetIndexedPixel(size_t y, size_t x, uint8_t index, uint8_t grayscale);
void SetIndexedPixel(size_t y, size_t x, uint8_t index, RGBAPixel pixel);
void SetPaletteIndex(size_t index, uint8_t nR, uint8_t nG, uint8_t nB, uint8_t nA);
void SetPalette(const ImageBackend& pal, uint32_t offset = 0);
uint32_t GetWidth() const;
uint32_t GetHeight() const;
uint8_t GetColorType() const;
uint8_t GetBitDepth() const;
protected:
uint8_t** pixelMatrix = nullptr; // height * [width * bytePerPixel]
void* colorPalette = nullptr;
uint8_t* alphaPalette = nullptr;
size_t paletteSize = 16 * 16;
uint32_t width = 0;
uint32_t height = 0;
uint8_t colorType = 0;
uint8_t bitDepth = 0;
bool hasImageData = false;
bool isColorIndexed = false;
double GetBytesPerPixel() const;
void FreeImageData();
};

756
ZAPDTR/ZAPD/Main.cpp Normal file
View File

@@ -0,0 +1,756 @@
#include "Globals.h"
#include <atomic>
#include <Utils/DiskFile.h>
#include <Utils/Path.h>
#include <Utils/Directory.h>
#include "WarningHandler.h"
// Linker Hacks Begin
#include "ZAnimation.h"
ZNormalAnimation nAnim(nullptr);
ZCurveAnimation cAnim(nullptr);
ZLinkAnimation lAnim(nullptr);
ZLegacyAnimation lAnim2(nullptr);
#include "ZArray.h"
ZArray arr(nullptr);
#include "ZAudio.h"
ZAudio audio(nullptr);
#include "ZBackground.h"
ZBackground back(nullptr);
#include "ZBlob.h"
ZBlob blob(nullptr);
#include "ZCollision.h"
ZCollisionHeader colHeader(nullptr);
#include "ZCutscene.h"
ZCutscene cs(nullptr);
#include "ZLimb.h"
ZLimb limb(nullptr);
#include "ZMtx.h"
ZMtx mtx(nullptr);
#include "ZPath.h"
ZPath path(nullptr);
#include "ZPlayerAnimationData.h"
ZPlayerAnimationData pAnimData(nullptr);
#include "ZScalar.h"
ZScalar scalar(nullptr);
#include "ZSkeleton.h"
ZLimbTable limbTbl(nullptr);
ZSkeleton skel(nullptr);
#include "ZString.h"
ZString str(nullptr);
#include "ZSymbol.h"
ZSymbol sym(nullptr);
#include "ZText.h"
ZText txt(nullptr);
#include "ZTextMM.h"
ZTextMM txtMM(nullptr);
#include "ZTexture.h"
ZTexture tex(nullptr);
#include "ZVector.h"
ZVector vec(nullptr);
#include "ZVtx.h"
ZVtx vtx(nullptr);
#include "ZRoom/ZRoom.h"
ZRoom room(nullptr);
#include "ZPointer.h"
ZPointer pointer(nullptr);
#include "ZCKeyFrame.h"
ZKeyFrameSkel kfSKel(nullptr);
#include "ZCkeyFrameAnim.h"
ZKeyFrameAnim kfAnim(nullptr);
// Linker Hacks End
#include "ZFile.h"
#include "ZTexture.h"
#include <functional>
#include "CrashHandler.h"
#include <string>
#include <string_view>
#include "tinyxml2.h"
#include <ctpl_stl.h>
const char gBuildHash[] = "";
using ArgFunc = void (*)(int&, char**);
void Arg_SetOutputPath(int& i, char* argv[]);
void Arg_SetInputPath(int& i, char* argv[]);
void Arg_SetBaseromPath(int& i, char* argv[]);
void Arg_SetSourceOutputPath(int& i, char* argv[]);
void Arg_GenerateSourceFile(int& i, char* argv[]);
void Arg_TestMode(int& i, char* argv[]);
void Arg_LegacyDList(int& i, char* argv[]);
void Arg_EnableProfiling(int& i, char* argv[]);
void Arg_UseExternalResources(int& i, char* argv[]);
void Arg_SetTextureType(int& i, char* argv[]);
void Arg_ReadConfigFile(int& i, char* argv[]);
void Arg_EnableErrorHandler(int& i, char* argv[]);
void Arg_SetVerbosity(int& i, char* argv[]);
void Arg_VerboseUnaccounted(int& i, char* argv[]);
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_SetFileListPath(int& i, char* argv[]);
void Arg_SetBuildRawTexture(int& i, char* argv[]);
void Arg_SetNoRomMode(int& i, char* argv[]);
void Arg_SetXMLMode(int& i, char* argv[]);
int main(int argc, char* argv[]);
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
ZFileMode fileMode, int workerID);
void ParseArgs(int& argc, char* argv[]);
void BuildAssetTexture(const fs::path& pngFilePath, TextureType texType, const fs::path& outPath);
void BuildAssetBackground(const fs::path& imageFilePath, const fs::path& outPath);
void BuildAssetBlob(const fs::path& blobFilePath, const fs::path& outPath);
ZFileMode ParseFileMode(const std::string& buildMode, ExporterSet* exporterSet);
int HandleExtract(ZFileMode fileMode, ExporterSet* exporterSet, std::atomic<size_t>* extractCount = nullptr, std::atomic<size_t>* totalExtract = nullptr);
int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileMode fileMode);
std::atomic<unsigned int> numWorkersLeft = 0;
extern const char gBuildHash[];
extern void ImportExporters();
extern "C" int zapd_report(int argc, char* argv[], std::atomic<size_t>* extractCount, std::atomic<size_t>* totalExtract)
{
int returnCode = 0;
if (argc < 2)
{
printf("ZAPD.out (%s) [mode (btex/bovl/bsf/bblb/bmdlintr/bamnintr/e)] ...\n", gBuildHash);
return 1;
}
Globals* g = new Globals();
WarningHandler::Init(argc, argv);
for (int i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "--version"))
{
printf("ZAPD.out %s\n", gBuildHash);
return 0;
}
else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
{
printf("Congratulations!\n");
printf("You just found the (unimplemented and undocumented) ZAPD's help message.\n");
printf("Feel free to implement it if you want :D\n");
WarningHandler::PrintHelp();
return 0;
}
}
ParseArgs(argc, argv);
// Parse File Mode
ExporterSet* exporterSet = Globals::Instance->GetExporterSet();
// We've parsed through our commands once. If an exporter exists, it's been set by now.
// Now we'll parse through them again but pass them on to our exporter if one is available.
if (exporterSet != nullptr && exporterSet->parseArgsFunc != nullptr) {
for (int32_t i = 2; i < argc; i++) {
exporterSet->parseArgsFunc(argc, argv, i);
}
}
if (Globals::Instance->onlyGenCustomOtr) {
if (exporterSet != nullptr) {
exporterSet->endProgramFunc();
} else {
printf("Error: No exporter set, unable to make custom otr.\n");
}
delete g;
return 0;
}
std::string buildMode = argv[1];
ZFileMode fileMode = ParseFileMode(buildMode, exporterSet);
if (fileMode == ZFileMode::Invalid)
{
printf("Error: Invalid file mode '%s'\n", buildMode.c_str());
return 1;
}
Globals::Instance->fileMode = fileMode;
if (fileMode == ZFileMode::ExtractDirectory)
Globals::Instance->rom = new ZRom(Globals::Instance->baseRomPath.string());
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO)
printf("ZAPD: Zelda Asset Processor For Decomp: %s\n", gBuildHash);
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG)
WarningHandler::PrintWarningsDebugInfo();
if (fileMode == ZFileMode::Extract || fileMode == ZFileMode::BuildSourceFile || fileMode == ZFileMode::ExtractDirectory)
returnCode = HandleExtract(fileMode, exporterSet, extractCount, totalExtract);
else if (fileMode == ZFileMode::BuildTexture)
BuildAssetTexture(Globals::Instance->inputPath, Globals::Instance->texType,
Globals::Instance->outputPath);
else if (fileMode == ZFileMode::BuildBackground)
BuildAssetBackground(Globals::Instance->inputPath, Globals::Instance->outputPath);
else if (fileMode == ZFileMode::BuildBlob)
BuildAssetBlob(Globals::Instance->inputPath, Globals::Instance->outputPath);
if (exporterSet != nullptr && exporterSet->endProgramFunc != nullptr)
exporterSet->endProgramFunc();
delete g;
return returnCode;
}
extern "C" int zapd_main(int argc, char* argv[]) {
return zapd_report(argc, argv, nullptr, nullptr);
}
int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileMode fileMode)
{
bool parseSuccessful;
printf("(%i / %i): %s\n", (workerID + 1), fileListSize, fileListItem.c_str());
for (auto& extFile : Globals::Instance->cfg.externalFiles)
{
fs::path externalXmlFilePath = Globals::Instance->cfg.externalXmlFolder / extFile.xmlPath;
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO)
{
printf("Parsing external file from config: '%s'\n", externalXmlFilePath.c_str());
}
parseSuccessful = Parse(externalXmlFilePath, Globals::Instance->baseRomPath,
extFile.outPath, ZFileMode::ExternalFile, workerID);
if (!parseSuccessful)
return 1;
}
parseSuccessful = Parse(fileListItem, Globals::Instance->baseRomPath,
Globals::Instance->outputPath, fileMode, workerID);
if (!parseSuccessful)
return 1;
if (Globals::Instance->singleThreaded)
{
for (int i = 0; i < Globals::Instance->files.size(); i++)
{
delete Globals::Instance->files[i];
Globals::Instance->files.erase(Globals::Instance->files.begin() + i);
i--;
}
Globals::Instance->externalFiles.clear();
Globals::Instance->segments.clear();
Globals::Instance->segmentFiles.clear();
Globals::Instance->cfg.segmentRefFiles.clear();
}
else
{
for (int i = 0; i < Globals::Instance->workerData[workerID]->files.size(); i++)
{
delete Globals::Instance->workerData[workerID]->files[i];
Globals::Instance->workerData[workerID]->files.erase(
Globals::Instance->workerData[workerID]->files.begin() +
i);
i--;
}
Globals::Instance->workerData[workerID]->externalFiles.clear();
Globals::Instance->workerData[workerID]->segments.clear();
Globals::Instance->workerData[workerID]->segmentFiles.clear();
Globals::Instance->workerData[workerID]->segmentRefFiles.clear();
numWorkersLeft--;
}
return 0;
}
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
ZFileMode fileMode, int workerID)
{
tinyxml2::XMLDocument doc;
tinyxml2::XMLError eResult = doc.LoadFile(xmlFilePath.string().c_str());
if (eResult != tinyxml2::XML_SUCCESS)
{
// TODO: use XMLDocument::ErrorIDToName to get more specific error messages here
HANDLE_ERROR(WarningType::InvalidXML,
StringHelper::Sprintf("invalid XML file: '%s'", xmlFilePath.c_str()), "");
return false;
}
tinyxml2::XMLNode* root = doc.FirstChild();
if (root == nullptr)
{
HANDLE_WARNING(
WarningType::InvalidXML,
StringHelper::Sprintf("missing Root tag in xml file: '%s'", xmlFilePath.c_str()), "");
return false;
}
for (tinyxml2::XMLElement* child = root->FirstChildElement(); child != NULL;
child = child->NextSiblingElement())
{
if (std::string_view(child->Name()) == "File")
{
ZFile* file = new ZFile(fileMode, child, basePath, outPath, "", xmlFilePath, workerID);
Globals::Instance->AddFile(file, workerID);
if (fileMode == ZFileMode::ExternalFile)
{
Globals::Instance->AddExternalFile(file, workerID);
file->isExternalFile = true;
}
}
else if (std::string(child->Name()) == "ExternalFile")
{
const char* xmlPathValue = child->Attribute("XmlPath");
if (xmlPathValue == nullptr)
{
throw std::runtime_error(StringHelper::Sprintf(
"Parse: Fatal error in '%s'.\n"
"\t Missing 'XmlPath' attribute in `ExternalFile` element.\n",
xmlFilePath.c_str()));
}
const char* outPathValue = child->Attribute("OutPath");
if (outPathValue == nullptr)
{
throw std::runtime_error(StringHelper::Sprintf(
"Parse: Fatal error in '%s'.\n"
"\t Missing 'OutPath' attribute in `ExternalFile` element.\n",
xmlFilePath.c_str()));
}
fs::path externalXmlFilePath =
Globals::Instance->cfg.externalXmlFolder / fs::path(xmlPathValue);
fs::path externalOutFilePath = fs::path(outPathValue);
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO)
{
printf("Parsing external file: '%s'\n", externalXmlFilePath.c_str());
}
// Recursion. What can go wrong?
Parse(externalXmlFilePath, basePath, externalOutFilePath, ZFileMode::ExternalFile, workerID);
}
else
{
std::string errorHeader =
StringHelper::Sprintf("when parsing file '%s'", xmlFilePath.c_str());
std::string errorBody = StringHelper::Sprintf(
"Found a resource outside a File element: '%s'", child->Name());
HANDLE_ERROR(WarningType::InvalidXML, errorHeader, errorBody);
}
}
if (fileMode != ZFileMode::ExternalFile)
{
ExporterSet* exporterSet = Globals::Instance->GetExporterSet();
if (exporterSet != nullptr && exporterSet->beginXMLFunc != nullptr)
exporterSet->beginXMLFunc();
std::vector<ZFile*> files;
if (Globals::Instance->singleThreaded)
files = Globals::Instance->files;
else
files = Globals::Instance->workerData[workerID]->files;
for (ZFile* file : files)
{
if (fileMode == ZFileMode::BuildSourceFile)
file->BuildSourceFile();
else
file->ExtractResources();
}
if (exporterSet != nullptr && exporterSet->endXMLFunc != nullptr)
exporterSet->endXMLFunc();
}
return true;
}
void ParseArgs(int& argc, char* argv[])
{
static const std::unordered_map<std::string, ArgFunc> ArgFuncDictionary = {
{"-o", &Arg_SetOutputPath},
{"--outputpath", &Arg_SetOutputPath},
{"-i", &Arg_SetInputPath},
{"--inputpath", &Arg_SetInputPath},
{"-b", &Arg_SetBaseromPath},
{"--baserompath", &Arg_SetBaseromPath},
{"-osf", &Arg_SetSourceOutputPath},
{"-gsf", &Arg_GenerateSourceFile},
{"-tm", &Arg_TestMode},
{"-ulzdl", &Arg_LegacyDList},
{"-profile", &Arg_EnableProfiling},
{"-uer", &Arg_UseExternalResources},
{"-tt", &Arg_SetTextureType},
{"-rconf", &Arg_ReadConfigFile},
{"-eh", &Arg_EnableErrorHandler},
{"-v", &Arg_SetVerbosity},
{"-vu", &Arg_VerboseUnaccounted},
{"--verbose-unaccounted", &Arg_VerboseUnaccounted},
{"-se", &Arg_SetExporter},
{"--set-exporter", &Arg_SetExporter},
{"--gcc-compat", &Arg_EnableGCCCompat},
{"-s", &Arg_ForceStatic},
{"--static", &Arg_ForceStatic},
{"-us", &Arg_ForceUnaccountedStatic},
{"--unaccounted-static", &Arg_ForceUnaccountedStatic},
{"-fl", &Arg_SetFileListPath},
{"-brt", &Arg_SetBuildRawTexture},
{"--norom", &Arg_SetNoRomMode},
{"-oxml", &Arg_SetXMLMode},
};
for (int32_t i = 2; i < argc; i++)
{
std::string arg = argv[i];
// Ignore warning args as they have already been parsed
if (arg.length() > 2 && arg[0] == '-' && arg[1] == 'W' && arg[2] != '\0')
{
continue;
}
auto it = ArgFuncDictionary.find(arg);
if (it == ArgFuncDictionary.end())
{
fprintf(stderr, "Unsupported argument: %s\n", arg.c_str());
ExporterSet* exporterSet = Globals::Instance->GetExporterSet();
if (exporterSet != nullptr)
exporterSet->parseArgsFunc(argc, argv, i);
continue;
}
std::invoke(it->second, i, argv);
}
}
ZFileMode ParseFileMode(const std::string& buildMode, ExporterSet* exporterSet)
{
ZFileMode fileMode = ZFileMode::Invalid;
if (buildMode == "btex")
fileMode = ZFileMode::BuildTexture;
else if (buildMode == "bren")
fileMode = ZFileMode::BuildBackground;
else if (buildMode == "bsf")
fileMode = ZFileMode::BuildSourceFile;
else if (buildMode == "bblb")
fileMode = ZFileMode::BuildBlob;
else if (buildMode == "e")
fileMode = ZFileMode::Extract;
else if (buildMode == "ed")
fileMode = ZFileMode::ExtractDirectory;
else if (exporterSet != nullptr && exporterSet->parseFileModeFunc != nullptr)
exporterSet->parseFileModeFunc(buildMode, fileMode);
return fileMode;
}
void Arg_SetOutputPath(int& i, [[maybe_unused]] char* argv[])
{
Globals::Instance->outputPath = argv[++i];
if (Globals::Instance->sourceOutputPath == "")
Globals::Instance->sourceOutputPath = Globals::Instance->outputPath;
}
void Arg_SetInputPath(int& i, char* argv[])
{
Globals::Instance->inputPath = argv[++i];
}
void Arg_SetBaseromPath(int& i, char* argv[])
{
Globals::Instance->baseRomPath = argv[++i];
}
void Arg_SetSourceOutputPath(int& i, char* argv[])
{
Globals::Instance->sourceOutputPath = argv[++i];
}
void Arg_GenerateSourceFile(int& i, char* argv[])
{
// Generate source file during extraction
Globals::Instance->genSourceFile = std::string_view(argv[++i]) == "1";
}
void Arg_TestMode(int& i, char* argv[])
{
// Test Mode (enables certain experimental features)
Globals::Instance->testMode = std::string_view(argv[++i]) == "1";
}
void Arg_LegacyDList(int& i, char* argv[])
{
Globals::Instance->useLegacyZDList = std::string_view(argv[++i]) == "1";
}
void Arg_EnableProfiling(int& i, char* argv[])
{
Globals::Instance->profile = std::string_view(argv[++i]) == "1";
}
void Arg_UseExternalResources(int& i, char* argv[])
{
// Split resources into their individual components(enabled by default)
// TODO: We may wish to make this a part of the config file...
Globals::Instance->useExternalResources = std::string_view(argv[++i]) == "1";
}
void Arg_SetTextureType(int& i, char* argv[])
{
Globals::Instance->texType = ZTexture::GetTextureTypeFromString(argv[++i]);
}
void Arg_ReadConfigFile(int& i, char* argv[])
{
Globals::Instance->cfg.ReadConfigFile(argv[++i]);
}
void Arg_EnableErrorHandler([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
{
CrashHandler_Init();
}
void Arg_SetVerbosity(int& i, char* argv[])
{
Globals::Instance->verbosity = static_cast<VerbosityLevel>(strtol(argv[++i], NULL, 16));
}
void Arg_VerboseUnaccounted([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
{
Globals::Instance->verboseUnaccounted = true;
}
void Arg_SetExporter(int& i, char* argv[])
{
ImportExporters();
Globals::Instance->currentExporter = argv[++i];
}
void Arg_EnableGCCCompat([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
{
Globals::Instance->gccCompat = true;
}
void Arg_ForceStatic([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
{
Globals::Instance->forceStatic = true;
}
void Arg_ForceUnaccountedStatic([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
{
Globals::Instance->forceUnaccountedStatic = true;
}
void Arg_SetFileListPath(int& i, char* argv[])
{
Globals::Instance->fileListPath = argv[++i];
}
void Arg_SetBuildRawTexture([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
{
Globals::Instance->buildRawTexture = true;
}
void Arg_SetNoRomMode([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
{
Globals::Instance->onlyGenCustomOtr = true;
}
void Arg_SetXMLMode(int& i, char* argv[])
{
char* xmlList = argv[++i];
size_t xmlListPos = 0;
size_t xmlListLen = strlen(xmlList);
while (xmlListPos < xmlListLen)
{
char* nextDelimiterPtr = strchr(&xmlList[xmlListPos], ',');
if (nextDelimiterPtr == nullptr)
nextDelimiterPtr = strchr(&xmlList[xmlListPos], 0);
if (nextDelimiterPtr == nullptr)
return;
size_t curModeLen = nextDelimiterPtr - &xmlList[xmlListPos];
// Audio Sound Font (asf)
if (strncmp(&xmlList[xmlListPos], "asf", curModeLen) == 0)
Globals::Instance->xmlExtractModes |= 1 << (int)XMLModeShift::SoundFont;
// Audio Sample (asp)
else if (strncmp(&xmlList[xmlListPos], "asp", curModeLen) == 0)
Globals::Instance->xmlExtractModes |= 1 << (int)XMLModeShift::Sample;
// Audio Sequence (asq)
else if (strncmp(&xmlList[xmlListPos], "asq", curModeLen) == 0)
Globals::Instance->xmlExtractModes |= 1 << (int)XMLModeShift::Sequence;
// We read the 3 chars for the type
xmlListPos += curModeLen;
if (xmlList[xmlListPos] != ',' && xmlList[xmlListPos] != 0)
HANDLE_WARNING(
WarningType::Always, "Invalid Argument",
"XML Extract mode not separated by ','. This may have unintended side effects.");
xmlListPos++;
}
}
int HandleExtract(ZFileMode fileMode, ExporterSet* exporterSet, std::atomic<size_t>* extractCount, std::atomic<size_t>* totalExtract)
{
bool procFileModeSuccess = false;
if (exporterSet != nullptr && exporterSet->processFileModeFunc != nullptr)
procFileModeSuccess = exporterSet->processFileModeFunc(fileMode);
if (!procFileModeSuccess)
{
bool parseSuccessful;
for (auto& extFile : Globals::Instance->cfg.externalFiles)
{
if (fileMode == ZFileMode::ExtractDirectory)
{
std::vector<std::string> fileList =
Directory::ListFiles(Globals::Instance->inputPath.string());
const int num_threads = std::thread::hardware_concurrency();
ctpl::thread_pool pool(num_threads > 1 ? num_threads / 2 : 1);
bool parseSuccessful;
auto start = std::chrono::steady_clock::now();
size_t fileListSize = fileList.size();
Globals::Instance->singleThreaded = true;
for (size_t i = 0; i < fileListSize; i++)
Globals::Instance->workerData[i] = new FileWorker();
numWorkersLeft = fileListSize;
if (totalExtract != nullptr) {
*totalExtract = fileListSize;
}
for (size_t i = 0; i < fileListSize; i++)
{
if (Globals::Instance->singleThreaded)
{
ExtractFunc(i, fileList.size(), fileList[i], fileMode);
if (extractCount != nullptr) {
*extractCount = i;
}
}
else
{
std::string fileListItem = fileList[i];
pool.push([i, fileListSize, fileListItem, fileMode](int) {
ExtractFunc(i, fileListSize, fileListItem, fileMode);
});
}
}
if (!Globals::Instance->singleThreaded)
{
while (true)
{
if (numWorkersLeft <= 0)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
}
auto end = std::chrono::steady_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::seconds>(end - start).count();
printf("Generated OTR File Data in %i seconds\n", diff);
}
else
{
fs::path externalXmlFilePath =
Globals::Instance->cfg.externalXmlFolder / extFile.xmlPath;
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO)
printf("Parsing external file from config: '%s'\n",
externalXmlFilePath.c_str());
parseSuccessful = Parse(externalXmlFilePath, Globals::Instance->baseRomPath,
extFile.outPath, ZFileMode::ExternalFile, 0);
if (!parseSuccessful)
return 1;
}
}
}
return 0;
}
void BuildAssetTexture(const fs::path& pngFilePath, TextureType texType, const fs::path& outPath)
{
return Globals::Instance->BuildAssetTexture(pngFilePath, texType, outPath);
}
void BuildAssetBackground(const fs::path& imageFilePath, const fs::path& outPath)
{
ZBackground background(nullptr);
background.ParseBinaryFile(imageFilePath.string(), false);
DiskFile::WriteAllText(outPath.string(), background.GetBodySourceCode());
}
void BuildAssetBlob(const fs::path& blobFilePath, const fs::path& outPath)
{
ZBlob* blob = ZBlob::FromFile(blobFilePath.string());
std::string name = outPath.stem().string(); // filename without extension
std::string src = blob->GetBodySourceCode();
DiskFile::WriteAllText(outPath.string(), src);
delete blob;
}

View File

View File

@@ -0,0 +1,614 @@
#include "CutsceneMM_Commands.h"
#include <unordered_map>
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
/**** GENERIC ****/
// Specific for command lists where each entry has size 8 bytes
const std::unordered_map<CutsceneMM_CommandType, CsCommandListDescriptor> csCommandsDescMM = {
{CutsceneMM_CommandType::CS_CMD_MISC, {"CS_MISC", "(%s, %i, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING, {"CS_LIGHT_SETTING", "(0x%02X, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_TRANSITION, {"CS_TRANSITION", "(%s, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_MOTION_BLUR, {"CS_MOTION_BLUR", "(%s, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_GIVE_TATL, {"CS_GIVE_TATL", "(%s, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_START_SEQ, {"CS_START_SEQ", "(%s, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_2,
{"CS_SFX_REVERB_INDEX_2", "(0x%04X, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_1,
{"CS_SFX_REVERB_INDEX_1", "(0x%04X, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_MODIFY_SEQ, {"CS_MODIFY_SEQ", "(%s, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_STOP_SEQ, {"CS_STOP_SEQ", "(%s, %i, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_START_AMBIENCE, {"CS_START_AMBIENCE", "(0x%04X, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_FADE_OUT_AMBIENCE,
{"CS_FADE_OUT_AMBIENCE", "(0x%04X, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_DESTINATION, {"CS_DESTINATION", "(%s, %i, %i)"}},
{CutsceneMM_CommandType::CS_CMD_CHOOSE_CREDITS_SCENES,
{"CS_CHOOSE_CREDITS_SCENES", "(%s, %i, %i)"}},
};
CutsceneMMSubCommandEntry_GenericCmd::CutsceneMMSubCommandEntry_GenericCmd(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex, CutsceneMM_CommandType cmdId)
: CutsceneSubCommandEntry(rawData, rawDataIndex), commandId(cmdId)
{
}
std::string CutsceneMMSubCommandEntry_GenericCmd::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
const auto& element = csCommandsDescMM.find(commandId);
std::string entryFmt = "CS_UNK_DATA(0x%02X, %i, %i, %i)";
std::string type = "";
bool isIndexInSeqId = enumData->seqId.find(base - 1) != enumData->seqId.end();
if (element != csCommandsDescMM.end())
{
entryFmt = element->second.cmdMacro;
entryFmt += element->second.args;
}
if (commandId == CutsceneMM_CommandType::CS_CMD_MISC &&
enumData->miscType.find(base) != enumData->miscType.end())
type = enumData->miscType[base];
else if (commandId == CutsceneMM_CommandType::CS_CMD_TRANSITION &&
enumData->transitionType.find(base) != enumData->transitionType.end())
type = enumData->transitionType[base];
else if (commandId == CutsceneMM_CommandType::CS_CMD_MOTION_BLUR &&
enumData->motionBlurType.find(base) != enumData->motionBlurType.end())
type = enumData->motionBlurType[base];
else if (commandId == CutsceneMM_CommandType::CS_CMD_MODIFY_SEQ &&
enumData->modifySeqType.find(base) != enumData->modifySeqType.end())
type = enumData->modifySeqType[base];
else if (commandId == CutsceneMM_CommandType::CS_CMD_DESTINATION &&
enumData->destinationType.find(base) != enumData->destinationType.end())
type = enumData->destinationType[base];
else if (commandId == CutsceneMM_CommandType::CS_CMD_CHOOSE_CREDITS_SCENES &&
enumData->chooseCreditsSceneType.find(base) != enumData->chooseCreditsSceneType.end())
type = enumData->chooseCreditsSceneType[base];
else if ((commandId == CutsceneMM_CommandType::CS_CMD_START_SEQ ||
commandId == CutsceneMM_CommandType::CS_CMD_STOP_SEQ) &&
isIndexInSeqId)
type = enumData->seqId[base - 1];
else if (commandId == CutsceneMM_CommandType::CS_CMD_GIVE_TATL)
type = base ? "true" : "false";
if (type != "")
return StringHelper::Sprintf("%s", entryFmt.c_str(), type.c_str(), startFrame, endFrame,
pad);
if (commandId == CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING ||
commandId == CutsceneMM_CommandType::CS_CMD_START_SEQ ||
commandId == CutsceneMM_CommandType::CS_CMD_STOP_SEQ)
{
return StringHelper::Sprintf("%s", entryFmt.c_str(), base - 1, startFrame, endFrame, pad);
}
return StringHelper::Sprintf("%s", entryFmt.c_str(), base, startFrame, endFrame, pad);
}
CutsceneMMCommand_GenericCmd::CutsceneMMCommand_GenericCmd(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex,
CutsceneMM_CommandType cmdId)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
commandID = static_cast<uint32_t>(cmdId);
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneMMSubCommandEntry_GenericCmd(rawData, rawDataIndex, cmdId);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneMMCommand_GenericCmd::GetCommandMacro() const
{
const auto& element = csCommandsDescMM.find(static_cast<CutsceneMM_CommandType>(commandID));
if (element != csCommandsDescMM.end())
{
return StringHelper::Sprintf("%s_LIST(%i)", element->second.cmdMacro, numEntries);
}
return StringHelper::Sprintf("CS_UNK_DATA_LIST(0x%X, %i)", commandID, numEntries);
}
/**** CAMERA ****/
CutsceneSubCommandEntry_SplineCamPoint::CutsceneSubCommandEntry_SplineCamPoint(
const std::vector<uint8_t>& 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_SplineCamPoint::GetBodySourceCode() const
{
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_SplineCamPoint::GetRawSize() const
{
return 0x0C;
}
CutsceneSubCommandEntry_SplineMiscPoint::CutsceneSubCommandEntry_SplineMiscPoint(
const std::vector<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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_Spline::CutsceneMMCommand_Spline(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
numHeaders = 0;
totalCommands = 0;
rawDataIndex += 4;
while (1)
{
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_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(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
unk_06 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x06);
unk_07 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x07);
unk_08 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x08);
unk_09 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x09);
unk_0A = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x0A);
unk_0B = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x0B);
}
std::string CutsceneSubCommandEntry_TransitionGeneral::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (enumData->transitionGeneralType.find(base) != enumData->transitionGeneralType.end())
return StringHelper::Sprintf("CS_TRANSITION_GENERAL(%s, %i, %i, %i, %i, %i)",
enumData->transitionGeneralType[base].c_str(), startFrame,
endFrame, unk_06, unk_07, unk_08);
return StringHelper::Sprintf("CS_TRANSITION_GENERAL(0x%02X, %i, %i, %i, %i, %i)", base,
startFrame, endFrame, unk_06, unk_07, unk_08);
}
size_t CutsceneSubCommandEntry_TransitionGeneral::GetRawSize() const
{
return 0x0C;
}
CutsceneMMCommand_TransitionGeneral::CutsceneMMCommand_TransitionGeneral(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneSubCommandEntry_TransitionGeneral(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneMMCommand_TransitionGeneral::GetCommandMacro() const
{
return StringHelper::Sprintf("CS_TRANSITION_GENERAL_LIST(%i)", numEntries);
}
CutsceneSubCommandEntry_FadeOutSeq::CutsceneSubCommandEntry_FadeOutSeq(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
unk_08 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8);
}
/**** FADE OUT SEQUENCE ****/
std::string CutsceneSubCommandEntry_FadeOutSeq::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (enumData->fadeOutSeqPlayer.find(base) != enumData->fadeOutSeqPlayer.end())
return StringHelper::Sprintf("CS_FADE_OUT_SEQ(%s, %i, %i)",
enumData->fadeOutSeqPlayer[base].c_str(), startFrame,
endFrame);
return StringHelper::Sprintf("CS_FADE_OUT_SEQ(%i, %i, %i)", base, startFrame, endFrame);
}
size_t CutsceneSubCommandEntry_FadeOutSeq::GetRawSize() const
{
return 0x0C;
}
CutsceneMMCommand_FadeOutSeq::CutsceneMMCommand_FadeOutSeq(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneSubCommandEntry_FadeOutSeq(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneMMCommand_FadeOutSeq::GetCommandMacro() const
{
return StringHelper::Sprintf("CS_FADE_OUT_SEQ_LIST(%i)", numEntries);
}
/**** NON IMPLEMENTED ****/
CutsceneSubCommandEntry_NonImplemented::CutsceneSubCommandEntry_NonImplemented(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
}
CutsceneMMCommand_NonImplemented::CutsceneMMCommand_NonImplemented(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneSubCommandEntry_NonImplemented(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
/**** RUMBLE ****/
CutsceneMMSubCommandEntry_Rumble::CutsceneMMSubCommandEntry_Rumble(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
intensity = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x06);
decayTimer = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x07);
decayStep = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x08);
}
std::string CutsceneMMSubCommandEntry_Rumble::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (enumData->rumbleType.find(base) != enumData->rumbleType.end())
return StringHelper::Sprintf("CS_RUMBLE(%s, %i, %i, 0x%02X, 0x%02X, 0x%02X)",
enumData->rumbleType[base].c_str(), startFrame, endFrame,
intensity, decayTimer, decayStep);
return StringHelper::Sprintf("CS_RUMBLE(0x%04X, %i, %i, 0x%02X, 0x%02X, 0x%02X)", base,
startFrame, endFrame, intensity, decayTimer, decayStep);
}
size_t CutsceneMMSubCommandEntry_Rumble::GetRawSize() const
{
return 0x0C;
}
CutsceneMMCommand_Rumble::CutsceneMMCommand_Rumble(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneMMSubCommandEntry_Rumble(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneMMCommand_Rumble::GetCommandMacro() const
{
return StringHelper::Sprintf("CS_RUMBLE_LIST(%i)", numEntries);
}
/**** TEXT ****/
CutsceneMMSubCommandEntry_Text::CutsceneMMSubCommandEntry_Text(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
type = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x6);
textId1 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x8);
textId2 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0xA);
}
std::string CutsceneMMSubCommandEntry_Text::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (type == 0xFFFF)
{
return StringHelper::Sprintf("CS_TEXT_NONE(%i, %i)", startFrame, endFrame);
}
if (type == 2 &&
enumData->ocarinaSongActionId.find(base) != enumData->ocarinaSongActionId.end())
{
return StringHelper::Sprintf("CS_TEXT_OCARINA_ACTION(%s, %i, %i, 0x%X)",
enumData->ocarinaSongActionId[base].c_str(), startFrame,
endFrame, textId1);
}
switch (type)
{
case 0:
return StringHelper::Sprintf("CS_TEXT_DEFAULT(0x%X, %i, %i, 0x%X, 0x%X)", base, startFrame,
endFrame, textId1, textId2);
case 1:
return StringHelper::Sprintf("CS_TEXT_TYPE_1(0x%X, %i, %i, 0x%X, 0x%X)", base, startFrame,
endFrame, textId1, textId2);
case 3:
return StringHelper::Sprintf("CS_TEXT_TYPE_3(0x%X, %i, %i, 0x%X, 0x%X)", base, startFrame,
endFrame, textId1, textId2);
case 4:
return StringHelper::Sprintf("CS_TEXT_BOSSES_REMAINS(0x%X, %i, %i, 0x%X)", base, startFrame,
endFrame, textId1);
case 5:
return StringHelper::Sprintf("CS_TEXT_ALL_NORMAL_MASKS(0x%X, %i, %i, 0x%X)", base,
startFrame, endFrame, textId1);
}
return nullptr;
}
size_t CutsceneMMSubCommandEntry_Text::GetRawSize() const
{
return 0x0C;
}
CutsceneMMCommand_Text::CutsceneMMCommand_Text(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneMMSubCommandEntry_Text(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneMMCommand_Text::GetCommandMacro() const
{
return StringHelper::Sprintf("CS_TEXT_LIST(%i)", numEntries);
}
/**** ACTOR CUE ****/
CutsceneMMSubCommandEntry_ActorCue::CutsceneMMSubCommandEntry_ActorCue(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
rotX = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x6);
rotY = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x8);
rotZ = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0xA);
startPosX = BitConverter::ToInt32BE(rawData, rawDataIndex + 0xC);
startPosY = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x10);
startPosZ = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x14);
endPosX = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x18);
endPosY = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x1C);
endPosZ = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x20);
normalX = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x24);
normalY = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x28);
normalZ = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x2C);
}
std::string CutsceneMMSubCommandEntry_ActorCue::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (static_cast<CutsceneMM_CommandType>(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)",
enumData->playerCueId[base].c_str(), startFrame, endFrame,
rotX, rotY, rotZ, startPosX, startPosY, startPosZ, endPosX,
endPosY, endPosZ, normalX, normalY, normalZ);
}
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)",
base, startFrame, endFrame, rotX, rotY, rotZ, startPosX,
startPosY, startPosZ, endPosX, endPosY, endPosZ, normalX,
normalY, normalZ);
}
}
size_t CutsceneMMSubCommandEntry_ActorCue::GetRawSize() const
{
return 0x30;
}
CutsceneMMCommand_ActorCue::CutsceneMMCommand_ActorCue(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneMMSubCommandEntry_ActorCue(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneMMCommand_ActorCue::GetCommandMacro() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (static_cast<CutsceneMM_CommandType>(commandID) == CutsceneMM_CommandType::CS_CMD_PLAYER_CUE)
{
return StringHelper::Sprintf("CS_PLAYER_CUE_LIST(%i)", numEntries);
}
if (enumData->cutsceneCmd.find(commandID) != enumData->cutsceneCmd.end())
{
return StringHelper::Sprintf("CS_ACTOR_CUE_LIST(%s, %i)",
enumData->cutsceneCmd[commandID].c_str(), numEntries);
}
return StringHelper::Sprintf("CS_ACTOR_CUE_LIST(0x%03X, %i)", commandID, numEntries);
}

View File

@@ -0,0 +1,481 @@
#pragma once
#include "Cutscene_Common.h"
// https://github.com/zeldaret/mm/blob/0c7b90cf97f26483c8b6a98ae099a295f61e72ab/include/z64cutscene.h#L294-530
enum class CutsceneMM_CommandType
{
/* -2 */ CS_CMD_ACTOR_CUE_POST_PROCESS = -2,
/* -1 */ CS_CAM_STOP,
/* 0x00A */ CS_CMD_TEXT = 10,
/* 0x05A */ CS_CMD_CAMERA_SPLINE = 90,
/* 0x064 */ CS_CMD_ACTOR_CUE_100 = 100,
/* 0x065 */ CS_CMD_ACTOR_CUE_101,
/* 0x066 */ CS_CMD_ACTOR_CUE_102,
/* 0x067 */ CS_CMD_ACTOR_CUE_103,
/* 0x068 */ CS_CMD_ACTOR_CUE_104,
/* 0x069 */ CS_CMD_ACTOR_CUE_105,
/* 0x06A */ CS_CMD_ACTOR_CUE_106,
/* 0x06B */ CS_CMD_ACTOR_CUE_107,
/* 0x06C */ CS_CMD_ACTOR_CUE_108,
/* 0x06D */ CS_CMD_ACTOR_CUE_109,
/* 0x06E */ CS_CMD_ACTOR_CUE_110,
/* 0x06F */ CS_CMD_ACTOR_CUE_111,
/* 0x070 */ CS_CMD_ACTOR_CUE_112,
/* 0x071 */ CS_CMD_ACTOR_CUE_113,
/* 0x072 */ CS_CMD_ACTOR_CUE_114,
/* 0x073 */ CS_CMD_ACTOR_CUE_115,
/* 0x074 */ CS_CMD_ACTOR_CUE_116,
/* 0x075 */ CS_CMD_ACTOR_CUE_117,
/* 0x076 */ CS_CMD_ACTOR_CUE_118,
/* 0x077 */ CS_CMD_ACTOR_CUE_119,
/* 0x078 */ CS_CMD_ACTOR_CUE_120,
/* 0x079 */ CS_CMD_ACTOR_CUE_121,
/* 0x07A */ CS_CMD_ACTOR_CUE_122,
/* 0x07B */ CS_CMD_ACTOR_CUE_123,
/* 0x07C */ CS_CMD_ACTOR_CUE_124,
/* 0x07D */ CS_CMD_ACTOR_CUE_125,
/* 0x07E */ CS_CMD_ACTOR_CUE_126,
/* 0x07F */ CS_CMD_ACTOR_CUE_127,
/* 0x080 */ CS_CMD_ACTOR_CUE_128,
/* 0x081 */ CS_CMD_ACTOR_CUE_129,
/* 0x082 */ CS_CMD_ACTOR_CUE_130,
/* 0x083 */ CS_CMD_ACTOR_CUE_131,
/* 0x084 */ CS_CMD_ACTOR_CUE_132,
/* 0x085 */ CS_CMD_ACTOR_CUE_133,
/* 0x086 */ CS_CMD_ACTOR_CUE_134,
/* 0x087 */ CS_CMD_ACTOR_CUE_135,
/* 0x088 */ CS_CMD_ACTOR_CUE_136,
/* 0x089 */ CS_CMD_ACTOR_CUE_137,
/* 0x08A */ CS_CMD_ACTOR_CUE_138,
/* 0x08B */ CS_CMD_ACTOR_CUE_139,
/* 0x08C */ CS_CMD_ACTOR_CUE_140,
/* 0x08D */ CS_CMD_ACTOR_CUE_141,
/* 0x08E */ CS_CMD_ACTOR_CUE_142,
/* 0x08F */ CS_CMD_ACTOR_CUE_143,
/* 0x090 */ CS_CMD_ACTOR_CUE_144,
/* 0x091 */ CS_CMD_ACTOR_CUE_145,
/* 0x092 */ CS_CMD_ACTOR_CUE_146,
/* 0x093 */ CS_CMD_ACTOR_CUE_147,
/* 0x094 */ CS_CMD_ACTOR_CUE_148,
/* 0x095 */ CS_CMD_ACTOR_CUE_149,
/* 0x096 */ CS_CMD_MISC,
/* 0x097 */ CS_CMD_LIGHT_SETTING,
/* 0x098 */ CS_CMD_TRANSITION,
/* 0x099 */ CS_CMD_MOTION_BLUR,
/* 0x09A */ CS_CMD_GIVE_TATL,
/* 0x09B */ CS_CMD_TRANSITION_GENERAL,
/* 0x09C */ CS_CMD_FADE_OUT_SEQ,
/* 0x09D */ CS_CMD_TIME,
/* 0x0C8 */ CS_CMD_PLAYER_CUE = 200,
/* 0x0C9 */ CS_CMD_ACTOR_CUE_201,
/* 0x0FA */ CS_CMD_UNK_DATA_FA = 0xFA,
/* 0x0FE */ CS_CMD_UNK_DATA_FE = 0xFE,
/* 0x0FF */ CS_CMD_UNK_DATA_FF,
/* 0x100 */ CS_CMD_UNK_DATA_100,
/* 0x101 */ CS_CMD_UNK_DATA_101,
/* 0x102 */ CS_CMD_UNK_DATA_102,
/* 0x103 */ CS_CMD_UNK_DATA_103,
/* 0x104 */ CS_CMD_UNK_DATA_104,
/* 0x105 */ CS_CMD_UNK_DATA_105,
/* 0x108 */ CS_CMD_UNK_DATA_108 = 0x108,
/* 0x109 */ CS_CMD_UNK_DATA_109,
/* 0x12C */ CS_CMD_START_SEQ = 300,
/* 0x12D */ CS_CMD_STOP_SEQ,
/* 0x12E */ CS_CMD_START_AMBIENCE,
/* 0x12F */ CS_CMD_FADE_OUT_AMBIENCE,
/* 0x130 */ CS_CMD_SFX_REVERB_INDEX_2,
/* 0x131 */ CS_CMD_SFX_REVERB_INDEX_1,
/* 0x132 */ CS_CMD_MODIFY_SEQ,
/* 0x15E */ CS_CMD_DESTINATION = 350,
/* 0x15F */ CS_CMD_CHOOSE_CREDITS_SCENES,
/* 0x190 */ CS_CMD_RUMBLE = 400,
/* 0x1C2 */ CS_CMD_ACTOR_CUE_450 = 450,
/* 0x1C3 */ CS_CMD_ACTOR_CUE_451,
/* 0x1C4 */ CS_CMD_ACTOR_CUE_452,
/* 0x1C5 */ CS_CMD_ACTOR_CUE_453,
/* 0x1C6 */ CS_CMD_ACTOR_CUE_454,
/* 0x1C7 */ CS_CMD_ACTOR_CUE_455,
/* 0x1C8 */ CS_CMD_ACTOR_CUE_456,
/* 0x1C9 */ CS_CMD_ACTOR_CUE_457,
/* 0x1CA */ CS_CMD_ACTOR_CUE_458,
/* 0x1CB */ CS_CMD_ACTOR_CUE_459,
/* 0x1CC */ CS_CMD_ACTOR_CUE_460,
/* 0x1CD */ CS_CMD_ACTOR_CUE_461,
/* 0x1CE */ CS_CMD_ACTOR_CUE_462,
/* 0x1CF */ CS_CMD_ACTOR_CUE_463,
/* 0x1D0 */ CS_CMD_ACTOR_CUE_464,
/* 0x1D1 */ CS_CMD_ACTOR_CUE_465,
/* 0x1D2 */ CS_CMD_ACTOR_CUE_466,
/* 0x1D3 */ CS_CMD_ACTOR_CUE_467,
/* 0x1D4 */ CS_CMD_ACTOR_CUE_468,
/* 0x1D5 */ CS_CMD_ACTOR_CUE_469,
/* 0x1D6 */ CS_CMD_ACTOR_CUE_470,
/* 0x1D7 */ CS_CMD_ACTOR_CUE_471,
/* 0x1D8 */ CS_CMD_ACTOR_CUE_472,
/* 0x1D9 */ CS_CMD_ACTOR_CUE_473,
/* 0x1DA */ CS_CMD_ACTOR_CUE_474,
/* 0x1DB */ CS_CMD_ACTOR_CUE_475,
/* 0x1DC */ CS_CMD_ACTOR_CUE_476,
/* 0x1DD */ CS_CMD_ACTOR_CUE_477,
/* 0x1DE */ CS_CMD_ACTOR_CUE_478,
/* 0x1DF */ CS_CMD_ACTOR_CUE_479,
/* 0x1E0 */ CS_CMD_ACTOR_CUE_480,
/* 0x1E1 */ CS_CMD_ACTOR_CUE_481,
/* 0x1E2 */ CS_CMD_ACTOR_CUE_482,
/* 0x1E3 */ CS_CMD_ACTOR_CUE_483,
/* 0x1E4 */ CS_CMD_ACTOR_CUE_484,
/* 0x1E5 */ CS_CMD_ACTOR_CUE_485,
/* 0x1E6 */ CS_CMD_ACTOR_CUE_486,
/* 0x1E7 */ CS_CMD_ACTOR_CUE_487,
/* 0x1E8 */ CS_CMD_ACTOR_CUE_488,
/* 0x1E9 */ CS_CMD_ACTOR_CUE_489,
/* 0x1EA */ CS_CMD_ACTOR_CUE_490,
/* 0x1EB */ CS_CMD_ACTOR_CUE_491,
/* 0x1EC */ CS_CMD_ACTOR_CUE_492,
/* 0x1ED */ CS_CMD_ACTOR_CUE_493,
/* 0x1EE */ CS_CMD_ACTOR_CUE_494,
/* 0x1EF */ CS_CMD_ACTOR_CUE_495,
/* 0x1F0 */ CS_CMD_ACTOR_CUE_496,
/* 0x1F1 */ CS_CMD_ACTOR_CUE_497,
/* 0x1F2 */ CS_CMD_ACTOR_CUE_498,
/* 0x1F3 */ CS_CMD_ACTOR_CUE_499,
/* 0x1F4 */ CS_CMD_ACTOR_CUE_500,
/* 0x1F5 */ CS_CMD_ACTOR_CUE_501,
/* 0x1F6 */ CS_CMD_ACTOR_CUE_502,
/* 0x1F7 */ CS_CMD_ACTOR_CUE_503,
/* 0x1F8 */ CS_CMD_ACTOR_CUE_504,
/* 0x1F9 */ CS_CMD_ACTOR_CUE_SOTCS,
/* 0x1FA */ CS_CMD_ACTOR_CUE_506,
/* 0x1FB */ CS_CMD_ACTOR_CUE_507,
/* 0x1FC */ CS_CMD_ACTOR_CUE_508,
/* 0x1FD */ CS_CMD_ACTOR_CUE_509,
/* 0x1FE */ CS_CMD_ACTOR_CUE_510,
/* 0x1FF */ CS_CMD_ACTOR_CUE_511,
/* 0x200 */ CS_CMD_ACTOR_CUE_512,
/* 0x201 */ CS_CMD_ACTOR_CUE_513,
/* 0x202 */ CS_CMD_ACTOR_CUE_514,
/* 0x203 */ CS_CMD_ACTOR_CUE_515,
/* 0x204 */ CS_CMD_ACTOR_CUE_516,
/* 0x205 */ CS_CMD_ACTOR_CUE_517,
/* 0x206 */ CS_CMD_ACTOR_CUE_518,
/* 0x207 */ CS_CMD_ACTOR_CUE_519,
/* 0x208 */ CS_CMD_ACTOR_CUE_520,
/* 0x209 */ CS_CMD_ACTOR_CUE_521,
/* 0x20A */ CS_CMD_ACTOR_CUE_522,
/* 0x20B */ CS_CMD_ACTOR_CUE_523,
/* 0x20C */ CS_CMD_ACTOR_CUE_524,
/* 0x20D */ CS_CMD_ACTOR_CUE_525,
/* 0x20E */ CS_CMD_ACTOR_CUE_526,
/* 0x20F */ CS_CMD_ACTOR_CUE_527,
/* 0x210 */ CS_CMD_ACTOR_CUE_528,
/* 0x211 */ CS_CMD_ACTOR_CUE_529,
/* 0x212 */ CS_CMD_ACTOR_CUE_530,
/* 0x213 */ CS_CMD_ACTOR_CUE_531,
/* 0x214 */ CS_CMD_ACTOR_CUE_532,
/* 0x215 */ CS_CMD_ACTOR_CUE_533,
/* 0x216 */ CS_CMD_ACTOR_CUE_534,
/* 0x217 */ CS_CMD_ACTOR_CUE_535,
/* 0x218 */ CS_CMD_ACTOR_CUE_536,
/* 0x219 */ CS_CMD_ACTOR_CUE_537,
/* 0x21A */ CS_CMD_ACTOR_CUE_538,
/* 0x21B */ CS_CMD_ACTOR_CUE_539,
/* 0x21C */ CS_CMD_ACTOR_CUE_540,
/* 0x21D */ CS_CMD_ACTOR_CUE_541,
/* 0x21E */ CS_CMD_ACTOR_CUE_542,
/* 0x21F */ CS_CMD_ACTOR_CUE_543,
/* 0x220 */ CS_CMD_ACTOR_CUE_544,
/* 0x221 */ CS_CMD_ACTOR_CUE_545,
/* 0x222 */ CS_CMD_ACTOR_CUE_546,
/* 0x223 */ CS_CMD_ACTOR_CUE_547,
/* 0x224 */ CS_CMD_ACTOR_CUE_548,
/* 0x225 */ CS_CMD_ACTOR_CUE_549,
/* 0x226 */ CS_CMD_ACTOR_CUE_550,
/* 0x227 */ CS_CMD_ACTOR_CUE_551,
/* 0x228 */ CS_CMD_ACTOR_CUE_552,
/* 0x229 */ CS_CMD_ACTOR_CUE_553,
/* 0x22A */ CS_CMD_ACTOR_CUE_554,
/* 0x22B */ CS_CMD_ACTOR_CUE_555,
/* 0x22C */ CS_CMD_ACTOR_CUE_556,
/* 0x22D */ CS_CMD_ACTOR_CUE_557,
/* 0x22E */ CS_CMD_ACTOR_CUE_558,
/* 0x22F */ CS_CMD_ACTOR_CUE_559,
/* 0x230 */ CS_CMD_ACTOR_CUE_560,
/* 0x231 */ CS_CMD_ACTOR_CUE_561,
/* 0x232 */ CS_CMD_ACTOR_CUE_562,
/* 0x233 */ CS_CMD_ACTOR_CUE_563,
/* 0x234 */ CS_CMD_ACTOR_CUE_564,
/* 0x235 */ CS_CMD_ACTOR_CUE_565,
/* 0x236 */ CS_CMD_ACTOR_CUE_566,
/* 0x237 */ CS_CMD_ACTOR_CUE_567,
/* 0x238 */ CS_CMD_ACTOR_CUE_568,
/* 0x239 */ CS_CMD_ACTOR_CUE_569,
/* 0x23A */ CS_CMD_ACTOR_CUE_570,
/* 0x23B */ CS_CMD_ACTOR_CUE_571,
/* 0x23C */ CS_CMD_ACTOR_CUE_572,
/* 0x23D */ CS_CMD_ACTOR_CUE_573,
/* 0x23E */ CS_CMD_ACTOR_CUE_574,
/* 0x23F */ CS_CMD_ACTOR_CUE_575,
/* 0x240 */ CS_CMD_ACTOR_CUE_576,
/* 0x241 */ CS_CMD_ACTOR_CUE_577,
/* 0x242 */ CS_CMD_ACTOR_CUE_578,
/* 0x243 */ CS_CMD_ACTOR_CUE_579,
/* 0x244 */ CS_CMD_ACTOR_CUE_580,
/* 0x245 */ CS_CMD_ACTOR_CUE_581,
/* 0x246 */ CS_CMD_ACTOR_CUE_582,
/* 0x247 */ CS_CMD_ACTOR_CUE_583,
/* 0x248 */ CS_CMD_ACTOR_CUE_584,
/* 0x249 */ CS_CMD_ACTOR_CUE_585,
/* 0x24A */ CS_CMD_ACTOR_CUE_586,
/* 0x24B */ CS_CMD_ACTOR_CUE_587,
/* 0x24C */ CS_CMD_ACTOR_CUE_588,
/* 0x24D */ CS_CMD_ACTOR_CUE_589,
/* 0x24E */ CS_CMD_ACTOR_CUE_590,
/* 0x24F */ CS_CMD_ACTOR_CUE_591,
/* 0x250 */ CS_CMD_ACTOR_CUE_592,
/* 0x251 */ CS_CMD_ACTOR_CUE_593,
/* 0x252 */ CS_CMD_ACTOR_CUE_594,
/* 0x253 */ CS_CMD_ACTOR_CUE_595,
/* 0x254 */ CS_CMD_ACTOR_CUE_596,
/* 0x255 */ CS_CMD_ACTOR_CUE_597,
/* 0x256 */ CS_CMD_ACTOR_CUE_598,
/* 0x257 */ CS_CMD_ACTOR_CUE_599
};
/**** GENERIC ****/
class CutsceneMMSubCommandEntry_GenericCmd : public CutsceneSubCommandEntry
{
public:
CutsceneMM_CommandType commandId;
CutsceneMMSubCommandEntry_GenericCmd(const std::vector<uint8_t>& rawData, offset_t rawDataIndex,
CutsceneMM_CommandType cmdId);
std::string GetBodySourceCode() const override;
};
class CutsceneMMCommand_GenericCmd : public CutsceneCommand
{
public:
CutsceneMMCommand_GenericCmd(const std::vector<uint8_t>& rawData, offset_t rawDataIndex,
CutsceneMM_CommandType cmdId);
std::string GetCommandMacro() const override;
};
/**** CAMERA ****/
// TODO: MM cutscene camera command is implemented as a placeholder until we better understand how
// it works
class CutsceneSubCommandEntry_SplineCamPoint : public CutsceneSubCommandEntry
{
public:
uint8_t interpType;
uint8_t weight;
uint16_t duration;
uint16_t posX;
uint16_t posY;
uint16_t posZ;
uint16_t relTo;
CutsceneSubCommandEntry_SplineCamPoint(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneSubCommandEntry_SplineMiscPoint : public CutsceneSubCommandEntry
{
public:
uint16_t unused0;
uint16_t roll;
uint16_t fov;
uint16_t unused1;
CutsceneSubCommandEntry_SplineMiscPoint(const std::vector<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
size_t GetCommandSize() const override;
};
/**** TRANSITION GENERAL ****/
class CutsceneSubCommandEntry_TransitionGeneral : public CutsceneSubCommandEntry
{
public:
uint8_t unk_06;
uint8_t unk_07;
uint8_t unk_08;
uint8_t unk_09;
uint8_t unk_0A;
uint8_t unk_0B;
CutsceneSubCommandEntry_TransitionGeneral(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneMMCommand_TransitionGeneral : public CutsceneCommand
{
public:
CutsceneMMCommand_TransitionGeneral(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};
/**** FADE OUT SEQUENCE ****/
class CutsceneSubCommandEntry_FadeOutSeq : public CutsceneSubCommandEntry
{
public:
uint32_t unk_08;
CutsceneSubCommandEntry_FadeOutSeq(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneMMCommand_FadeOutSeq : public CutsceneCommand
{
public:
CutsceneMMCommand_FadeOutSeq(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};
/**** NON IMPLEMENTED ****/
class CutsceneSubCommandEntry_NonImplemented : public CutsceneSubCommandEntry
{
public:
CutsceneSubCommandEntry_NonImplemented(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex);
};
class CutsceneMMCommand_NonImplemented : public CutsceneCommand
{
public:
CutsceneMMCommand_NonImplemented(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
};
/**** RUMBLE ****/
class CutsceneMMSubCommandEntry_Rumble : public CutsceneSubCommandEntry
{
public:
uint8_t intensity;
uint8_t decayTimer;
uint8_t decayStep;
CutsceneMMSubCommandEntry_Rumble(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneMMCommand_Rumble : public CutsceneCommand
{
public:
CutsceneMMCommand_Rumble(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};
/**** TEXT ****/
class CutsceneMMSubCommandEntry_Text : public CutsceneSubCommandEntry
{
public:
uint16_t type;
uint16_t textId1;
uint16_t textId2;
CutsceneMMSubCommandEntry_Text(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneMMCommand_Text : public CutsceneCommand
{
public:
CutsceneMMCommand_Text(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};
/**** ACTOR CUE ****/
class CutsceneMMSubCommandEntry_ActorCue : public CutsceneSubCommandEntry
{
public:
uint16_t rotX, rotY, rotZ;
int32_t startPosX, startPosY, startPosZ;
int32_t endPosX, endPosY, endPosZ;
float normalX, normalY, normalZ;
CutsceneMMSubCommandEntry_ActorCue(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneMMCommand_ActorCue : public CutsceneCommand
{
public:
CutsceneMMCommand_ActorCue(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};

View File

@@ -0,0 +1,458 @@
#include "CutsceneOoT_Commands.h"
#include <cassert>
#include <unordered_map>
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
/**** GENERIC ****/
// Specific for command lists where each entry has size 0x30 bytes
const std::unordered_map<CutsceneOoT_CommandType, CsCommandListDescriptor> csCommandsDesc = {
{CutsceneOoT_CommandType::CS_CMD_MISC,
{"CS_MISC", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
{CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING,
{"CS_LIGHT_SETTING", "(0x%02X, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
{CutsceneOoT_CommandType::CS_CMD_START_SEQ,
{"CS_START_SEQ", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
{CutsceneOoT_CommandType::CS_CMD_STOP_SEQ,
{"CS_STOP_SEQ", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
{CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ,
{"CS_FADE_OUT_SEQ", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
};
CutsceneOoTSubCommandEntry_GenericCmd::CutsceneOoTSubCommandEntry_GenericCmd(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex, CutsceneOoT_CommandType cmdId)
: CutsceneSubCommandEntry(rawData, rawDataIndex), commandId(cmdId)
{
word0 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0);
word1 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x4);
unused1 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x8);
unused2 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0xC);
unused3 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x10);
unused4 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x14);
unused5 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x18);
unused6 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x1C);
unused7 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x20);
unused8 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x24);
unused9 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x28);
unused10 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x2C);
}
std::string CutsceneOoTSubCommandEntry_GenericCmd::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
const auto& element = csCommandsDesc.find(commandId);
if (element != csCommandsDesc.end())
{
bool isIndexInMisc = enumData->miscType.find(base) != enumData->miscType.end();
bool isIndexInFade =
enumData->fadeOutSeqPlayer.find(base) != enumData->fadeOutSeqPlayer.end();
bool isIndexInSeqId = enumData->seqId.find(base - 1) != enumData->seqId.end();
std::string entryFmt = element->second.cmdMacro;
std::string firstArg;
entryFmt += element->second.args;
if (commandId == CutsceneOoT_CommandType::CS_CMD_MISC && isIndexInMisc)
firstArg = enumData->miscType[base];
else if (commandId == CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ && isIndexInFade)
firstArg = enumData->fadeOutSeqPlayer[base];
else if (commandId == CutsceneOoT_CommandType::CS_CMD_START_SEQ && isIndexInSeqId)
firstArg = enumData->seqId[base - 1];
else if (commandId == CutsceneOoT_CommandType::CS_CMD_STOP_SEQ && isIndexInSeqId)
firstArg = enumData->seqId[base - 1];
else
{
return StringHelper::Sprintf(entryFmt.c_str(), base - 1, startFrame, endFrame, pad,
unused1, unused2, unused3, unused4, unused5, unused6,
unused7, unused8, unused9, unused10);
}
}
return StringHelper::Sprintf("CS_UNK_DATA(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, "
"0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X)",
word0, word1, unused1, unused2, unused3, unused4, unused5, unused6,
unused7, unused8, unused9, unused10);
}
size_t CutsceneOoTSubCommandEntry_GenericCmd::GetRawSize() const
{
return 0x30;
}
CutsceneOoTCommand_GenericCmd::CutsceneOoTCommand_GenericCmd(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex,
CutsceneOoT_CommandType cmdId)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
commandID = static_cast<uint32_t>(cmdId);
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneOoTSubCommandEntry_GenericCmd(rawData, rawDataIndex, cmdId);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneOoTCommand_GenericCmd::GetCommandMacro() const
{
const auto& element = csCommandsDesc.find(static_cast<CutsceneOoT_CommandType>(commandID));
if (element != csCommandsDesc.end())
{
return StringHelper::Sprintf("%s_LIST(%i)", element->second.cmdMacro, numEntries);
}
return StringHelper::Sprintf("CS_UNK_DATA_LIST(0x%X, %i)", commandID, numEntries);
}
/**** CAMERA ****/
CutsceneOoTCommand_CameraPoint::CutsceneOoTCommand_CameraPoint(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
continueFlag = BitConverter::ToInt8BE(rawData, rawDataIndex + 0);
cameraRoll = BitConverter::ToInt8BE(rawData, rawDataIndex + 1);
nextPointFrame = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
viewAngle = BitConverter::ToFloatBE(rawData, rawDataIndex + 4);
posX = BitConverter::ToInt16BE(rawData, rawDataIndex + 8);
posY = BitConverter::ToInt16BE(rawData, rawDataIndex + 10);
posZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 12);
unused = BitConverter::ToInt16BE(rawData, rawDataIndex + 14);
}
std::string CutsceneOoTCommand_CameraPoint::GetBodySourceCode() const
{
std::string continueMacro = "CS_CAM_CONTINUE";
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);
}
size_t CutsceneOoTCommand_CameraPoint::GetRawSize() const
{
return 0x10;
}
CutsceneOoTCommand_GenericCameraCmd::CutsceneOoTCommand_GenericCameraCmd(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
base = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0);
startFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
endFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4);
unused = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6);
bool shouldContinue = true;
uint32_t currentPtr = rawDataIndex + 8;
while (shouldContinue)
{
CutsceneOoTCommand_CameraPoint* camPoint =
new CutsceneOoTCommand_CameraPoint(rawData, currentPtr);
entries.push_back(camPoint);
if (camPoint->continueFlag == -1)
shouldContinue = false;
currentPtr += camPoint->GetRawSize();
}
}
std::string CutsceneOoTCommand_GenericCameraCmd::GetCommandMacro() const
{
std::string result;
const char* listStr;
if (commandID == (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE)
{
listStr = "CS_CAM_AT_SPLINE";
}
else if (commandID == (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER)
{
listStr = "CS_CAM_AT_SPLINE_REL_TO_PLAYER";
}
else if (commandID == (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER)
{
listStr = "CS_CAM_EYE_SPLINE_REL_TO_PLAYER";
}
else
{
listStr = "CS_CAM_EYE_SPLINE";
}
result += StringHelper::Sprintf("%s(%i, %i)", listStr, startFrame, endFrame);
return result;
}
size_t CutsceneOoTCommand_GenericCameraCmd::GetCommandSize() const
{
return 0x0C + entries.at(0)->GetRawSize() * entries.size();
}
/**** RUMBLE ****/
CutsceneOoTSubCommandEntry_Rumble::CutsceneOoTSubCommandEntry_Rumble(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
sourceStrength = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x06);
duration = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x07);
decreaseRate = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x08);
unk_09 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x09);
unk_0A = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x0A);
}
std::string CutsceneOoTSubCommandEntry_Rumble::GetBodySourceCode() const
{
// Note: the first argument is unused
return StringHelper::Sprintf("CS_RUMBLE_CONTROLLER(%i, %i, %i, %i, %i, %i, 0x%02X, 0x%02X)",
base, startFrame, endFrame, sourceStrength, duration, decreaseRate,
unk_09, unk_0A);
}
size_t CutsceneOoTSubCommandEntry_Rumble::GetRawSize() const
{
return 0x0C;
}
CutsceneOoTCommand_Rumble::CutsceneOoTCommand_Rumble(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneOoTSubCommandEntry_Rumble(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneOoTCommand_Rumble::GetCommandMacro() const
{
return StringHelper::Sprintf("CS_RUMBLE_CONTROLLER_LIST(%i)", numEntries);
}
/**** TEXT ****/
CutsceneOoTSubCommandEntry_Text::CutsceneOoTSubCommandEntry_Text(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
type = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x6);
textId1 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x8);
textId2 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0xA);
}
std::string CutsceneOoTSubCommandEntry_Text::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (type == 0xFFFF)
{
return StringHelper::Sprintf("CS_TEXT_NONE(%i, %i)", startFrame, endFrame);
}
if (type == 2 &&
enumData->ocarinaSongActionId.find(base) != enumData->ocarinaSongActionId.end())
{
return StringHelper::Sprintf("CS_TEXT_OCARINA_ACTION(%s, %i, %i, 0x%X)",
enumData->ocarinaSongActionId[base].c_str(), startFrame,
endFrame, textId1);
}
if (enumData->textType.find(type) != enumData->textType.end())
{
return StringHelper::Sprintf("CS_TEXT(0x%X, %i, %i, %s, 0x%X, 0x%X)", base, startFrame,
endFrame, enumData->textType[type].c_str(), textId1, textId2);
}
return StringHelper::Sprintf("CS_TEXT(0x%X, %i, %i, %i, 0x%X, 0x%X)", base, startFrame,
endFrame, type, textId1, textId2);
}
size_t CutsceneOoTSubCommandEntry_Text::GetRawSize() const
{
return 0x0C;
}
CutsceneOoTCommand_Text::CutsceneOoTCommand_Text(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneOoTSubCommandEntry_Text(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneOoTCommand_Text::GetCommandMacro() const
{
return StringHelper::Sprintf("CS_TEXT_LIST(%i)", numEntries);
}
/**** ACTOR CUE ****/
CutsceneOoTSubCommandEntry_ActorCue::CutsceneOoTSubCommandEntry_ActorCue(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
rotX = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x6);
rotY = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x8);
rotZ = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0xA);
startPosX = BitConverter::ToInt32BE(rawData, rawDataIndex + 0xC);
startPosY = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x10);
startPosZ = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x14);
endPosX = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x18);
endPosY = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x1C);
endPosZ = BitConverter::ToInt32BE(rawData, rawDataIndex + 0x20);
normalX = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x24);
normalY = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x28);
normalZ = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x2C);
}
std::string CutsceneOoTSubCommandEntry_ActorCue::GetBodySourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (static_cast<CutsceneOoT_CommandType>(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)",
enumData->playerCueId[base].c_str(), startFrame, endFrame,
rotX, rotY, rotZ, startPosX, startPosY, startPosZ, endPosX,
endPosY, endPosZ, normalX, normalY, normalZ);
}
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)",
base, startFrame, endFrame, rotX, rotY, rotZ, startPosX,
startPosY, startPosZ, endPosX, endPosY, endPosZ, normalX,
normalY, normalZ);
}
}
size_t CutsceneOoTSubCommandEntry_ActorCue::GetRawSize() const
{
return 0x30;
}
CutsceneOoTCommand_ActorCue::CutsceneOoTCommand_ActorCue(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneOoTSubCommandEntry_ActorCue(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneOoTCommand_ActorCue::GetCommandMacro() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (static_cast<CutsceneOoT_CommandType>(commandID) ==
CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE)
{
return StringHelper::Sprintf("CS_PLAYER_CUE_LIST(%i)", entries.size());
}
if (enumData->cutsceneCmd.find(commandID) != enumData->cutsceneCmd.end())
{
return StringHelper::Sprintf("CS_ACTOR_CUE_LIST(%s, %i)",
enumData->cutsceneCmd[commandID].c_str(), entries.size());
}
return StringHelper::Sprintf("CS_ACTOR_CUE_LIST(0x%04X, %i)", commandID, entries.size());
}
/**** DESTINATION ****/
CutsceneOoTCommand_Destination::CutsceneOoTCommand_Destination(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
base = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0);
startFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
endFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4);
unknown = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6); // endFrame duplicate
}
std::string CutsceneOoTCommand_Destination::GenerateSourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (enumData->destination.find(base) != enumData->destination.end())
{
return StringHelper::Sprintf("CS_DESTINATION(%s, %i, %i),\n",
enumData->destination[base].c_str(), startFrame, endFrame);
}
return StringHelper::Sprintf("CS_DESTINATION(%i, %i, %i),\n", base, startFrame, endFrame);
}
size_t CutsceneOoTCommand_Destination::GetCommandSize() const
{
return 0x10;
}
/**** TRANSITION ****/
CutsceneOoTCommand_Transition::CutsceneOoTCommand_Transition(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
base = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0);
startFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
endFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4);
}
std::string CutsceneOoTCommand_Transition::GenerateSourceCode() const
{
EnumData* enumData = &Globals::Instance->cfg.enumData;
if (enumData->transitionType.find(base) != enumData->transitionType.end())
{
return StringHelper::Sprintf("CS_TRANSITION(%s, %i, %i),\n",
enumData->transitionType[base].c_str(), startFrame, endFrame);
}
return StringHelper::Sprintf("CS_TRANSITION(%i, %i, %i),\n", base, startFrame, endFrame);
}
size_t CutsceneOoTCommand_Transition::GetCommandSize() const
{
return 0x10;
}

View File

@@ -0,0 +1,314 @@
#pragma once
#include "Cutscene_Common.h"
// https://github.com/zeldaret/oot/blob/7235af2249843fb68740111b70089bad827a4730/include/z64cutscene.h#L35-L165
enum class CutsceneOoT_CommandType
{
CS_CMD_CAM_EYE_SPLINE = 0x01,
CS_CMD_CAM_AT_SPLINE,
CS_CMD_MISC,
CS_CMD_LIGHT_SETTING,
CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER,
CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER,
CS_CMD_CAM_EYE,
CS_CMD_CAM_AT,
CS_CMD_RUMBLE_CONTROLLER,
CS_CMD_PLAYER_CUE,
CS_CMD_UNIMPLEMENTED_B,
CS_CMD_UNIMPLEMENTED_D = 0x0D,
CS_CMD_ACTOR_CUE_1_0,
CS_CMD_ACTOR_CUE_0_0,
CS_CMD_ACTOR_CUE_1_1,
CS_CMD_ACTOR_CUE_0_1,
CS_CMD_ACTOR_CUE_0_2,
CS_CMD_TEXT,
CS_CMD_UNIMPLEMENTED_15 = 0x15,
CS_CMD_UNIMPLEMENTED_16,
CS_CMD_ACTOR_CUE_0_3,
CS_CMD_ACTOR_CUE_1_2,
CS_CMD_ACTOR_CUE_2_0,
CS_CMD_UNIMPLEMENTED_1B = 0x1B,
CS_CMD_UNIMPLEMENTED_1C,
CS_CMD_ACTOR_CUE_3_0,
CS_CMD_ACTOR_CUE_4_0,
CS_CMD_ACTOR_CUE_6_0,
CS_CMD_UNIMPLEMENTED_20,
CS_CMD_UNIMPLEMENTED_21,
CS_CMD_ACTOR_CUE_0_4,
CS_CMD_ACTOR_CUE_1_3,
CS_CMD_ACTOR_CUE_2_1,
CS_CMD_ACTOR_CUE_3_1,
CS_CMD_ACTOR_CUE_4_1,
CS_CMD_ACTOR_CUE_0_5,
CS_CMD_ACTOR_CUE_1_4,
CS_CMD_ACTOR_CUE_2_2,
CS_CMD_ACTOR_CUE_3_2,
CS_CMD_ACTOR_CUE_4_2,
CS_CMD_ACTOR_CUE_5_0,
CS_CMD_TRANSITION,
CS_CMD_ACTOR_CUE_0_6,
CS_CMD_ACTOR_CUE_4_3,
CS_CMD_ACTOR_CUE_1_5,
CS_CMD_ACTOR_CUE_7_0,
CS_CMD_ACTOR_CUE_2_3,
CS_CMD_ACTOR_CUE_3_3,
CS_CMD_ACTOR_CUE_6_1,
CS_CMD_ACTOR_CUE_3_4,
CS_CMD_ACTOR_CUE_4_4,
CS_CMD_ACTOR_CUE_5_1,
CS_CMD_ACTOR_CUE_6_2 = 0x39,
CS_CMD_ACTOR_CUE_6_3,
CS_CMD_UNIMPLEMENTED_3B,
CS_CMD_ACTOR_CUE_7_1,
CS_CMD_UNIMPLEMENTED_3D,
CS_CMD_ACTOR_CUE_8_0,
CS_CMD_ACTOR_CUE_3_5,
CS_CMD_ACTOR_CUE_1_6,
CS_CMD_ACTOR_CUE_3_6,
CS_CMD_ACTOR_CUE_3_7,
CS_CMD_ACTOR_CUE_2_4,
CS_CMD_ACTOR_CUE_1_7,
CS_CMD_ACTOR_CUE_2_5,
CS_CMD_ACTOR_CUE_1_8,
CS_CMD_UNIMPLEMENTED_47,
CS_CMD_ACTOR_CUE_2_6,
CS_CMD_UNIMPLEMENTED_49,
CS_CMD_ACTOR_CUE_2_7,
CS_CMD_ACTOR_CUE_3_8,
CS_CMD_ACTOR_CUE_0_7,
CS_CMD_ACTOR_CUE_5_2,
CS_CMD_ACTOR_CUE_1_9,
CS_CMD_ACTOR_CUE_4_5,
CS_CMD_ACTOR_CUE_1_10,
CS_CMD_ACTOR_CUE_2_8,
CS_CMD_ACTOR_CUE_3_9,
CS_CMD_ACTOR_CUE_4_6,
CS_CMD_ACTOR_CUE_5_3,
CS_CMD_ACTOR_CUE_0_8,
CS_CMD_START_SEQ,
CS_CMD_STOP_SEQ,
CS_CMD_ACTOR_CUE_6_4,
CS_CMD_ACTOR_CUE_7_2,
CS_CMD_ACTOR_CUE_5_4,
CS_CMD_ACTOR_CUE_0_9 = 0x5D,
CS_CMD_ACTOR_CUE_1_11,
CS_CMD_ACTOR_CUE_0_10 = 0x69,
CS_CMD_ACTOR_CUE_2_9,
CS_CMD_ACTOR_CUE_0_11,
CS_CMD_ACTOR_CUE_3_10,
CS_CMD_UNIMPLEMENTED_6D,
CS_CMD_ACTOR_CUE_0_12,
CS_CMD_ACTOR_CUE_7_3,
CS_CMD_UNIMPLEMENTED_70,
CS_CMD_UNIMPLEMENTED_71,
CS_CMD_ACTOR_CUE_7_4,
CS_CMD_ACTOR_CUE_6_5,
CS_CMD_ACTOR_CUE_1_12,
CS_CMD_ACTOR_CUE_2_10,
CS_CMD_ACTOR_CUE_1_13,
CS_CMD_ACTOR_CUE_0_13,
CS_CMD_ACTOR_CUE_1_14,
CS_CMD_ACTOR_CUE_2_11,
CS_CMD_ACTOR_CUE_0_14 = 0x7B,
CS_CMD_FADE_OUT_SEQ,
CS_CMD_ACTOR_CUE_1_15,
CS_CMD_ACTOR_CUE_2_12,
CS_CMD_ACTOR_CUE_3_11,
CS_CMD_ACTOR_CUE_4_7,
CS_CMD_ACTOR_CUE_5_5,
CS_CMD_ACTOR_CUE_6_6,
CS_CMD_ACTOR_CUE_1_16,
CS_CMD_ACTOR_CUE_2_13,
CS_CMD_ACTOR_CUE_3_12,
CS_CMD_ACTOR_CUE_7_5,
CS_CMD_ACTOR_CUE_4_8,
CS_CMD_ACTOR_CUE_5_6,
CS_CMD_ACTOR_CUE_6_7,
CS_CMD_ACTOR_CUE_0_15,
CS_CMD_ACTOR_CUE_0_16,
CS_CMD_TIME,
CS_CMD_ACTOR_CUE_1_17,
CS_CMD_ACTOR_CUE_7_6,
CS_CMD_ACTOR_CUE_9_0,
CS_CMD_ACTOR_CUE_0_17,
CS_CMD_DESTINATION = 0x03E8,
CS_CMD_END = 0xFFFF
};
/**** GENERIC ****/
class CutsceneOoTSubCommandEntry_GenericCmd : public CutsceneSubCommandEntry
{
public:
CutsceneOoT_CommandType commandId;
uint32_t word0 = 0;
uint32_t word1 = 0;
uint32_t unused1 = 0;
uint32_t unused2 = 0;
uint32_t unused3 = 0;
uint32_t unused4 = 0;
uint32_t unused5 = 0;
uint32_t unused6 = 0;
uint32_t unused7 = 0;
uint32_t unused8 = 0;
uint32_t unused9 = 0;
uint32_t unused10 = 0;
CutsceneOoTSubCommandEntry_GenericCmd(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex, CutsceneOoT_CommandType cmdId);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneOoTCommand_GenericCmd : public CutsceneCommand
{
public:
CutsceneOoTCommand_GenericCmd(const std::vector<uint8_t>& rawData, offset_t rawDataIndex,
CutsceneOoT_CommandType cmdId);
std::string GetCommandMacro() const override;
};
/**** CAMERA ****/
class CutsceneOoTCommand_CameraPoint : public CutsceneSubCommandEntry
{
public:
int8_t continueFlag;
int8_t cameraRoll;
int16_t nextPointFrame;
float viewAngle;
int16_t posX, posY, posZ;
int16_t unused;
CutsceneOoTCommand_CameraPoint(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneOoTCommand_GenericCameraCmd : public CutsceneCommand
{
public:
uint16_t base;
uint16_t startFrame;
uint16_t endFrame;
uint16_t unused;
CutsceneOoTCommand_GenericCameraCmd(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
size_t GetCommandSize() const override;
};
/**** TRANSITION ****/
class CutsceneOoTCommand_Transition : public CutsceneCommand
{
public:
uint16_t base;
uint16_t startFrame;
uint16_t endFrame;
CutsceneOoTCommand_Transition(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GenerateSourceCode() const override;
size_t GetCommandSize() const override;
};
/**** RUMBLE ****/
class CutsceneOoTSubCommandEntry_Rumble : public CutsceneSubCommandEntry
{
public:
uint8_t sourceStrength;
uint8_t duration;
uint8_t decreaseRate;
uint8_t unk_09;
uint8_t unk_0A;
CutsceneOoTSubCommandEntry_Rumble(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneOoTCommand_Rumble : public CutsceneCommand
{
public:
CutsceneOoTCommand_Rumble(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};
/**** TEXT ****/
class CutsceneOoTSubCommandEntry_Text : public CutsceneSubCommandEntry
{
public:
uint16_t type;
uint16_t textId1;
uint16_t textId2;
CutsceneOoTSubCommandEntry_Text(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneOoTCommand_Text : public CutsceneCommand
{
public:
CutsceneOoTCommand_Text(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};
/**** ACTOR CUE ****/
class CutsceneOoTSubCommandEntry_ActorCue : public CutsceneSubCommandEntry
{
public:
uint16_t rotX, rotY, rotZ;
int32_t startPosX, startPosY, startPosZ;
int32_t endPosX, endPosY, endPosZ;
float normalX, normalY, normalZ;
CutsceneOoTSubCommandEntry_ActorCue(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneOoTCommand_ActorCue : public CutsceneCommand
{
public:
CutsceneOoTCommand_ActorCue(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};
/**** DESTINATION ****/
class CutsceneOoTCommand_Destination : public CutsceneCommand
{
public:
uint16_t base;
uint16_t startFrame;
uint16_t endFrame;
uint16_t unknown;
CutsceneOoTCommand_Destination(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GenerateSourceCode() const override;
size_t GetCommandSize() const override;
};

View File

@@ -0,0 +1,128 @@
#include "Cutscene_Common.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
/* CutsceneSubCommandEntry */
CutsceneSubCommandEntry::CutsceneSubCommandEntry(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
{
base = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0);
startFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
endFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4);
pad = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6);
}
std::string CutsceneSubCommandEntry::GetBodySourceCode() const
{
return StringHelper::Sprintf("CMD_HH(0x%04X, 0x%04X), CMD_HH(0x%04X, 0x%04X)", base, startFrame,
endFrame, pad);
}
size_t CutsceneSubCommandEntry::GetRawSize() const
{
return 0x08;
}
/* CutsceneCommand */
CutsceneCommand::CutsceneCommand(const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
{
numEntries = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0);
}
CutsceneCommand::~CutsceneCommand()
{
for (auto entry : entries)
{
delete entry;
}
}
std::string CutsceneCommand::GetCommandMacro() const
{
return StringHelper::Sprintf("CMD_W(0x%08X), CMD_W(0x%08X)", commandID, numEntries);
}
std::string CutsceneCommand::GenerateSourceCode() const
{
std::string result;
result += GetCommandMacro();
result += ",\n";
for (auto& entry : entries)
{
result += " ";
result += entry->GetBodySourceCode();
result += ",\n";
}
return result;
}
size_t CutsceneCommand::GetCommandSize() const
{
size_t size = 0;
if (entries.size() > 0)
{
size = entries.at(0)->GetRawSize() * entries.size();
}
else
{
size = 0x08 * numEntries;
}
return 0x08 + size;
}
void CutsceneCommand::SetCommandID(uint32_t nCommandID)
{
commandID = nCommandID;
for (auto& entry : entries)
{
entry->commandID = commandID;
}
}
/*** TIME ****/
CutsceneSubCommandEntry_SetTime::CutsceneSubCommandEntry_SetTime(
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
: CutsceneSubCommandEntry(rawData, rawDataIndex)
{
hour = BitConverter::ToUInt8BE(rawData, rawDataIndex + 6);
minute = BitConverter::ToUInt8BE(rawData, rawDataIndex + 7);
}
std::string CutsceneSubCommandEntry_SetTime::GetBodySourceCode() const
{
// Note: Both OoT and MM have the first argument unused
return StringHelper::Sprintf("CS_TIME(%i, %i, %i, %i, %i)", base, startFrame, endFrame, hour,
minute);
}
size_t CutsceneSubCommandEntry_SetTime::GetRawSize() const
{
return 0x0C;
}
CutsceneCommand_Time::CutsceneCommand_Time(const std::vector<uint8_t>& rawData,
offset_t rawDataIndex)
: CutsceneCommand(rawData, rawDataIndex)
{
rawDataIndex += 4;
entries.reserve(numEntries);
for (size_t i = 0; i < numEntries; i++)
{
auto* entry = new CutsceneSubCommandEntry_SetTime(rawData, rawDataIndex);
entries.push_back(entry);
rawDataIndex += entry->GetRawSize();
}
}
std::string CutsceneCommand_Time::GetCommandMacro() const
{
return StringHelper::Sprintf("CS_TIME_LIST(%i)", numEntries);
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "Declaration.h"
typedef struct CsCommandListDescriptor
{
const char* cmdMacro;
const char* args;
} CsCommandListDescriptor;
class CutsceneSubCommandEntry
{
public:
uint16_t base;
uint16_t startFrame;
uint16_t endFrame;
uint16_t pad;
uint32_t commandID;
CutsceneSubCommandEntry(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
virtual ~CutsceneSubCommandEntry() = default;
virtual std::string GetBodySourceCode() const;
virtual size_t GetRawSize() const;
};
class CutsceneCommand
{
public:
uint32_t commandID;
uint32_t commandIndex;
uint32_t numEntries;
std::vector<CutsceneSubCommandEntry*> entries;
CutsceneCommand(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
virtual ~CutsceneCommand();
virtual std::string GetCommandMacro() const;
virtual std::string GenerateSourceCode() const;
virtual size_t GetCommandSize() const;
virtual void SetCommandID(uint32_t nCommandID);
};
/**** TIME ****/
class CutsceneSubCommandEntry_SetTime : public CutsceneSubCommandEntry
{
public:
uint8_t hour;
uint8_t minute;
CutsceneSubCommandEntry_SetTime(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetBodySourceCode() const override;
size_t GetRawSize() const override;
};
class CutsceneCommand_Time : public CutsceneCommand
{
public:
CutsceneCommand_Time(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
std::string GetCommandMacro() const override;
};

View File

@@ -0,0 +1,354 @@
#include "SkinLimbStructs.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "ZDisplayList.h"
#include "ZFile.h"
/* SkinVertex */
SkinVertex::SkinVertex(ZFile* nParent) : ZResource(nParent)
{
}
void SkinVertex::ParseRawData()
{
const auto& rawData = parent->GetRawData();
index = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x00);
s = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x02);
t = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x04);
normX = BitConverter::ToInt8BE(rawData, rawDataIndex + 0x06);
normY = BitConverter::ToInt8BE(rawData, rawDataIndex + 0x07);
normZ = BitConverter::ToInt8BE(rawData, rawDataIndex + 0x08);
alpha = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x09);
}
std::string SkinVertex::GetBodySourceCode() const
{
return StringHelper::Sprintf("0x%02X, %i, %i, %i, %i, %i, 0x%02X", index, s, t, normX, normY,
normZ, alpha);
}
std::string SkinVertex::GetSourceTypeName() const
{
return "SkinVertex";
}
ZResourceType SkinVertex::GetResourceType() const
{
// TODO
return ZResourceType::Error;
}
size_t SkinVertex::GetRawDataSize() const
{
return 0x0A;
}
/* SkinTransformation */
SkinTransformation::SkinTransformation(ZFile* nParent) : ZResource(nParent)
{
}
void SkinTransformation::ParseRawData()
{
const auto& rawData = parent->GetRawData();
limbIndex = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x00);
x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x02);
y = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x04);
z = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x06);
scale = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x08);
}
std::string SkinTransformation::GetBodySourceCode() const
{
return StringHelper::Sprintf("0x%02X, %i, %i, %i, 0x%02X", limbIndex, x, y, z, scale);
}
std::string SkinTransformation::GetSourceTypeName() const
{
return "SkinTransformation";
}
ZResourceType SkinTransformation::GetResourceType() const
{
// TODO
return ZResourceType::Error;
}
size_t SkinTransformation::GetRawDataSize() const
{
return 0x0A;
}
/* SkinLimbModif */
SkinLimbModif::SkinLimbModif(ZFile* nParent) : ZResource(nParent)
{
}
void SkinLimbModif::ParseRawData()
{
const auto& rawData = parent->GetRawData();
vtxCount = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x00);
transformCount = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x02);
unk_4 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x04);
skinVertices = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x08);
limbTransformations = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0C);
if (skinVertices != 0 && GETSEGNUM(skinVertices) == parent->segment)
{
uint32_t unk_8_Offset = Seg2Filespace(skinVertices, parent->baseAddress);
skinVertices_arr.reserve(vtxCount);
for (size_t i = 0; i < vtxCount; i++)
{
SkinVertex skinVertices_data(parent);
skinVertices_data.ExtractFromFile(unk_8_Offset);
skinVertices_arr.push_back(skinVertices_data);
unk_8_Offset += skinVertices_data.GetRawDataSize();
}
}
if (limbTransformations != 0 && GETSEGNUM(skinVertices) == parent->segment)
{
uint32_t unk_C_Offset = Seg2Filespace(limbTransformations, parent->baseAddress);
limbTransformations_arr.reserve(transformCount);
for (size_t i = 0; i < transformCount; i++)
{
SkinTransformation limbTransformations_data(parent);
limbTransformations_data.ExtractFromFile(unk_C_Offset);
limbTransformations_arr.push_back(limbTransformations_data);
unk_C_Offset += limbTransformations_data.GetRawDataSize();
}
}
}
void SkinLimbModif::DeclareReferences(const std::string& prefix)
{
std::string varPrefix = prefix;
if (name != "")
varPrefix = name;
if (skinVertices != 0 && GETSEGNUM(skinVertices) == parent->segment)
{
const auto& res = skinVertices_arr.at(0);
std::string unk_8_Str = res.GetDefaultName(varPrefix);
size_t arrayItemCnt = skinVertices_arr.size();
std::string entryStr = "";
for (size_t i = 0; i < arrayItemCnt; i++)
{
auto& child = skinVertices_arr[i];
child.DeclareReferences(varPrefix);
entryStr += StringHelper::Sprintf("\t{ %s },", child.GetBodySourceCode().c_str());
if (i < arrayItemCnt - 1)
entryStr += "\n";
}
uint32_t skinVertices_Offset = Seg2Filespace(skinVertices, parent->baseAddress);
Declaration* decl = parent->GetDeclaration(skinVertices_Offset);
if (decl == nullptr)
{
parent->AddDeclarationArray(skinVertices_Offset, res.GetDeclarationAlignment(),
arrayItemCnt * res.GetRawDataSize(),
res.GetSourceTypeName(), unk_8_Str, arrayItemCnt, entryStr);
}
else
decl->declBody = entryStr;
}
if (limbTransformations != 0 && GETSEGNUM(limbTransformations) == parent->segment)
{
const auto& res = limbTransformations_arr.at(0);
std::string unk_C_Str = res.GetDefaultName(varPrefix);
size_t arrayItemCnt = limbTransformations_arr.size();
std::string entryStr = "";
for (size_t i = 0; i < arrayItemCnt; i++)
{
auto& child = limbTransformations_arr[i];
child.DeclareReferences(varPrefix);
entryStr += StringHelper::Sprintf("\t{ %s },", child.GetBodySourceCode().c_str());
if (i < arrayItemCnt - 1)
entryStr += "\n";
}
uint32_t unk_C_Offset = Seg2Filespace(limbTransformations, parent->baseAddress);
Declaration* decl = parent->GetDeclaration(unk_C_Offset);
if (decl == nullptr)
{
parent->AddDeclarationArray(unk_C_Offset, res.GetDeclarationAlignment(),
arrayItemCnt * res.GetRawDataSize(),
res.GetSourceTypeName(), unk_C_Str, arrayItemCnt, entryStr);
}
else
decl->declBody = entryStr;
}
}
std::string SkinLimbModif::GetBodySourceCode() const
{
std::string skinVertices_Str;
std::string unk_C_Str;
Globals::Instance->GetSegmentedPtrName(skinVertices, parent, "SkinVertex", skinVertices_Str, parent->workerID);
Globals::Instance->GetSegmentedPtrName(limbTransformations, parent, "SkinTransformation",
unk_C_Str, parent->workerID);
std::string entryStr = StringHelper::Sprintf("\n\t\tARRAY_COUNTU(%s), ARRAY_COUNTU(%s),\n",
skinVertices_Str.c_str(), unk_C_Str.c_str());
entryStr += StringHelper::Sprintf("\t\t%i, %s, %s\n\t", unk_4, skinVertices_Str.c_str(),
unk_C_Str.c_str());
return entryStr;
}
std::string SkinLimbModif::GetSourceTypeName() const
{
return "SkinLimbModif";
}
ZResourceType SkinLimbModif::GetResourceType() const
{
// TODO
return ZResourceType::Error;
}
size_t SkinLimbModif::GetRawDataSize() const
{
return 0x10;
}
/* SkinAnimatedLimbData */
SkinAnimatedLimbData::SkinAnimatedLimbData(ZFile* nParent) : ZResource(nParent)
{
}
void SkinAnimatedLimbData::ParseRawData()
{
const auto& rawData = parent->GetRawData();
totalVtxCount = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x00);
limbModifCount = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x02);
limbModifications = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x04);
dlist = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x08);
if (limbModifications != 0 && GETSEGNUM(limbModifications) == parent->segment)
{
uint32_t limbModifications_Offset = Seg2Filespace(limbModifications, parent->baseAddress);
limbModifications_arr.reserve(limbModifCount);
for (size_t i = 0; i < limbModifCount; i++)
{
SkinLimbModif limbModifications_data(parent);
limbModifications_data.ExtractFromFile(limbModifications_Offset);
limbModifications_arr.push_back(limbModifications_data);
limbModifications_Offset += limbModifications_data.GetRawDataSize();
}
}
}
void SkinAnimatedLimbData::DeclareReferences(const std::string& prefix)
{
std::string varPrefix = prefix;
if (name != "")
varPrefix = name;
ZResource::DeclareReferences(varPrefix);
if (limbModifications != SEGMENTED_NULL && GETSEGNUM(limbModifications) == parent->segment)
{
const auto& res = limbModifications_arr.at(0);
std::string limbModifications_Str = res.GetDefaultName(varPrefix);
size_t arrayItemCnt = limbModifications_arr.size();
std::string entryStr = "";
for (size_t i = 0; i < arrayItemCnt; i++)
{
auto& child = limbModifications_arr[i];
child.DeclareReferences(varPrefix);
entryStr += StringHelper::Sprintf("\t{ %s },", child.GetBodySourceCode().c_str());
if (i < arrayItemCnt - 1)
entryStr += "\n";
}
uint32_t limbModifications_Offset = Seg2Filespace(limbModifications, parent->baseAddress);
Declaration* decl = parent->GetDeclaration(limbModifications_Offset);
if (decl == nullptr)
{
parent->AddDeclarationArray(limbModifications_Offset, res.GetDeclarationAlignment(),
arrayItemCnt * res.GetRawDataSize(),
res.GetSourceTypeName(), limbModifications_Str,
arrayItemCnt, entryStr);
}
else
decl->declBody = entryStr;
}
if (dlist != SEGMENTED_NULL && GETSEGNUM(dlist) == parent->segment)
{
uint32_t dlist_Offset = Seg2Filespace(dlist, parent->baseAddress);
int32_t dlistLength = ZDisplayList::GetDListLength(
parent->GetRawData(), dlist_Offset,
Globals::Instance->game == ZGame::OOT_SW97 ? DListType::F3DEX : DListType::F3DZEX);
ZDisplayList* dlist_data = new ZDisplayList(parent);
dlist_data->ExtractFromBinary(dlist_Offset, dlistLength);
std::string dListStr =
StringHelper::Sprintf("%sSkinLimbDL_%06X", varPrefix.c_str(), dlist_Offset);
dlist_data->SetName(dListStr);
dlist_data->DeclareVar(varPrefix, "");
dlist_data->DeclareReferences(varPrefix);
parent->AddResource(dlist_data);
}
}
std::string SkinAnimatedLimbData::GetBodySourceCode() const
{
std::string limbModifications_Str;
std::string dlist_Str;
Globals::Instance->GetSegmentedPtrName(limbModifications, parent, "SkinLimbModif",
limbModifications_Str, parent->workerID);
Globals::Instance->GetSegmentedPtrName(dlist, parent, "Gfx", dlist_Str, parent->workerID);
std::string entryStr = "\n";
entryStr += StringHelper::Sprintf("\t%i, ARRAY_COUNTU(%s),\n", totalVtxCount,
limbModifications_Str.c_str());
entryStr +=
StringHelper::Sprintf("\t%s, %s\n", limbModifications_Str.c_str(), dlist_Str.c_str());
return entryStr;
}
std::string SkinAnimatedLimbData::GetSourceTypeName() const
{
return "SkinAnimatedLimbData";
}
ZResourceType SkinAnimatedLimbData::GetResourceType() const
{
// TODO
return ZResourceType::Error;
}
size_t SkinAnimatedLimbData::GetRawDataSize() const
{
return 0x0C;
}

View File

@@ -0,0 +1,111 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "ZResource.h"
#include "ZDisplayList.h"
enum class ZLimbSkinType
{
SkinType_Null, // SkinLimb segment = NULL
SkinType_Animated = 4, // SkinLimb segment = SkinAnimatedLimbData*
SkinType_Normal = 11, // SkinLimb segment = Gfx*
};
class SkinVertex : public ZResource
{
public:
SkinVertex(ZFile* nParent);
void ParseRawData() override;
std::string GetBodySourceCode() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
public:
uint16_t index;
int16_t s;
int16_t t;
int8_t normX;
int8_t normY;
int8_t normZ;
uint8_t alpha;
};
class SkinTransformation : public ZResource
{
public:
SkinTransformation(ZFile* nParent);
void ParseRawData() override;
std::string GetBodySourceCode() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
public:
uint8_t limbIndex;
int16_t x;
int16_t y;
int16_t z;
uint8_t scale;
};
class SkinLimbModif : public ZResource
{
public:
SkinLimbModif(ZFile* nParent);
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;
uint16_t vtxCount; // Number of vertices in this modif entry
uint16_t transformCount; // Length of limbTransformations
uint16_t unk_4; // 0 or 1, used as an index for limbTransformations
segptr_t skinVertices; // SkinVertex*
segptr_t limbTransformations; // SkinTransformation*
std::vector<SkinVertex> skinVertices_arr;
std::vector<SkinTransformation> limbTransformations_arr;
};
class SkinAnimatedLimbData : public ZResource
{
public:
SkinAnimatedLimbData(ZFile* nParent);
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;
public:
uint16_t totalVtxCount;
uint16_t limbModifCount; // Length of limbModifications
segptr_t limbModifications; // SkinLimbModif*
segptr_t dlist; // Gfx*
std::vector<SkinLimbModif> limbModifications_arr;
// ZDisplayList* unk_8_dlist = nullptr;
};

View File

@@ -0,0 +1,123 @@
#include "OutputFormatter.h"
#include <Globals.h>
void OutputFormatter::Flush()
{
//if (!Globals::Instance->otrMode) // OTRTODO: MULTITHREADING
{
if (col > lineLimit && !Globals::Instance->otrMode)
{
str.append(1, '\n');
str.append(currentIndent, ' ');
uint32_t newCol = currentIndent + (wordP - word);
for (uint32_t i = 0; i < wordNests; i++)
nestIndent[nest - i] -= col - newCol;
col = newCol;
}
else
{
str.append(space, spaceP - space);
}
spaceP = space;
str.append(word, wordP - word);
wordP = word;
wordNests = 0;
}
}
int OutputFormatter::Write(const char* buf, int count)
{
// OTRTODO
//if (!Globals::Instance->singleThreaded)
//return 0;
for (int i = 0; i < count; i++)
{
char c = buf[i];
if (c == ' ' || c == '\t' || c == '\n')
{
if (wordP - word != 0)
{
Flush();
}
if (c == '\n')
{
col = 0;
*spaceP++ = c;
}
else if (c == '\t')
{
int n = tabSize - (col % tabSize);
col += n;
for (int j = 0; j < n; j++)
*spaceP++ = ' ';
}
else
{
col++;
*spaceP++ = c;
}
currentIndent = nestIndent[nest];
}
else
{
col++;
if (c == '(')
{
nest++;
nestIndent[nest] = col;
wordNests++;
}
else if (c == ')')
{
if (nest > 0)
nest--;
if (wordNests > 0)
wordNests--;
}
*wordP++ = c;
}
}
return count;
}
int OutputFormatter::Write(const std::string& buf)
{
return Write(buf.data(), buf.size());
}
thread_local OutputFormatter* OutputFormatter::Instance;
int OutputFormatter::WriteStatic(const char* buf, int count)
{
return Instance->Write(buf, count);
}
int (*OutputFormatter::StaticWriter())(const char* buf, int count)
{
Instance = this;
return &WriteStatic;
}
OutputFormatter::OutputFormatter(uint32_t tabSize, uint32_t indentation, uint32_t lineLimit)
: tabSize{tabSize}, lineLimit{lineLimit}, col{0}, nest{0}, nestIndent{indentation},
currentIndent{indentation}, wordNests(0), wordP{word}, spaceP{space}
{
}
std::string OutputFormatter::GetOutput()
{
Flush();
return std::move(str);
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include <cstdint>
class OutputFormatter
{
private:
const uint32_t tabSize;
const uint32_t lineLimit;
uint32_t col;
uint32_t nest;
uint32_t nestIndent[8];
uint32_t currentIndent;
uint32_t wordNests;
char word[128];
char space[128];
char* wordP;
char* spaceP;
std::string str;
void Flush();
static thread_local OutputFormatter* Instance;
static int WriteStatic(const char* buf, int count);
public:
OutputFormatter(uint32_t tabSize = 4, uint32_t indentation = 4, uint32_t lineLimit = 120);
int (*StaticWriter())(const char* buf, int count); // Must be `int` due to libgfxd
int Write(const char* buf, int count);
int Write(const std::string& buf);
std::string GetOutput();
};

View File

@@ -0,0 +1,354 @@
#if 0
#include "ZOverlay.h"
#include <cassert>
#include <unordered_set>
#include "Globals.h"
#include "Utils/Directory.h"
#include <Utils/DiskFile.h>
#include "Utils/Path.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
using namespace ELFIO;
const char* RelocationEntry::GetSectionName() const
{
switch (sectionType)
{
case SectionType::Text:
return ".text";
case SectionType::Data:
return ".data";
case SectionType::RoData:
return ".rodata";
case SectionType::Bss:
return ".bss";
case SectionType::ERROR:
return ".ERROR";
}
assert(!"Oh no :c");
}
const char* RelocationEntry::GetRelocTypeName() const
{
switch (relocationType)
{
case RelocationType::R_MIPS_32:
return "R_MIPS_32";
case RelocationType::R_MIPS_26:
return "R_MIPS_26";
case RelocationType::R_MIPS_HI16:
return "R_MIPS_HI16";
case RelocationType::R_MIPS_LO16:
return "R_MIPS_LO16";
}
assert(!"Oh no :c");
}
ZOverlay::ZOverlay()
{
name = "";
entries = std::vector<RelocationEntry*>();
}
ZOverlay::ZOverlay(const std::string& nName) : ZOverlay()
{
name = nName;
}
ZOverlay::~ZOverlay()
{
for (auto entry : entries)
if (entry)
delete entry;
entries.clear();
}
static const std::unordered_set<std::string> sRelSections = {
".rel.text",
".rel.data",
".rel.rodata",
};
static const std::unordered_set<std::string> sSections = {
".text", ".data", ".symtab", ".rodata", ".rodata.str1.4", ".rodata.cst4", ".rodata.cst8",
};
ZOverlay* ZOverlay::FromBuild(fs::path buildPath, fs::path cfgFolderPath)
{
std::string cfgText = DiskFile::ReadAllText(cfgFolderPath / "overlay.cfg");
std::vector<std::string> cfgLines = StringHelper::Split(cfgText, "\n");
ZOverlay* ovl = new ZOverlay(StringHelper::Strip(cfgLines[0], "\r"));
ovl->cfgLines = cfgLines;
int32_t sectionOffs[5] = {0};
std::vector<RelocationEntry*> textRelocs;
std::vector<RelocationEntry*> dataRelocs;
std::vector<RelocationEntry*> rodataRelocs;
// get the elf files
std::vector<elfio*> readers;
for (size_t i = 1; i < cfgLines.size(); i++)
{
std::string elfPath =
(buildPath / (cfgLines[i].substr(0, cfgLines[i].size() - 2) + ".o")).string();
elfio* reader = new elfio();
if (!reader->load(elfPath))
{
// not all files were compiled
for (auto r : readers)
delete r;
readers.clear();
delete ovl;
return nullptr;
}
readers.push_back(reader);
}
for (size_t curReaderId = 0; curReaderId < readers.size(); curReaderId++)
{
auto& curReader = readers[curReaderId];
Elf_Half sec_num = curReader->sections.size();
for (int32_t i = 0; i < sec_num; i++)
{
section* pSec = curReader->sections[i];
if (pSec->get_type() != SHT_REL ||
sRelSections.find(pSec->get_name()) == sRelSections.end())
{
continue;
}
symbol_section_accessor currentSymbols(*curReader,
curReader->sections[(Elf_Half)pSec->get_link()]);
SectionType sectionType = GetSectionTypeFromStr(pSec->get_name());
if (sectionType == SectionType::ERROR)
{
HANDLE_WARNING(WarningType::Always, "one of the section types returned ERROR", "");
}
relocation_section_accessor relocs(*curReader, pSec);
for (Elf_Xword j = 0; j < relocs.get_entries_num(); j++)
{
Elf64_Addr offset = 0;
Elf_Word symbol = 0;
Elf_Word type = 0;
{
Elf_Sxword addend = 0;
relocs.get_entry(j, offset, symbol, type, addend);
}
std::string curSymName;
Elf_Half curSymShndx = SHN_UNDEF;
{
Elf64_Addr value;
Elf_Xword size;
unsigned char bind;
unsigned char type;
unsigned char other;
currentSymbols.get_symbol(symbol, curSymName, value, size, bind, type,
curSymShndx, other);
}
// check symbols outside the elf but within the overlay
if (curSymShndx == SHN_UNDEF)
{
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG)
{
printf("Symbol '%s' doesn't exist in current .o file (%s). Searching...\n",
curSymName.c_str(), cfgLines[curReaderId + 1].c_str());
}
for (size_t readerId = 0; readerId < readers.size(); readerId++)
{
auto& reader = readers[readerId];
if (curSymShndx != SHN_UNDEF)
break;
if (reader == curReader)
continue;
auto sectionData = reader->sections[(Elf_Half)pSec->get_link()];
curSymShndx =
ovl->FindSymbolInSection(curSymName, sectionData, *reader, readerId);
if (curSymShndx != SHN_UNDEF)
break;
if (Globals::Instance->gccCompat)
{
// Symbol wasn't found, try checking every section
Elf_Half sec_num = reader->sections.size();
for (int32_t otherSectionIdx = 0; otherSectionIdx < sec_num;
otherSectionIdx++)
{
if (curSymShndx != SHN_UNDEF)
{
break;
}
auto sectionDataIter = reader->sections[otherSectionIdx];
curSymShndx = ovl->FindSymbolInSection(curSymName, sectionDataIter,
*reader, readerId);
}
}
}
}
if (curSymShndx != SHN_UNDEF)
{
RelocationType typeConverted = (RelocationType)type;
offset += sectionOffs[static_cast<size_t>(sectionType)];
RelocationEntry* reloc =
new RelocationEntry(sectionType, typeConverted, offset);
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG)
{
printf(".word 0x%08X # %s %s 0x%04X\n", reloc->CalcRelocationWord(),
reloc->GetSectionName(), reloc->GetRelocTypeName(), reloc->offset);
}
// this is to keep the correct reloc entry order
if (sectionType == SectionType::Text)
textRelocs.push_back(reloc);
if (sectionType == SectionType::Data)
dataRelocs.push_back(reloc);
if (sectionType == SectionType::RoData)
rodataRelocs.push_back(reloc);
}
}
}
// increase section offsets
for (int32_t i = 0; i < sec_num; i++)
{
section* pSec = curReader->sections[i];
if (pSec->get_type() == SHT_PROGBITS &&
sSections.find(pSec->get_name()) != sSections.end())
{
SectionType sectionType = GetSectionTypeFromStr(pSec->get_name());
sectionOffs[static_cast<size_t>(sectionType)] += pSec->get_size();
}
}
}
ovl->entries.reserve(textRelocs.size() + dataRelocs.size() + rodataRelocs.size());
ovl->entries.insert(ovl->entries.end(), textRelocs.begin(), textRelocs.end());
ovl->entries.insert(ovl->entries.end(), dataRelocs.begin(), dataRelocs.end());
ovl->entries.insert(ovl->entries.end(), rodataRelocs.begin(), rodataRelocs.end());
for (auto r : readers)
delete r;
readers.clear();
return ovl;
}
std::string ZOverlay::GetSourceOutputCode([[maybe_unused]] const std::string& prefix)
{
std::string output;
output += ".section .ovl\n";
output += StringHelper::Sprintf("# %sOverlayInfo\n", name.c_str());
output += StringHelper::Sprintf(".word _%sSegmentTextSize\n", name.c_str());
output += StringHelper::Sprintf(".word _%sSegmentDataSize\n", name.c_str());
output += StringHelper::Sprintf(".word _%sSegmentRoDataSize\n", name.c_str());
output += StringHelper::Sprintf(".word _%sSegmentBssSize\n", name.c_str());
output += "\n";
output += StringHelper::Sprintf(".word %i # reloc_count\n", entries.size());
for (size_t i = 0; i < entries.size(); i++)
{
RelocationEntry* reloc = entries[i];
output += StringHelper::Sprintf(".word 0x%08X # %s %s 0x%04X\n",
reloc->CalcRelocationWord(), reloc->GetSectionName(),
reloc->GetRelocTypeName(), reloc->offset);
}
size_t offset = (entries.size() * 4) + 20;
while (offset % 16 != 12)
{
output += ".word 0\n";
offset += 4;
}
output += "\n";
output +=
StringHelper::Sprintf(".word 0x%08X # %sOverlayInfoOffset\n", offset + 4, name.c_str());
return output;
}
SectionType ZOverlay::GetSectionTypeFromStr(const std::string& sectionName)
{
if (sectionName == ".rel.text" || sectionName == ".text")
return SectionType::Text;
else if (sectionName == ".rel.data" || sectionName == ".data")
return SectionType::Data;
else if (sectionName == ".rel.rodata" || sectionName == ".rodata" ||
sectionName == ".rodata.str1.4" || sectionName == ".rodata.cst4")
return SectionType::RoData;
else if (sectionName == ".rel.bss" || sectionName == ".bss")
return SectionType::Bss;
return SectionType::ERROR;
}
ELFIO::Elf_Half ZOverlay::FindSymbolInSection(const std::string& curSymName,
ELFIO::section* sectionData, ELFIO::elfio& reader,
size_t readerId)
{
if (sectionData == nullptr)
return SHN_UNDEF;
auto sectionDataName = sectionData->get_name();
if (sSections.find(sectionDataName) == sSections.end())
return SHN_UNDEF;
#ifdef DEVELOPMENT
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG)
{
printf("\t File '%s' section: %s \n", cfgLines[readerId + 1].c_str(),
sectionDataName.c_str());
}
#endif
symbol_section_accessor symbols(reader, sectionData);
Elf_Xword symbolNum = symbols.get_symbols_num();
for (Elf_Xword symIdx = 0; symIdx < symbolNum; symIdx++)
{
Elf_Half shndx = SHN_UNDEF;
Elf64_Addr value;
std::string name;
Elf_Xword size;
unsigned char bind;
unsigned char type;
unsigned char other;
symbols.get_symbol(symIdx, name, value, size, bind, type, shndx, other);
if (name == curSymName)
{
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG)
{
printf("\t Symbol '%s' found in '%s' '%s' \n", curSymName.c_str(),
cfgLines[readerId + 1].c_str(), sectionDataName.c_str());
}
return shndx;
}
}
return SHN_UNDEF;
}
#endif

View File

@@ -0,0 +1,78 @@
#pragma once
#if 0
#include "Utils/Directory.h"
#include "ZResource.h"
#include "elfio/elfio.hpp"
#include "tinyxml2.h"
enum class SectionType
{
Text = 1,
Data = 2,
RoData = 3,
Bss = 4,
ERROR = 255
};
enum class RelocationType
{
R_MIPS_32 = 2,
R_MIPS_26 = 4,
R_MIPS_HI16 = 5,
R_MIPS_LO16 = 6,
};
class RelocationEntry
{
public:
SectionType sectionType;
RelocationType relocationType;
int32_t offset;
RelocationEntry(SectionType nSecType, RelocationType nRelType, int32_t nOffset)
{
sectionType = nSecType;
relocationType = nRelType;
offset = nOffset;
}
uint32_t CalcRelocationWord()
{
uint32_t relocationWord = 0;
relocationWord |= static_cast<uint32_t>(sectionType) << 30;
relocationWord |= static_cast<uint32_t>(relocationType) << 24;
relocationWord |= offset;
return relocationWord;
}
const char* GetSectionName() const;
const char* GetRelocTypeName() const;
};
class ZOverlay
{
public:
std::string name;
ZOverlay(const std::string& nName);
~ZOverlay();
static ZOverlay* FromBuild(fs::path buildPath, fs::path cfgFolderPath);
std::string GetSourceOutputCode(const std::string& prefix);
private:
std::vector<RelocationEntry*> entries;
std::vector<std::string> cfgLines;
ZOverlay();
static SectionType GetSectionTypeFromStr(const std::string& sectionName);
// static std::string GetOverlayNameFromElf(ELFIO::elfio& reader);
ELFIO::Elf_Half FindSymbolInSection(const std::string& curSymName, ELFIO::section* sectionData,
ELFIO::elfio& reader, size_t readerId);
};
#endif

View File

@@ -0,0 +1,178 @@
#include "BinaryReader.h"
#include <cmath>
#include <stdexcept>
#include "Stream.h"
BinaryReader::BinaryReader(Stream* nStream)
{
stream.reset(nStream);
}
BinaryReader::BinaryReader(std::shared_ptr<Stream> nStream)
{
stream = nStream;
}
void BinaryReader::Close()
{
stream->Close();
}
void BinaryReader::SetEndianness(Endianness endianness)
{
this->endianness = endianness;
}
Endianness BinaryReader::GetEndianness() const
{
return endianness;
}
void BinaryReader::Seek(uint32_t offset, SeekOffsetType seekType)
{
stream->Seek(offset, seekType);
}
uint32_t BinaryReader::GetBaseAddress()
{
return stream->GetBaseAddress();
}
void BinaryReader::Read(int32_t length)
{
stream->Read(length);
}
void BinaryReader::Read(char* buffer, int32_t length)
{
stream->Read(buffer, length);
}
char BinaryReader::ReadChar()
{
return (char)stream->ReadByte();
}
int8_t BinaryReader::ReadByte()
{
return stream->ReadByte();
}
uint8_t BinaryReader::ReadUByte()
{
return (uint8_t)stream->ReadByte();
}
int16_t BinaryReader::ReadInt16()
{
int16_t result = 0;
stream->Read((char*)&result, sizeof(int16_t));
if (endianness != Endianness::Native)
result = BSWAP16(result);
return result;
}
int32_t BinaryReader::ReadInt32()
{
int32_t result = 0;
stream->Read((char*)&result, sizeof(int32_t));
if (endianness != Endianness::Native)
result = BSWAP32(result);
return result;
}
uint16_t BinaryReader::ReadUInt16()
{
uint16_t result = 0;
stream->Read((char*)&result, sizeof(uint16_t));
if (endianness != Endianness::Native)
result = BSWAP16(result);
return result;
}
uint32_t BinaryReader::ReadUInt32()
{
uint32_t result = 0;
stream->Read((char*)&result, sizeof(uint32_t));
if (endianness != Endianness::Native)
result = BSWAP32(result);
return result;
}
uint64_t BinaryReader::ReadUInt64()
{
uint64_t result = 0;
stream->Read((char*)&result, sizeof(uint64_t));
if (endianness != Endianness::Native)
result = BSWAP64(result);
return result;
}
float BinaryReader::ReadSingle()
{
float result = NAN;
stream->Read((char*)&result, sizeof(float));
if (endianness != Endianness::Native)
{
float tmp;
char* dst = (char*)&tmp;
char* src = (char*)&result;
dst[3] = src[0]; dst[2] = src[1]; dst[1] = src[2]; dst[0] = src[3];
result = tmp;
}
if (std::isnan(result))
throw std::runtime_error("BinaryReader::ReadSingle(): Error reading stream");
return result;
}
double BinaryReader::ReadDouble()
{
double result = NAN;
stream->Read((char*)&result, sizeof(double));
if (endianness != Endianness::Native)
{
double tmp;
char* dst = (char*)&tmp;
char* src = (char*)&result;
dst[7] = src[0]; dst[6] = src[1]; dst[5] = src[2]; dst[4] = src[3];
dst[3] = src[4]; dst[2] = src[5]; dst[1] = src[6]; dst[0] = src[7];
result = tmp;
}
if (std::isnan(result))
throw std::runtime_error("BinaryReader::ReadDouble(): Error reading stream");
return result;
}
std::string BinaryReader::ReadString()
{
std::string res;
int numChars = ReadInt32();
for (int i = 0; i < numChars; i++)
res += ReadChar();
return res;
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <array>
#include <memory>
#include <string>
#include <vector>
#include "BitConverter.h"
#include "Stream.h"
class BinaryReader
{
public:
BinaryReader(Stream* nStream);
BinaryReader(std::shared_ptr<Stream> nStream);
void Close();
void SetEndianness(Endianness endianness);
Endianness GetEndianness() const;
void Seek(uint32_t offset, SeekOffsetType seekType);
uint32_t GetBaseAddress();
void Read(int32_t length);
void Read(char* buffer, int32_t length);
char ReadChar();
int8_t ReadByte();
int16_t ReadInt16();
int32_t ReadInt32();
uint8_t ReadUByte();
uint16_t ReadUInt16();
uint32_t ReadUInt32();
uint64_t ReadUInt64();
float ReadSingle();
double ReadDouble();
std::string ReadString();
protected:
std::shared_ptr<Stream> stream;
Endianness endianness = Endianness::Native;
};

View File

@@ -0,0 +1,148 @@
#include "BinaryWriter.h"
BinaryWriter::BinaryWriter(Stream* nStream)
{
stream.reset(nStream);
}
BinaryWriter::BinaryWriter(std::shared_ptr<Stream> nStream)
{
stream = nStream;
}
void BinaryWriter::SetEndianness(Endianness endianness)
{
this->endianness = endianness;
}
void BinaryWriter::Close()
{
stream->Close();
}
std::shared_ptr<Stream> BinaryWriter::GetStream()
{
return stream;
}
uint64_t BinaryWriter::GetBaseAddress()
{
return stream->GetBaseAddress();
}
uint64_t BinaryWriter::GetLength()
{
return stream->GetLength();
}
void BinaryWriter::Seek(int32_t offset, SeekOffsetType seekType)
{
stream->Seek(offset, seekType);
}
void BinaryWriter::Write(int8_t value)
{
stream->Write((char*)&value, sizeof(int8_t));
}
void BinaryWriter::Write(uint8_t value)
{
stream->Write((char*)&value, sizeof(uint8_t));
}
void BinaryWriter::Write(int16_t value)
{
if (endianness != Endianness::Native)
value = BSWAP16(value);
stream->Write((char*)&value, sizeof(int16_t));
}
void BinaryWriter::Write(uint16_t value)
{
if (endianness != Endianness::Native)
value = BSWAP16(value);
stream->Write((char*)&value, sizeof(uint16_t));
}
void BinaryWriter::Write(int32_t value)
{
if (endianness != Endianness::Native)
value = BSWAP32(value);
stream->Write((char*)&value, sizeof(int32_t));
}
void BinaryWriter::Write(int32_t valueA, int32_t valueB)
{
Write(valueA);
Write(valueB);
}
void BinaryWriter::Write(uint32_t value)
{
if (endianness != Endianness::Native)
value = BSWAP32(value);
stream->Write((char*)&value, sizeof(uint32_t));
}
void BinaryWriter::Write(int64_t value)
{
if (endianness != Endianness::Native)
value = BSWAP64(value);
stream->Write((char*)&value, sizeof(int64_t));
}
void BinaryWriter::Write(uint64_t value)
{
if (endianness != Endianness::Native)
value = BSWAP64(value);
stream->Write((char*)&value, sizeof(uint64_t));
}
void BinaryWriter::Write(float value)
{
if (endianness != Endianness::Native)
{
float tmp;
char* dst = (char*)&tmp;
char* src = (char*)&value;
dst[3] = src[0]; dst[2] = src[1]; dst[1] = src[2]; dst[0] = src[3];
value = tmp;
}
stream->Write((char*)&value, sizeof(float));
}
void BinaryWriter::Write(double value)
{
if (endianness != Endianness::Native)
{
double tmp;
char* dst = (char*)&tmp;
char* src = (char*)&value;
dst[7] = src[0]; dst[6] = src[1]; dst[5] = src[2]; dst[4] = src[3];
dst[3] = src[4]; dst[2] = src[5]; dst[1] = src[6]; dst[0] = src[7];
value = tmp;
}
stream->Write((char*)&value, sizeof(double));
}
void BinaryWriter::Write(const std::string& str)
{
int strLen = str.size();
Write(strLen);
for (char c : str)
stream->WriteByte(c);
}
void BinaryWriter::Write(char* srcBuffer, size_t length)
{
stream->Write(srcBuffer, length);
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <array>
#include <memory>
#include <string>
#include <vector>
#include "BitConverter.h"
#include "Stream.h"
class BinaryWriter
{
public:
BinaryWriter(Stream* nStream);
BinaryWriter(std::shared_ptr<Stream> nStream);
void SetEndianness(Endianness endianness);
std::shared_ptr<Stream> GetStream();
uint64_t GetBaseAddress();
uint64_t GetLength();
void Seek(int32_t offset, SeekOffsetType seekType);
void Close();
void Write(int8_t value);
void Write(uint8_t value);
void Write(int16_t value);
void Write(uint16_t value);
void Write(int32_t value);
void Write(int32_t valueA, int32_t valueB);
void Write(uint32_t value);
void Write(int64_t value);
void Write(uint64_t value);
void Write(float value);
void Write(double value);
void Write(const std::string& str);
void Write(char* srcBuffer, size_t length);
protected:
std::shared_ptr<Stream> stream;
Endianness endianness = Endianness::Native;
};

View File

@@ -0,0 +1,209 @@
#pragma once
#include <cstdint>
#include <limits>
#include <vector>
#include <cstring>
#ifdef _MSC_VER
#define BSWAP16 _byteswap_ushort
#define BSWAP32 _byteswap_ulong
#define BSWAP64 _byteswap_uint64
#else
#define BSWAP16 __builtin_bswap16
#define BSWAP32 __builtin_bswap32
#define BSWAP64 __builtin_bswap64
#endif
enum class Endianness
{
Little = 0,
Big = 1,
#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || defined(__BIG_ENDIAN__)
Native = Big,
#else
Native = Little,
#endif
};
class BitConverter
{
public:
static inline int8_t ToInt8BE(const uint8_t* data, int32_t offset)
{
return (uint8_t)data[offset + 0];
}
static inline int8_t ToInt8BE(const std::vector<uint8_t>& data, int32_t offset)
{
return (uint8_t)data[offset + 0];
}
static inline uint8_t ToUInt8BE(const uint8_t* data, int32_t offset)
{
return (uint8_t)data[offset + 0];
}
static inline uint8_t ToUInt8BE(const std::vector<uint8_t>& data, int32_t offset)
{
return (uint8_t)data[offset + 0];
}
static inline int16_t ToInt16BE(const uint8_t* data, int32_t offset)
{
return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
}
static inline int16_t ToInt16BE(const std::vector<uint8_t>& data, int32_t offset)
{
return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
}
static inline uint16_t ToUInt16BE(const uint8_t* data, int32_t offset)
{
return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
}
static inline uint16_t ToUInt16BE(const std::vector<uint8_t>& data, int32_t offset)
{
return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
}
static inline int32_t ToInt32BE(const uint8_t* data, int32_t offset)
{
return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
}
static inline int32_t ToInt32BE(const std::vector<uint8_t>& data, int32_t offset)
{
return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
}
static inline uint32_t ToUInt32BE(const uint8_t* data, int32_t offset)
{
return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
}
static inline uint32_t ToUInt32BE(const std::vector<uint8_t>& data, int32_t offset)
{
return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
}
static inline int64_t ToInt64BE(const uint8_t* data, int32_t offset)
{
return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
}
static inline int64_t ToInt64BE(const std::vector<uint8_t>& data, int32_t offset)
{
return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
}
static inline uint64_t ToUInt64BE(const uint8_t* data, int32_t offset)
{
return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
}
static inline uint64_t ToUInt64BE(const std::vector<uint8_t>& data, int32_t offset)
{
return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
}
static inline float ToFloatBE(const uint8_t* data, int32_t offset)
{
float value;
uint32_t floatData = ((uint32_t)data[offset + 0] << 24) +
((uint32_t)data[offset + 1] << 16) +
((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float");
std::memcpy(&value, &floatData, sizeof(value));
return value;
}
static inline float ToFloatBE(const std::vector<uint8_t>& data, int32_t offset)
{
float value;
uint32_t floatData = ((uint32_t)data[offset + 0] << 24) +
((uint32_t)data[offset + 1] << 16) +
((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float");
std::memcpy(&value, &floatData, sizeof(value));
return value;
}
static inline double ToDoubleBE(const uint8_t* data, int32_t offset)
{
double value;
uint64_t floatData =
((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double");
// Checks if the float format on the platform the ZAPD binary is running on supports the
// same float format as the object file.
static_assert(std::numeric_limits<float>::is_iec559,
"expected IEC559 floats on host machine");
std::memcpy(&value, &floatData, sizeof(value));
return value;
}
static inline double ToDoubleBE(const std::vector<uint8_t>& data, int32_t offset)
{
double value;
uint64_t floatData =
((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double");
// Checks if the float format on the platform the ZAPD binary is running on supports the
// same float format as the object file.
static_assert(std::numeric_limits<double>::is_iec559,
"expected IEC559 doubles on host machine");
std::memcpy(&value, &floatData, sizeof(value));
return value;
}
// Rewrites the rom data in-place to be in BigEndian/z64 format
static inline void RomToBigEndian(uint8_t* rom, size_t romSize) {
if (romSize <= 0) {
return;
}
// Use the first byte to determine byte order
uint8_t firstByte = rom[0];
switch (firstByte) {
case 0x37: // v64
for (size_t pos = 0; pos < (romSize / 2); pos++) {
((uint16_t*)rom)[pos] = ToUInt16BE(rom, pos * 2);
}
break;
case 0x40: // n64
for (size_t pos = 0; pos < (romSize / 4); pos++) {
((uint32_t*)rom)[pos] = ToUInt32BE(rom, pos * 4);
}
break;
case 0x80: // z64
break; // Already BE, no need to swap
}
}
};

View File

@@ -0,0 +1,60 @@
#pragma once
#include <string>
#include <vector>
#include "StringHelper.h"
#include <iostream>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
#undef GetCurrentDirectory
#undef CreateDirectory
class Directory
{
public:
#ifndef PATH_HACK
static std::string GetCurrentDirectory() { return fs::current_path().string(); }
#endif
static bool Exists(const fs::path& path) { return fs::exists(path); }
// Stupid hack because of Windows.h
static void MakeDirectory(const std::string& path)
{
CreateDirectory(path);
}
static void CreateDirectory(const std::string& path)
{
try
{
fs::create_directories(path);
}
catch (...)
{
}
}
static std::vector<std::string> ListFiles(const std::string& dir)
{
std::vector<std::string> lst;
if (Exists(dir))
{
for (auto& p : fs::recursive_directory_iterator(dir))
{
if (!p.is_directory())
lst.push_back(p.path().generic_string());
}
}
return lst;
}
};

View File

@@ -0,0 +1,91 @@
#pragma once
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "Path.h"
#include "Utils/StringHelper.h"
#include "Utils/Directory.h"
class DiskFile
{
public:
static bool Exists(const fs::path& filePath)
{
std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
return file.good();
}
static std::vector<uint8_t> ReadAllBytes(const fs::path& filePath)
{
std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
if (!file)
return std::vector<uint8_t>();
int32_t fileSize = (int32_t)file.tellg();
file.seekg(0);
char* data = new char[fileSize];
file.read(data, fileSize);
std::vector<uint8_t> result = std::vector<uint8_t>(data, data + fileSize);
delete[] data;
return result;
};
static std::string ReadAllText(const fs::path& filePath)
{
std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
int32_t fileSize = (int32_t)file.tellg();
file.seekg(0);
char* data = new char[fileSize + 1];
memset(data, 0, fileSize + 1);
file.read(data, fileSize);
std::string str = std::string((const char*)data);
delete[] data;
return str;
};
static std::vector<std::string> ReadAllLines(const fs::path& filePath)
{
std::string text = ReadAllText(filePath);
std::vector<std::string> lines = StringHelper::Split(text, "\n");
return lines;
};
static void WriteAllBytes(const fs::path& filePath, const std::vector<uint8_t>& data)
{
std::ofstream file(filePath, std::ios::binary);
file.write((char*)data.data(), data.size());
};
static void WriteAllBytes(const std::string& filePath, const std::vector<char>& data)
{
if (!Directory::Exists(Path::GetDirectoryName(filePath))) {
Directory::MakeDirectory(Path::GetDirectoryName(filePath).string());
}
std::ofstream file(filePath, std::ios::binary);
file.write((char*)data.data(), data.size());
};
static void WriteAllBytes(const std::string& filePath, const char* data, int dataSize)
{
std::ofstream file(filePath, std::ios::binary);
file.write((char*)data, dataSize);
};
static void WriteAllText(const fs::path& filePath, const std::string& text)
{
if (!Directory::Exists(Path::GetDirectoryName(filePath))) {
Directory::MakeDirectory(Path::GetDirectoryName(filePath).string());
}
std::ofstream file(filePath, std::ios::out);
file.write(text.c_str(), text.size());
}
};

View File

@@ -0,0 +1,97 @@
#include "MemoryStream.h"
#include <cstring>
#ifndef _MSC_VER
#define memcpy_s(dest, destSize, source, sourceSize) memcpy(dest, source, destSize)
#endif
MemoryStream::MemoryStream()
{
buffer = std::vector<char>();
//buffer.reserve(1024 * 16);
bufferSize = 0;
baseAddress = 0;
}
MemoryStream::MemoryStream(char* nBuffer, size_t nBufferSize) : MemoryStream()
{
buffer = std::vector<char>(nBuffer, nBuffer + nBufferSize);
bufferSize = nBufferSize;
baseAddress = 0;
}
MemoryStream::~MemoryStream()
{
}
uint64_t MemoryStream::GetLength()
{
return buffer.size();
}
void MemoryStream::Seek(int32_t offset, SeekOffsetType seekType)
{
if (seekType == SeekOffsetType::Start)
baseAddress = offset;
else if (seekType == SeekOffsetType::Current)
baseAddress += offset;
else if (seekType == SeekOffsetType::End)
baseAddress = bufferSize - 1 - offset;
}
std::unique_ptr<char[]> MemoryStream::Read(size_t length)
{
std::unique_ptr<char[]> result = std::make_unique<char[]>(length);
memcpy_s(result.get(), length, &buffer[baseAddress], length);
baseAddress += length;
return result;
}
void MemoryStream::Read(const char* dest, size_t length)
{
memcpy_s((void*)dest, length, &buffer[baseAddress], length);
baseAddress += length;
}
int8_t MemoryStream::ReadByte()
{
return buffer[baseAddress++];
}
void MemoryStream::Write(char* srcBuffer, size_t length)
{
if (baseAddress + length >= buffer.size())
{
buffer.resize(baseAddress + length);
bufferSize += length;
}
memcpy_s(&buffer[baseAddress], length, srcBuffer, length);
baseAddress += length;
}
void MemoryStream::WriteByte(int8_t value)
{
if (baseAddress >= buffer.size())
{
buffer.resize(baseAddress + 1);
bufferSize = baseAddress;
}
buffer[baseAddress++] = value;
}
std::vector<char> MemoryStream::ToVector()
{
return buffer;
}
void MemoryStream::Flush()
{
}
void MemoryStream::Close()
{
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <memory>
#include <vector>
#include "Stream.h"
class MemoryStream : public Stream
{
public:
MemoryStream();
MemoryStream(char* nBuffer, size_t nBufferSize);
~MemoryStream();
uint64_t GetLength() override;
void Seek(int32_t offset, SeekOffsetType seekType) override;
std::unique_ptr<char[]> Read(size_t length) override;
void Read(const char* dest, size_t length) override;
int8_t ReadByte() override;
void Write(char* srcBuffer, size_t length) override;
void WriteByte(int8_t value) override;
std::vector<char> ToVector();
void Flush() override;
void Close() override;
protected:
std::vector<char> buffer;
std::size_t bufferSize;
};

50
ZAPDTR/ZAPD/Utils/Path.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#include <iostream>
#include <string>
#include "Utils/StringHelper.h"
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
class Path
{
public:
static std::string GetFileName(const fs::path& input)
{
// https://en.cppreference.com/w/cpp/filesystem/path/filename
return input.filename().string();
};
static std::string GetFileNameWithoutExtension(const fs::path& input)
{
// https://en.cppreference.com/w/cpp/filesystem/path/stem
return input.stem().string();
};
static std::string GetFileNameExtension(const std::string& input)
{
return input.substr(input.find_last_of("."), input.length());
};
static fs::path GetPath(const std::string& input)
{
std::vector<std::string> split = StringHelper::Split(input, "/");
fs::path output;
for (std::string str : split)
{
if (str.find_last_of(".") == std::string::npos)
output /= str;
}
return output;
};
static fs::path GetDirectoryName(const fs::path& path) { return path.parent_path(); };
};

View File

@@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#include <memory>
enum class SeekOffsetType
{
Start,
Current,
End
};
class Stream
{
public:
virtual ~Stream() = default;
virtual uint64_t GetLength() = 0;
uint64_t GetBaseAddress() { return baseAddress; }
virtual void Seek(int32_t offset, SeekOffsetType seekType) = 0;
virtual std::unique_ptr<char[]> Read(size_t length) = 0;
virtual void Read(const char* dest, size_t length) = 0;
virtual int8_t ReadByte() = 0;
virtual void Write(char* destBuffer, size_t length) = 0;
virtual void WriteByte(int8_t value) = 0;
virtual void Flush() = 0;
virtual void Close() = 0;
protected:
uint64_t baseAddress;
};

View File

@@ -0,0 +1,191 @@
#include "StringHelper.h"
#if (_MSC_VER)
#pragma optimize("2", on)
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _MSC_VER
#define vsprintf_s vsprintf
#endif
std::vector<std::string> StringHelper::Split(std::string s, const std::string& delimiter)
{
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string token;
std::vector<std::string> res;
while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
token = s.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.push_back(token);
}
res.push_back(s.substr(pos_start));
return res;
}
std::vector<std::string_view> StringHelper::Split(std::string_view s, const std::string& delimiter)
{
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string_view token;
std::vector<std::string_view> res;
while ((pos_end = s.find(delimiter, pos_start)) != std::string_view::npos)
{
token = s.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.push_back(token);
}
res.push_back(s.substr(pos_start));
return res;
}
std::string StringHelper::Strip(std::string s, const std::string& delimiter)
{
size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos)
{
token = s.substr(0, pos);
s.erase(pos, pos + delimiter.length());
}
return s;
}
std::string StringHelper::Replace(std::string str, const std::string& from,
const std::string& to)
{
size_t start_pos = str.find(from);
while (start_pos != std::string::npos)
{
str.replace(start_pos, from.length(), to);
start_pos = str.find(from);
}
return str;
}
void StringHelper::ReplaceOriginal(std::string& str, const std::string& from, const std::string& to)
{
size_t start_pos = str.find(from);
while (start_pos != std::string::npos)
{
str.replace(start_pos, from.length(), to);
start_pos = str.find(from);
}
}
bool StringHelper::StartsWith(const std::string& s, const std::string& input)
{
#if __cplusplus >= 202002L
return s.starts_with(input.c_str());
#else
return s.rfind(input, 0) == 0;
#endif
}
bool StringHelper::Contains(const std::string& s, const std::string& input)
{
return s.find(input) != std::string::npos;
}
bool StringHelper::EndsWith(const std::string& s, const std::string& input)
{
size_t inputLen = strlen(input.c_str());
return s.rfind(input) == (s.size() - inputLen);
}
std::string StringHelper::Sprintf(const char* format, ...)
{
char buffer[32768];
// char buffer[2048];
std::string output;
va_list va;
va_start(va, format);
vsprintf_s(buffer, format, va);
va_end(va);
output = buffer;
return output;
}
std::string StringHelper::Implode(std::vector<std::string>& elements,
const char* const separator)
{
return "";
// return std::accumulate(std::begin(elements), std::end(elements), std::string(),
//[separator](std::string& ss, std::string& s) {
// return ss.empty() ? s : ss + separator + s;
//});
}
int64_t StringHelper::StrToL(const std::string& str, int32_t base)
{
return std::strtoull(str.c_str(), nullptr, base);
}
std::string StringHelper::BoolStr(bool b)
{
return b ? "true" : "false";
}
bool StringHelper::HasOnlyDigits(const std::string& str)
{
return std::all_of(str.begin(), str.end(), ::isdigit);
}
// Validate a hex string based on the c89 standard
// https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Integer-Constants
bool StringHelper::IsValidHex(std::string_view str)
{
if (str.length() < 3)
{
return false;
}
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
{
return std::all_of(str.begin() + 2, str.end(), ::isxdigit);
}
return false;
}
bool StringHelper::IsValidHex(const std::string& str)
{
return IsValidHex(std::string_view(str.c_str()));
}
bool StringHelper::IsValidOffset(std::string_view str)
{
if (str.length() == 1)
{
// 0 is a valid offset
return isdigit(str[0]);
}
return IsValidHex(str);
}
bool StringHelper::IsValidOffset(const std::string& str)
{
if (str.length() == 1)
{
// 0 is a valid offset
return isdigit(str[0]);
}
return IsValidHex(str);
}
bool StringHelper::IEquals(const std::string& a, const std::string& b)
{
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
[](char a, char b) { return tolower(a) == tolower(b); });
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <algorithm>
#include <cstdarg>
#include <cstring>
#include <numeric>
#include <string>
#include <string_view>
#include <vector>
#include <cstdint>
class StringHelper
{
public:
static std::vector<std::string> Split(std::string s, const std::string& delimiter);
static std::vector<std::string_view> Split(std::string_view s, const std::string& delimiter);
static std::string Strip(std::string s, const std::string& delimiter);
static std::string Replace(std::string str, const std::string& from, const std::string& to);
static void ReplaceOriginal(std::string& str, const std::string& from, const std::string& to);
static bool StartsWith(const std::string& s, const std::string& input);
static bool Contains(const std::string& s, const std::string& input);
static bool EndsWith(const std::string& s, const std::string& input);
static std::string Sprintf(const char* format, ...);
static std::string Implode(std::vector<std::string>& elements, const char* const separator);
static int64_t StrToL(const std::string& str, int32_t base = 10);
static std::string BoolStr(bool b);
static bool HasOnlyDigits(const std::string& str);
static bool IsValidHex(std::string_view str);
static bool IsValidHex(const std::string& str);
static bool IsValidOffset(std::string_view str);
static bool IsValidOffset(const std::string& str);
static bool IEquals(const std::string& a, const std::string& b);
};

45
ZAPDTR/ZAPD/Utils/vt.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef VT_H
#define VT_H
// clang-format off
#define VT_COLOR_BLACK 0
#define VT_COLOR_RED 1
#define VT_COLOR_GREEN 2
#define VT_COLOR_YELLOW 3
#define VT_COLOR_BLUE 4
#define VT_COLOR_PURPLE 5
#define VT_COLOR_CYAN 6
#define VT_COLOR_WHITE 7
#define VT_COLOR_LIGHTGRAY 8
#define VT_COLOR_DARKGRAY 9
#define VT_COLOR_FOREGROUND 3
#define VT_COLOR_BACKGROUND 4
// clang-format on
#define VT_COLOR_EXPAND0(type, color) #type #color
#define VT_COLOR_EXPAND1(type, color) VT_COLOR_EXPAND0(type, color)
#define VT_COLOR(type, color) VT_COLOR_EXPAND1(VT_COLOR_##type, VT_COLOR_##color)
#define VT_ESC "\x1b"
#define VT_CSI "["
#define VT_CUP(x, y) VT_ESC VT_CSI y ";" x "H"
#define VT_ED(n) VT_ESC VT_CSI #n "J"
#define VT_SGR(n) VT_ESC VT_CSI n "m"
// Add more macros if necessary
#define VT_COL(back, fore) VT_SGR(VT_COLOR(BACKGROUND, back) ";" VT_COLOR(FOREGROUND, fore))
#define VT_FGCOL(color) VT_SGR(VT_COLOR(FOREGROUND, color))
#define VT_BGCOL(color) VT_SGR(VT_COLOR(BACKGROUND, color))
// Bold
#define VT_BOLD "1"
// Bold color support
#define VT_BOLD_FGCOL(color) VT_SGR(VT_BOLD ";" VT_COLOR(FOREGROUND, color))
#define VT_BOLD_BGCOL(color) VT_SGR(VT_BOLD ";" VT_COLOR(BACKGROUND, color))
#define VT_RST VT_SGR("")
#define VT_CLS VT_ED(2)
#endif

View File

@@ -0,0 +1,455 @@
/**
* ZAPD Warning- and Error-handling system
* =======================================
*
* This provides a common standard way to write ZAPD warnings/errors, which should be used for all
* such. It will pretty-print them in a uniform way, with styles defined in the header.
*
* Warnings/errors should be constructed using the macros given in the header; there are now plenty
* of examples in the codebase of how to do this. Their purposes are noted above each category in
* the header. Each warning has a type, one of the ones in warningStringToInitMap, or
* WarningType::Always, which is used for warnings that cannot be disabled and do not display a
* type.
*
* Currently there are three levels of alert a warning can have:
* - Off (does not display anything)
* - Warn (print a warning but continue processing)
* - Err (behave like an error, i.e. print and throw an exception to crash ZAPD when occurs)
*
* Flag use:
* - -Wfoo enables warnings of type foo
* - -Wno-foo disables warnings of type foo
* - -Werror=foo escalates foo to behave like an error
* - -Weverything enables all warnings
* - -Werror escalates all enabled warnings to errors
*
* Errors do not have types, and will always throw an exception; they cannot be disabled.
*
* Format
* ===
* Each printed warning/error contains the same three sections:
* - Preamble: automatically generated; the content varies depending on category. It will print the
* file and function that the warning is from, and information about the files being processed
* or extracted.
* - Header: begins with 'warning: ' or 'error:', should contain essential information about the
* warning/error, ends with the warning type if applicable. Printed with emphasis to make it
* stand out. Does not start with a capital letter or end with a '.'
* - Body (optional): indented, should contain further diagnostic information useful for identifying
* and fixing the warning/error. Can be a sentence with captialisation and '.' on the end.
*
* Please think of what the end user will find most useful when writing the header and body, and try
* to keep it brief without sacrificing important information! Also remember that if the user is
* only looking at stderr, they will normally have no other context.
*
* Warning vs error
* ===
* The principle that we have operated on so far is
* - issue a warning if ZAPD will still be able to produce a valid, compilable C file that will
* match
* - if this cannot happen, use an error.
* but at the end of the day, it is up to the programmer's discretion what it should be possible to
* disable.
*
* Documentation
* ===
* Remember that all warnings also need to be documented in the README.md. The help is generated
* automatically.
*/
#include "WarningHandler.h"
#include <cassert>
#include "Globals.h"
#include "Utils/StringHelper.h"
typedef struct
{
WarningType type;
WarningLevel defaultLevel;
std::string description;
} WarningInfoInit;
typedef struct
{
WarningLevel level;
std::string name;
std::string description;
} WarningInfo;
/**
* Master list of all default warning types and features
*
* To add a warning type, fill in a new row of this map. Think carefully about what its default
* level should be, and try and make the description both brief and informative: it is used in the
* help message, so again, think about what the end user needs to know.
*/
// clang-format off
static const std::unordered_map<std::string, WarningInfoInit> warningStringToInitMap = {
{"deprecated", {WarningType::Deprecated,
#ifdef DEPRECATION_ON
WarningLevel::Warn,
#else
WarningLevel::Off,
#endif
"Deprecated features"}},
{"unaccounted", {WarningType::Unaccounted, WarningLevel::Off, "Large blocks of unaccounted"}},
{"missing-offsets", {WarningType::MissingOffsets, WarningLevel::Warn, "Offset attribute missing in XML tag"}},
{"intersection", {WarningType::Intersection, WarningLevel::Warn, "Two assets intersect"}},
{"missing-attribute", {WarningType::MissingAttribute, WarningLevel::Warn, "Required attribute missing in XML tag"}},
{"invalid-attribute-value", {WarningType::InvalidAttributeValue, WarningLevel::Err, "Attribute declared in XML is wrong"}},
{"unknown-attribute", {WarningType::UnknownAttribute, WarningLevel::Warn, "Unknown attribute in XML entry tag"}},
{"invalid-xml", {WarningType::InvalidXML, WarningLevel::Err, "XML has syntax errors"}},
{"invalid-jpeg", {WarningType::InvalidJPEG, WarningLevel::Err, "JPEG file does not conform to the game's format requirements"}},
{"invalid-png", {WarningType::InvalidPNG, WarningLevel::Err, "Issues arising when processing PNG data"}},
{"invalid-extracted-data", {WarningType::InvalidExtractedData, WarningLevel::Err, "Extracted data does not have correct form"}},
{"missing-segment", {WarningType::MissingSegment, WarningLevel::Warn, "Segment not given in File tag in XML"}},
{"hardcoded-generic-pointer", {WarningType::HardcodedGenericPointer, WarningLevel::Off, "A generic segmented pointer must be produced"}},
{"hardcoded-pointer", {WarningType::HardcodedPointer, WarningLevel::Warn, "ZAPD lacks the info to make a symbol, so must output a hardcoded pointer"}},
{"not-implemented", {WarningType::NotImplemented, WarningLevel::Warn, "ZAPD does not currently support this feature"}},
};
/**
* Map constructed at runtime to contain the warning features as set by the user using -W flags.
*/
static std::unordered_map<WarningType, WarningInfo> warningTypeToInfoMap;
void WarningHandler::ConstructTypeToInfoMap() {
for (auto& entry : warningStringToInitMap) {
warningTypeToInfoMap[entry.second.type] = {entry.second.defaultLevel, entry.first, entry.second.description};
}
warningTypeToInfoMap[WarningType::Always] = {WarningLevel::Warn, "always", "you shouldn't be reading this"};
assert(warningTypeToInfoMap.size() == static_cast<size_t>(WarningType::Max));
}
/**
* Initialises the main warning type map and reads flags passed to set each warning type's level.
*/
void WarningHandler::Init(int argc, char* argv[]) {
ConstructTypeToInfoMap();
bool werror = false;
for (int i = 1; i < argc; i++) {
// If it doesn't start with "-W" skip it.
if (argv[i][0] != '-' || argv[i][1] != 'W' || argv[i][2] == '\0') {
continue;
}
WarningLevel warningTypeOn = WarningLevel::Warn;
size_t startingIndex = 2;
// "-Wno-"
if (argv[i][2] == 'n' && argv[i][3] == 'o' && argv[i][4] == '-' && argv[i][5] != '\0') {
warningTypeOn = WarningLevel::Off;
startingIndex = 5;
}
// Read starting after the "-W" or "-Wno-"
std::string_view currentArgv = &argv[i][startingIndex];
if (currentArgv == "error") {
werror = warningTypeOn != WarningLevel::Off;
} else if (currentArgv == "everything") {
for (auto& it: warningTypeToInfoMap) {
if (it.second.level <= WarningLevel::Warn) {
it.second.level = warningTypeOn;
}
}
} else {
// "-Werror=" / "-Wno-error=" parser
if (currentArgv.rfind("error=", 0) == 0) {
// Read starting after the "error=" part
currentArgv = &argv[i][startingIndex + 6];
warningTypeOn = warningTypeOn != WarningLevel::Off ? WarningLevel::Err : WarningLevel::Warn;
}
auto it = warningStringToInitMap.find(std::string(currentArgv));
if (it != warningStringToInitMap.end()) {
warningTypeToInfoMap[it->second.type].level = warningTypeOn;
}
else {
HANDLE_WARNING(WarningType::Always, StringHelper::Sprintf("unknown warning flag '%s'", argv[i]), "");
}
}
}
if (werror) {
for (auto& it: warningTypeToInfoMap) {
if (it.second.level >= WarningLevel::Warn) {
it.second.level = WarningLevel::Err;
}
}
}
}
bool WarningHandler::IsWarningEnabled(WarningType warnType) {
assert(static_cast<size_t>(warnType) >= 0 && warnType < WarningType::Max);
return warningTypeToInfoMap.at(warnType).level != WarningLevel::Off;
}
bool WarningHandler::WasElevatedToError(WarningType warnType) {
assert(static_cast<size_t>(warnType) >= 0 && warnType < WarningType::Max);
if (!IsWarningEnabled(warnType)) {
return false;
}
return warningTypeToInfoMap.at(warnType).level >= WarningLevel::Err;
}
/**
* Print file/line/function info for debugging
*/
void WarningHandler::FunctionPreamble(const char* filename, int32_t line, const char* function) {
bool forcePrint = false;
#ifdef DEVELOPMENT
forcePrint = true;
#endif
fprintf(stderr, "\n");
if (forcePrint || Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) {
fprintf(stderr, "%s:%i: in function <%s>:\n", filename, line, function);
}
}
/**
* Print the information about the file(s) being processed (XML for extraction, png etc. for building)
*/
void WarningHandler::ProcessedFilePreamble() {
if (Globals::Instance->inputPath != "") {
fprintf(stderr, "When processing file %s: ", Globals::Instance->inputPath.c_str());
}
}
/**
* Print information about the binary file being extracted
*/
void WarningHandler::ExtractedFilePreamble(const ZFile *parent, const ZResource* res, const uint32_t offset) {
fprintf(stderr, "in input binary file %s, ", parent->GetName().c_str());
if (res != nullptr) {
fprintf(stderr, "resource '%s' at ", res->GetName().c_str());
}
if (offset != static_cast<uint32_t>(-1)) {
fprintf(stderr, "offset 0x%06X:", offset);
}
fprintf(stderr, "\n\t");
}
/**
* Construct the rest of the message, after warning:/error. The message is filled in one character at a time, with indents added after newlines
*/
std::string WarningHandler::ConstructMessage(std::string message, const std::string& header, const std::string& body) {
message.reserve(message.size() + header.size() + body.size() + 10 * (sizeof(HANG_INDT) - 1));
message += StringHelper::Sprintf(HILITE("%s"), header.c_str());
message += "\n";
if (body == "") {
return message;
}
message += HANG_INDT;
for (const char* ptr = body.c_str(); *ptr != '\0'; ptr++) {
message += *ptr;
if (*ptr == '\n') {
message += HANG_INDT;
}
}
message += "\n";
return message;
}
/* Error module functions */
void WarningHandler::PrintErrorAndThrow(const std::string& header, const std::string& body) {
std::string errorMsg = ERR_FMT("error: ");
throw std::runtime_error(ConstructMessage(errorMsg, header, body));
}
/* Error types, to be used via the macros */
void WarningHandler::ErrorType(WarningType warnType, const std::string& header, const std::string& body) {
std::string headerMsg = header;
for (const auto& iter: warningStringToInitMap) {
if (iter.second.type == warnType) {
headerMsg += StringHelper::Sprintf(" [%s]", iter.first.c_str());
}
}
PrintErrorAndThrow(headerMsg, body);
}
void WarningHandler::Error_Plain(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) {
FunctionPreamble(filename, line, function);
ErrorType(warnType, header, body);
}
void WarningHandler::Error_Process(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) {
FunctionPreamble(filename, line, function);
ProcessedFilePreamble();
ErrorType(warnType, header, body);
}
void WarningHandler::Error_Resource(const char* filename, int32_t line, const char* function, WarningType warnType, const ZFile *parent, const ZResource* res, const uint32_t offset, const std::string& header, const std::string& body) {
assert(parent != nullptr);
FunctionPreamble(filename, line, function);
ProcessedFilePreamble();
ExtractedFilePreamble(parent, res, offset);
ErrorType(warnType, header, body);
}
/* Warning module functions */
void WarningHandler::PrintWarningBody(const std::string& header, const std::string& body) {
std::string errorMsg = WARN_FMT("warning: ");
fprintf(stderr, "%s", ConstructMessage(errorMsg, header, body).c_str());
}
void WarningHandler::WarningTypeAndChooseEscalate(WarningType warnType, const std::string& header, const std::string& body) {
std::string headerMsg = header;
for (const auto& iter: warningStringToInitMap) {
if (iter.second.type == warnType) {
headerMsg += StringHelper::Sprintf(" [-W%s]", iter.first.c_str());
}
}
if (WasElevatedToError(warnType)) {
PrintErrorAndThrow(headerMsg, body);
} else {
PrintWarningBody(headerMsg, body);
}
}
/* Warning types, to be used via the macros */
void WarningHandler::Warning_Plain(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) {
if (!IsWarningEnabled(warnType)) {
return;
}
FunctionPreamble(filename, line, function);
WarningTypeAndChooseEscalate(warnType, header, body);
}
void WarningHandler::Warning_Process(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) {
if (!IsWarningEnabled(warnType)) {
return;
}
FunctionPreamble(filename, line, function);
ProcessedFilePreamble();
WarningTypeAndChooseEscalate(warnType, header, body);
}
void WarningHandler::Warning_Resource(const char* filename, int32_t line, const char* function, WarningType warnType, const ZFile *parent, const ZResource* res, const uint32_t offset, const std::string& header, const std::string& body) {
assert(parent != nullptr);
if (!IsWarningEnabled(warnType)) {
return;
}
FunctionPreamble(filename, line, function);
ProcessedFilePreamble();
ExtractedFilePreamble(parent, res, offset);
WarningTypeAndChooseEscalate(warnType, header, body);
}
/* Help-related functions */
#include <set>
/**
* Print each warning name, default status, and description using the init map
*/
void WarningHandler::PrintHelp() {
std::set<std::string> sortedKeys;
WarningInfoInit warningInfo;
uint32_t columnWidth = 25;
std::string dt;
// Sort keys through the magic of `set`, to print in alphabetical order
for (auto& it : warningStringToInitMap) {
sortedKeys.insert(it.first);
}
printf("\nWarning types ( * means enabled by default)\n");
for (auto& key : sortedKeys) {
warningInfo = warningStringToInitMap.at(key);
if (warningInfo.defaultLevel <= WarningLevel::Warn) {
dt = "-W";
dt += key;
if (warningInfo.defaultLevel == WarningLevel::Warn) {
dt += " *";
}
printf(HELP_DT_INDT "%-*s", columnWidth, dt.c_str());
if (dt.length() + 2 > columnWidth) {
printf("\n" HELP_DT_INDT "%-*s", columnWidth, "");
}
printf("%s\n", warningInfo.description.c_str());
}
}
printf("\nDefault errors\n");
for (auto& key : sortedKeys) {
if (warningInfo.defaultLevel > WarningLevel::Warn) {
dt = "-W";
dt += key;
printf(HELP_DT_INDT "%-*s", columnWidth, dt.c_str());
if (dt.length() + 2 > columnWidth) {
printf("\n" HELP_DT_INDT "%*s", columnWidth, "");
}
printf("%s\n", warningInfo.description.c_str());
}
}
printf("\n");
printf("Other\n" HELP_DT_INDT "-Weverything will enable all existing warnings.\n" HELP_DT_INDT "-Werror will promote all warnings to errors.\n");
printf("\n");
printf("Warnings can be disabled using -Wno-... instead of -W...; -Weverything will override any -Wno-... flags passed before it.\n");
}
/**
* Print which warnings are currently enabled
*/
void WarningHandler::PrintWarningsDebugInfo()
{
std::string dt;
printf("Warnings status:\n");
for (auto& it: warningTypeToInfoMap) {
dt = it.second.name;
dt += ": ";
printf(HELP_DT_INDT "%-25s", dt.c_str());
switch (it.second.level)
{
case WarningLevel::Off:
printf(VT_FGCOL(LIGHTGRAY) "Off" VT_RST);
break;
case WarningLevel::Warn:
printf(VT_FGCOL(YELLOW) "Warn" VT_RST);
break;
case WarningLevel::Err:
printf(VT_FGCOL(RED) "Err" VT_RST);
break;
}
printf("\n");
}
printf("\n");
}

View File

@@ -0,0 +1,146 @@
#pragma once
#include <array>
#include <string>
#include <string_view>
#include <unordered_map>
#include "Utils/vt.h"
#include "ZFile.h"
#ifdef _MSC_VER
#define __PRETTY_FUNCTION__ __FUNCSIG__
#elif not defined(__GNUC__)
#define __PRETTY_FUNCTION__ __func__
#endif
// =======================================
/* Formatting macros */
// TODO: move this somewhere else so it can be used by other help
#define HELP_DT_INDT " "
/* Macros for formatting warnings/errors */
#define VT_HILITE VT_BOLD_FGCOL(WHITE)
#define VT_WARN VT_BOLD_FGCOL(PURPLE)
#define VT_ERR VT_BOLD_FGCOL(RED)
#define HILITE(string) (VT_HILITE string VT_RST)
#define WARN_FMT(string) (VT_WARN string VT_RST)
#define ERR_FMT(string) (VT_ERR string VT_RST)
// Maybe make WARN_LF instead
// Currently 8 spaces
#define WARN_INDT " "
// Currently 16 spaces
#define HANG_INDT " "
// =======================================
/* Warning and error macros */
// TODO: better names
// General-purpose, plain style (only prints function,file,line in the preamble)
#define HANDLE_ERROR(warningType, header, body) \
WarningHandler::Error_Plain(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, body)
#define HANDLE_WARNING(warningType, header, body) \
WarningHandler::Warning_Plain(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, \
body)
// For processing XMLs or textures/blobs (preamble contains function,file,line; processed file)
#define HANDLE_ERROR_PROCESS(warningType, header, body) \
WarningHandler::Error_Process(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, \
body)
#define HANDLE_WARNING_PROCESS(warningType, header, body) \
WarningHandler::Warning_Process(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, \
body)
// For ZResource-related stuff (preamble contains function,file,line; processed file; extracted file
// and offset)
#define HANDLE_ERROR_RESOURCE(warningType, parent, resource, offset, header, body) \
WarningHandler::Error_Resource(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, parent, \
resource, offset, header, body)
#define HANDLE_WARNING_RESOURCE(warningType, parent, resource, offset, header, body) \
WarningHandler::Warning_Resource(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, parent, \
resource, offset, header, body)
// =======================================
enum class WarningType
{
Always, // Warnings of this type are always printed, cannot be disabled.
Deprecated,
Unaccounted,
MissingOffsets,
Intersection,
MissingAttribute,
InvalidAttributeValue,
UnknownAttribute,
InvalidXML,
InvalidJPEG,
InvalidPNG,
InvalidExtractedData,
MissingSegment,
HardcodedPointer,
HardcodedGenericPointer,
NotImplemented,
Max,
};
enum class WarningLevel
{
Off,
Warn,
Err,
};
class WarningHandler
{
public:
static void ConstructTypeToInfoMap();
static void Init(int argc, char* argv[]);
static bool IsWarningEnabled(WarningType warnType);
static bool WasElevatedToError(WarningType warnType);
static void FunctionPreamble(const char* filename, int32_t line, const char* function);
static void ProcessedFilePreamble();
static void ExtractedFilePreamble(const ZFile* parent, const ZResource* res,
const uint32_t offset);
static std::string ConstructMessage(std::string message, const std::string& header,
const std::string& body);
[[noreturn]] static void PrintErrorAndThrow(const std::string& header, const std::string& body);
static void PrintWarningBody(const std::string& header, const std::string& body);
[[noreturn]] static void ErrorType(WarningType warnType, const std::string& header,
const std::string& body);
[[noreturn]] static void Error_Plain(const char* filename, int32_t line, const char* function,
WarningType warnType, const std::string& header,
const std::string& body);
[[noreturn]] static void Error_Process(const char* filename, int32_t line, const char* function,
WarningType warnType, const std::string& header,
const std::string& body);
[[noreturn]] static void Error_Resource(const char* filename, int32_t line,
const char* function, WarningType warnType,
const ZFile* parent, const ZResource* res,
const uint32_t offset, const std::string& header,
const std::string& body);
static void WarningTypeAndChooseEscalate(WarningType warnType, const std::string& header,
const std::string& body);
static void Warning_Plain(const char* filename, int32_t line, const char* function,
WarningType warnType, const std::string& header,
const std::string& body);
static void Warning_Process(const char* filename, int32_t line, const char* function,
WarningType warnType, const std::string& header,
const std::string& body);
static void Warning_Resource(const char* filename, int32_t line, const char* function,
WarningType warnType, const ZFile* parent, const ZResource* res,
const uint32_t offset, const std::string& header,
const std::string& body);
static void PrintHelp();
static void PrintWarningsDebugInfo();
};

194
ZAPDTR/ZAPD/ZActorList.cpp Normal file
View File

@@ -0,0 +1,194 @@
#include "ZActorList.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "WarningHandler.h"
#include "ZFile.h"
#include "ZRoom/ZNames.h"
REGISTER_ZFILENODE(ActorList, ZActorList);
ZActorList::ZActorList(ZFile* nParent) : ZResource(nParent)
{
RegisterRequiredAttribute("Count");
}
void ZActorList::ExtractFromBinary(uint32_t nRawDataIndex, uint8_t nNumActors)
{
rawDataIndex = nRawDataIndex;
numActors = nNumActors;
// Don't parse raw data of external files
if (parent->GetMode() == ZFileMode::ExternalFile)
return;
ParseRawData();
}
void ZActorList::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
numActors = StringHelper::StrToL(registeredAttributes.at("Count").value);
if (numActors < 1)
{
HANDLE_ERROR_RESOURCE(
WarningType::InvalidAttributeValue, parent, this, rawDataIndex,
StringHelper::Sprintf("invalid value '%d' found for 'NumPaths' attribute", numActors),
"Should be at least '1'");
}
}
void ZActorList::ParseRawData()
{
ZResource::ParseRawData();
offset_t currentPtr = rawDataIndex;
size_t largestlength = 0;
for (size_t i = 0; i < numActors; i++)
{
ActorSpawnEntry entry(parent->GetRawData(), currentPtr);
currentPtr += entry.GetRawDataSize();
actors.push_back(entry);
size_t actorNameLength = ZNames::GetActorName(entry.GetActorId()).size();
if (actorNameLength > largestlength)
largestlength = actorNameLength;
}
for (auto& entry : actors)
{
entry.SetLargestActorName(largestlength);
}
}
Declaration* ZActorList::DeclareVar(const std::string& prefix, const std::string& bodyStr)
{
std::string auxName = name;
if (name == "")
auxName = GetDefaultName(prefix);
Declaration* decl =
parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(),
GetSourceTypeName(), name, GetActorListArraySize(), bodyStr);
decl->staticConf = staticConf;
return decl;
}
std::string ZActorList::GetBodySourceCode() const
{
std::string declaration;
size_t index = 0;
for (auto& entry : actors)
{
declaration += StringHelper::Sprintf("\t{ %s },", entry.GetBodySourceCode().c_str());
if (index < actors.size() - 1)
declaration += "\n";
index++;
}
return declaration;
}
std::string ZActorList::GetSourceTypeName() const
{
return actors.front().GetSourceTypeName();
}
ZResourceType ZActorList::GetResourceType() const
{
return ZResourceType::ActorList;
}
size_t ZActorList::GetRawDataSize() const
{
return actors.size() * actors.front().GetRawDataSize();
}
size_t ZActorList::GetActorListArraySize() const
{
size_t actorCount = 0;
// Doing an else-if here so we only do the loop when the game is SW97.
// Actor 0x22 is removed from SW97, so we need to ensure that we don't increment the actor count
// for it.
if (Globals::Instance->game == ZGame::OOT_SW97)
{
actorCount = 0;
for (const auto& entry : actors)
if (entry.GetActorId() != 0x22)
actorCount++;
}
else
{
actorCount = actors.size();
}
return actorCount;
}
/* ActorSpawnEntry */
ActorSpawnEntry::ActorSpawnEntry(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex)
{
actorNum = BitConverter::ToInt16BE(rawData, rawDataIndex + 0);
posX = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
posY = BitConverter::ToInt16BE(rawData, rawDataIndex + 4);
posZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 6);
rotX = BitConverter::ToUInt16BE(rawData, rawDataIndex + 8);
rotY = BitConverter::ToUInt16BE(rawData, rawDataIndex + 10);
rotZ = BitConverter::ToUInt16BE(rawData, rawDataIndex + 12);
params = BitConverter::ToInt16BE(rawData, rawDataIndex + 14);
}
std::string ActorSpawnEntry::GetBodySourceCode() const
{
std::string body;
std::string actorNameFmt = StringHelper::Sprintf("%%-%zus ", largestActorName + 1);
body =
StringHelper::Sprintf(actorNameFmt.c_str(), (ZNames::GetActorName(actorNum) + ",").c_str());
body += StringHelper::Sprintf("{ %6i, %6i, %6i }, ", posX, posY, posZ);
if (Globals::Instance->game == ZGame::MM_RETAIL)
body += StringHelper::Sprintf("{ SPAWN_ROT_FLAGS(%#5hX, 0x%04X)"
", SPAWN_ROT_FLAGS(%#5hX, 0x%04X)"
", SPAWN_ROT_FLAGS(%#5hX, 0x%04X) }, ",
(rotX >> 7) & 0b111111111, rotX & 0b1111111,
(rotY >> 7) & 0b111111111, rotY & 0b1111111,
(rotZ >> 7) & 0b111111111, rotZ & 0b1111111);
else
body += StringHelper::Sprintf("{ %#6hX, %#6hX, %#6hX }, ", rotX, rotY, rotZ);
body += StringHelper::Sprintf("0x%04X", params);
return body;
}
std::string ActorSpawnEntry::GetSourceTypeName() const
{
return "ActorEntry";
}
size_t ActorSpawnEntry::GetRawDataSize() const
{
return 16;
}
uint16_t ActorSpawnEntry::GetActorId() const
{
return actorNum;
}
void ActorSpawnEntry::SetLargestActorName(size_t nameSize)
{
largestActorName = nameSize;
}

52
ZAPDTR/ZAPD/ZActorList.h Normal file
View File

@@ -0,0 +1,52 @@
#pragma once
#include "ZResource.h"
class ActorSpawnEntry
{
public:
uint16_t actorNum;
int16_t posX;
int16_t posY;
int16_t posZ;
uint16_t rotX;
uint16_t rotY;
uint16_t rotZ;
uint16_t params;
size_t largestActorName = 16;
ActorSpawnEntry(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex);
std::string GetBodySourceCode() const;
std::string GetSourceTypeName() const;
size_t GetRawDataSize() const;
uint16_t GetActorId() const;
void SetLargestActorName(size_t nameSize);
};
class ZActorList : public ZResource
{
public:
std::vector<ActorSpawnEntry> actors;
uint32_t numActors = 0;
ZActorList(ZFile* nParent);
void ExtractFromBinary(offset_t nRawDataIndex, uint8_t nNumActors);
void ParseXML(tinyxml2::XMLElement* reader) override;
void ParseRawData() override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
protected:
size_t GetActorListArraySize() const;
};

580
ZAPDTR/ZAPD/ZAnimation.cpp Normal file
View File

@@ -0,0 +1,580 @@
#include "ZAnimation.h"
#include <utility>
#include "Globals.h"
#include "Utils/BitConverter.h"
#include <Utils/DiskFile.h>
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Animation, ZNormalAnimation);
REGISTER_ZFILENODE(PlayerAnimation, ZLinkAnimation);
REGISTER_ZFILENODE(CurveAnimation, ZCurveAnimation);
REGISTER_ZFILENODE(LegacyAnimation, ZLegacyAnimation);
ZAnimation::ZAnimation(ZFile* nParent) : ZResource(nParent)
{
frameCount = 0;
genOTRDef = true;
}
void ZAnimation::ParseRawData()
{
ZResource::ParseRawData();
frameCount = BitConverter::ToInt16BE(parent->GetRawData(), rawDataIndex + 0);
}
/*
std::string ZAnimation::GetSourceOutputHeader(const std::string& prefix)
{
if (Globals::Instance->otrMode)
{
std::string str = "";
str += StringHelper::Sprintf("#define %s \"__OTR__%s/%s\"", name.c_str(), parent->GetOutName().c_str(), name.c_str());
return str;
}
else
return ZResource::GetSourceOutputHeader(prefix);
}
*/
ZResourceType ZAnimation::GetResourceType() const
{
return ZResourceType::Animation;
}
/* ZNormalAnimation */
ZNormalAnimation::ZNormalAnimation(ZFile* nParent) : ZAnimation(nParent)
{
}
size_t ZNormalAnimation::GetRawDataSize() const
{
return 16;
}
std::string ZNormalAnimation::GetSourceTypeName() const
{
return "AnimationHeader";
}
void ZNormalAnimation::ParseRawData()
{
ZAnimation::ParseRawData();
auto& data = parent->GetRawData();
rotationValuesSeg = BitConverter::ToInt32BE(data, rawDataIndex + 4);
rotationIndicesSeg = BitConverter::ToInt32BE(data, rawDataIndex + 8);
limit = BitConverter::ToInt16BE(data, rawDataIndex + 12);
rotationValuesOffset = Seg2Filespace(rotationValuesSeg, parent->baseAddress);
rotationIndicesOffset = Seg2Filespace(rotationIndicesSeg, parent->baseAddress);
uint32_t currentPtr = rotationValuesOffset;
// Read the Rotation Values
for (uint32_t i = 0; i < ((rotationIndicesOffset - rotationValuesOffset) / 2); i++)
{
rotationValues.push_back(BitConverter::ToInt16BE(data, currentPtr));
currentPtr += 2;
}
currentPtr = rotationIndicesOffset;
// Read the Rotation Indices
for (uint32_t i = 0; i < ((rawDataIndex - rotationIndicesOffset) / 6); i++)
{
rotationIndices.push_back(RotationIndex(BitConverter::ToInt16BE(data, currentPtr),
BitConverter::ToInt16BE(data, currentPtr + 2),
BitConverter::ToInt16BE(data, currentPtr + 4)));
currentPtr += 6;
}
}
void ZNormalAnimation::DeclareReferences(const std::string& prefix)
{
std::string defaultPrefix = prefix.c_str();
if (name != "")
defaultPrefix = name;
// replace g prefix with s for local variables
if (defaultPrefix.at(0) == 'g')
defaultPrefix.replace(0, 1, "s");
std::string indicesStr = "";
std::string valuesStr = " ";
const uint8_t lineLength = 14;
const uint8_t offset = 0;
if (!Globals::Instance->otrMode)
{
for (size_t i = 0; i < rotationValues.size(); i++)
{
valuesStr += StringHelper::Sprintf("0x%04X, ", rotationValues[i]);
if ((i - offset + 1) % lineLength == 0)
valuesStr += "\n ";
}
}
parent->AddDeclarationArray(rotationValuesOffset, DeclarationAlignment::Align4,
rotationValues.size() * 2, "s16",
StringHelper::Sprintf("%sFrameData", defaultPrefix.c_str()),
rotationValues.size(), valuesStr);
if (!Globals::Instance->otrMode)
{
for (size_t i = 0; i < rotationIndices.size(); i++)
{
indicesStr += StringHelper::Sprintf(" { 0x%04X, 0x%04X, 0x%04X },", rotationIndices[i].x,
rotationIndices[i].y, rotationIndices[i].z);
if (i != (rotationIndices.size() - 1))
indicesStr += "\n";
}
}
parent->AddDeclarationArray(rotationIndicesOffset, DeclarationAlignment::Align4,
rotationIndices.size() * 6, "JointIndex",
StringHelper::Sprintf("%sJointIndices", defaultPrefix.c_str()),
rotationIndices.size(), indicesStr);
}
std::string ZNormalAnimation::GetBodySourceCode() const
{
std::string frameDataName;
Globals::Instance->GetSegmentedPtrName(rotationValuesSeg, parent, "s16", frameDataName,
parent->workerID);
std::string jointIndicesName;
Globals::Instance->GetSegmentedPtrName(rotationIndicesSeg, parent, "JointIndex",
jointIndicesName, parent->workerID);
std::string headerStr =
StringHelper::Sprintf("\n\t{ %i }, %s,\n", frameCount, frameDataName.c_str());
headerStr += StringHelper::Sprintf("\t%s, %i\n", jointIndicesName.c_str(), limit);
return headerStr;
}
/* ZLinkAnimation */
ZLinkAnimation::ZLinkAnimation(ZFile* nParent) : ZAnimation(nParent)
{
segmentAddress = 0;
}
size_t ZLinkAnimation::GetRawDataSize() const
{
return 8;
}
std::string ZLinkAnimation::GetSourceTypeName() const
{
if (Globals::Instance->game == ZGame::MM_RETAIL)
return "PlayerAnimationHeader";
else
return "LinkAnimationHeader";
}
void ZLinkAnimation::ParseRawData()
{
ZAnimation::ParseRawData();
const auto& rawData = parent->GetRawData();
segmentAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 4);
}
std::string ZLinkAnimation::GetBodySourceCode() const
{
std::string segSymbol;
Globals::Instance->GetSegmentedPtrName(segmentAddress, parent, "", segSymbol, parent->workerID);
return StringHelper::Sprintf("\n\t{ %i }, %s\n", frameCount, segSymbol.c_str());
}
/* ZCurveAnimation */
CurveInterpKnot::CurveInterpKnot(ZFile* parent, const std::vector<uint8_t>& rawData,
uint32_t fileOffset)
: parent(parent)
{
unk_00 = BitConverter::ToUInt16BE(rawData, fileOffset + 0);
unk_02 = BitConverter::ToUInt16BE(rawData, fileOffset + 2);
unk_04 = BitConverter::ToInt16BE(rawData, fileOffset + 4);
unk_06 = BitConverter::ToInt16BE(rawData, fileOffset + 6);
unk_08 = BitConverter::ToFloatBE(rawData, fileOffset + 8);
}
CurveInterpKnot::CurveInterpKnot(ZFile* parent, const std::vector<uint8_t>& rawData,
uint32_t fileOffset, size_t index)
: CurveInterpKnot(parent, rawData, fileOffset + index * GetRawDataSize())
{
}
std::string CurveInterpKnot::GetBody([[maybe_unused]] const std::string& prefix) const
{
return StringHelper::Sprintf("0x%04X, 0x%04X, %i, %i, %ff", unk_00, unk_02, unk_04, unk_06,
unk_08);
}
size_t CurveInterpKnot::GetRawDataSize() const
{
return 0x0C;
}
std::string CurveInterpKnot::GetSourceTypeName()
{
return "CurveInterpKnot";
}
ZCurveAnimation::ZCurveAnimation(ZFile* nParent) : ZAnimation(nParent)
{
RegisterOptionalAttribute("SkelOffset");
}
void ZCurveAnimation::ParseXML(tinyxml2::XMLElement* reader)
{
ZAnimation::ParseXML(reader);
std::string skelOffsetXml = registeredAttributes.at("SkelOffset").value;
if (skelOffsetXml == "")
{
HANDLE_ERROR_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex,
"missing 'SkelOffset' attribute in <ZCurveAnimation>",
"You need to provide the offset of the curve skeleton.");
}
skelOffset = StringHelper::StrToL(skelOffsetXml, 0);
}
void ZCurveAnimation::ParseRawData()
{
ZAnimation::ParseRawData();
const auto& rawData = parent->GetRawData();
refIndex = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0);
transformData = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4);
copyValues = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8);
unk_0C = BitConverter::ToInt16BE(rawData, rawDataIndex + 12);
unk_10 = BitConverter::ToInt16BE(rawData, rawDataIndex + 14);
uint32_t limbCountAddress = Seg2Filespace(skelOffset, parent->baseAddress) + 4;
limbCount = BitConverter::ToUInt8BE(rawData, limbCountAddress);
size_t transformDataSize = 0;
size_t copyValuesSize = 0;
if (refIndex != 0)
{
uint32_t refIndexOffset = Seg2Filespace(refIndex, parent->baseAddress);
for (size_t i = 0; i < 3 * 3 * limbCount; i++)
{
uint8_t ref = BitConverter::ToUInt8BE(rawData, refIndexOffset + i);
if (ref == 0)
copyValuesSize++;
else
transformDataSize += ref;
refIndexArr.emplace_back(ref);
}
}
if (transformData != 0)
{
uint32_t transformDataOffset = Seg2Filespace(transformData, parent->baseAddress);
for (size_t i = 0; i < transformDataSize; i++)
transformDataArr.emplace_back(parent, rawData, transformDataOffset, i);
}
if (copyValues != 0)
{
uint32_t copyValuesOffset = Seg2Filespace(copyValues, parent->baseAddress);
for (size_t i = 0; i < copyValuesSize; i++)
copyValuesArr.emplace_back(BitConverter::ToInt16BE(rawData, copyValuesOffset + i * 2));
}
}
void ZCurveAnimation::DeclareReferences(const std::string& prefix)
{
if (refIndex != 0)
{
uint32_t refIndexOffset = Seg2Filespace(refIndex, parent->baseAddress);
std::string refIndexStr =
StringHelper::Sprintf("%sCurveAnime_%s_%06X", prefix.c_str(), "Ref", refIndexOffset);
std::string entryStr = " ";
uint16_t arrayItemCnt = refIndexArr.size();
size_t i = 0;
for (auto& child : refIndexArr)
{
entryStr += StringHelper::Sprintf("0x%02X, %s", child, (i++ % 8 == 7) ? "\n " : "");
}
Declaration* decl = parent->GetDeclaration(refIndexOffset);
if (decl == nullptr)
{
parent->AddDeclarationArray(refIndexOffset, DeclarationAlignment::Align4,
arrayItemCnt * 1, "u8", refIndexStr, arrayItemCnt,
entryStr);
}
else
{
decl->declBody = entryStr;
}
}
if (transformData != 0)
{
uint32_t transformDataOffset = Seg2Filespace(transformData, parent->baseAddress);
std::string transformDataStr = StringHelper::Sprintf(
"%sCurveAnime_%s_%06X", prefix.c_str(),
transformDataArr.at(0).GetSourceTypeName().c_str(), transformDataOffset);
std::string entryStr;
uint16_t arrayItemCnt = transformDataArr.size();
size_t i = 0;
for (auto& child : transformDataArr)
{
entryStr += StringHelper::Sprintf(" { %s },%s", child.GetBody(prefix).c_str(),
(++i < arrayItemCnt) ? "\n" : "");
}
Declaration* decl = parent->GetDeclaration(transformDataOffset);
if (decl == nullptr)
{
parent->AddDeclarationArray(transformDataOffset, DeclarationAlignment::Align4,
arrayItemCnt * transformDataArr.at(0).GetRawDataSize(),
transformDataArr.at(0).GetSourceTypeName(),
transformDataStr, arrayItemCnt, entryStr);
}
else
{
decl->declBody = entryStr;
}
}
if (copyValues != 0)
{
uint32_t copyValuesOffset = Seg2Filespace(copyValues, parent->baseAddress);
std::string copyValuesStr =
StringHelper::Sprintf("%sCurveAnime_%s_%06X", prefix.c_str(), "Copy", copyValuesOffset);
std::string entryStr = " ";
uint16_t arrayItemCnt = copyValuesArr.size();
size_t i = 0;
for (auto& child : copyValuesArr)
{
entryStr += StringHelper::Sprintf("% 6i, %s", child, (i++ % 8 == 7) ? "\n " : "");
}
Declaration* decl = parent->GetDeclaration(copyValuesOffset);
if (decl == nullptr)
{
parent->AddDeclarationArray(copyValuesOffset, DeclarationAlignment::Align4,
arrayItemCnt * 2, "s16", copyValuesStr, arrayItemCnt,
entryStr);
}
else
{
decl->declBody = entryStr;
}
}
}
std::string ZCurveAnimation::GetBodySourceCode() const
{
std::string refIndexStr;
Globals::Instance->GetSegmentedPtrName(refIndex, parent, "u8", refIndexStr, parent->workerID);
std::string transformDataStr;
Globals::Instance->GetSegmentedPtrName(transformData, parent, "CurveInterpKnot",
transformDataStr, parent->workerID);
std::string copyValuesStr;
Globals::Instance->GetSegmentedPtrName(copyValues, parent, "s16", copyValuesStr,
parent->workerID);
return StringHelper::Sprintf("\n\t%s,\n\t%s,\n\t%s,\n\t%i, %i\n", refIndexStr.c_str(),
transformDataStr.c_str(), copyValuesStr.c_str(), unk_0C, unk_10);
}
size_t ZCurveAnimation::GetRawDataSize() const
{
return 0x10;
}
DeclarationAlignment ZCurveAnimation::GetDeclarationAlignment() const
{
return DeclarationAlignment::Align4;
}
std::string ZCurveAnimation::GetSourceTypeName() const
{
return "CurveAnimationHeader";
}
/* ZLegacyAnimation */
ZLegacyAnimation::ZLegacyAnimation(ZFile* nParent) : ZAnimation(nParent)
{
}
void ZLegacyAnimation::ParseRawData()
{
ZAnimation::ParseRawData();
const auto& rawData = parent->GetRawData();
limbCount = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x02);
frameData = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x04);
jointKey = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x08);
if (GETSEGNUM(frameData) == parent->segment && GETSEGNUM(jointKey) == parent->segment)
{
uint32_t frameDataOffset = Seg2Filespace(frameData, parent->baseAddress);
uint32_t jointKeyOffset = Seg2Filespace(jointKey, parent->baseAddress);
uint32_t ptr = frameDataOffset;
for (size_t i = 0; i < (jointKeyOffset - frameDataOffset) / 2; i++)
{
frameDataArray.push_back(BitConverter::ToUInt16BE(rawData, ptr));
ptr += 2;
}
ptr = jointKeyOffset;
for (int32_t i = 0; i < limbCount + 1; i++)
{
LegacyJointKey key(parent);
key.ExtractFromFile(ptr);
jointKeyArray.push_back(key);
ptr += key.GetRawDataSize();
}
}
}
void ZLegacyAnimation::DeclareReferences(const std::string& prefix)
{
std::string varPrefix = prefix;
if (name != "")
varPrefix = name;
ZAnimation::DeclareReferences(varPrefix);
if (!frameDataArray.empty())
{
uint32_t frameDataOffset = Seg2Filespace(frameData, parent->baseAddress);
if (GETSEGNUM(frameData) == parent->segment && !parent->HasDeclaration(frameDataOffset))
{
std::string frameDataBody = "\t";
for (size_t i = 0; i < frameDataArray.size(); i++)
{
frameDataBody += StringHelper::Sprintf("0x%04X, ", frameDataArray[i]);
if (i % 8 == 7 && i + 1 < frameDataArray.size())
frameDataBody += "\n\t";
}
std::string frameDataName = StringHelper::Sprintf("%sFrameData", varPrefix.c_str());
parent->AddDeclarationArray(frameDataOffset, DeclarationAlignment::Align4,
frameDataArray.size() * 2, "s16", frameDataName,
frameDataArray.size(), frameDataBody);
}
}
if (!jointKeyArray.empty())
{
uint32_t jointKeyOffset = Seg2Filespace(jointKey, parent->baseAddress);
if (GETSEGNUM(jointKey) == parent->segment && !parent->HasDeclaration(jointKeyOffset))
{
const auto res = jointKeyArray.at(0);
std::string jointKeyBody;
for (size_t i = 0; i < jointKeyArray.size(); i++)
{
jointKeyBody += StringHelper::Sprintf("\t{ %s },",
jointKeyArray[i].GetBodySourceCode().c_str());
if (i + 1 < jointKeyArray.size())
jointKeyBody += "\n";
}
std::string jointKeyName = StringHelper::Sprintf("%sJointKey", varPrefix.c_str());
parent->AddDeclarationArray(jointKeyOffset, DeclarationAlignment::Align4,
jointKeyArray.size() * res.GetRawDataSize(),
res.GetSourceTypeName(), jointKeyName, jointKeyArray.size(),
jointKeyBody);
}
}
}
std::string ZLegacyAnimation::GetBodySourceCode() const
{
std::string body = "\n";
std::string frameDataName;
std::string jointKeyName;
Globals::Instance->GetSegmentedPtrName(frameData, parent, "s16", frameDataName, parent->workerID);
Globals::Instance->GetSegmentedPtrName(jointKey, parent, "LegacyJointKey", jointKeyName, parent->workerID);
body += StringHelper::Sprintf("\t%i, %i,\n", frameCount, limbCount);
body += StringHelper::Sprintf("\t%s,\n", frameDataName.c_str());
body += StringHelper::Sprintf("\t%s\n", jointKeyName.c_str());
return body;
}
std::string ZLegacyAnimation::GetSourceTypeName() const
{
return "LegacyAnimationHeader";
}
size_t ZLegacyAnimation::GetRawDataSize() const
{
return 0x0C;
}
LegacyJointKey::LegacyJointKey(ZFile* nParent) : ZResource(nParent)
{
}
void LegacyJointKey::ParseRawData()
{
ZResource::ParseRawData();
const auto& rawData = parent->GetRawData();
xMax = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x00);
x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x02);
yMax = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x04);
y = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x06);
zMax = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x08);
z = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x0A);
}
std::string LegacyJointKey::GetBodySourceCode() const
{
return StringHelper::Sprintf("%6i, %6i, %6i, %6i, %6i, %6i", xMax, x, yMax, y, zMax, z);
}
std::string LegacyJointKey::GetSourceTypeName() const
{
return "LegacyJointKey";
}
ZResourceType LegacyJointKey::GetResourceType() const
{
// TODO
return ZResourceType::Error;
}
size_t LegacyJointKey::GetRawDataSize() const
{
return 0x0C;
}

179
ZAPDTR/ZAPD/ZAnimation.h Normal file
View File

@@ -0,0 +1,179 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "ZResource.h"
#include "ZSkeleton.h"
#include "tinyxml2.h"
struct RotationIndex
{
// uint16_t transX, transY, transZ;
uint16_t x, y, z;
RotationIndex(uint16_t nX, uint16_t nY, uint16_t nZ) : x(nX), y(nY), z(nZ) {}
};
class ZAnimation : public ZResource
{
public:
int16_t frameCount;
ZAnimation(ZFile* nParent);
//std::string GetSourceOutputHeader(const std::string& prefix) override;
ZResourceType GetResourceType() const override;
protected:
void ParseRawData() override;
};
class ZNormalAnimation : public ZAnimation
{
public:
std::vector<uint16_t> rotationValues;
std::vector<RotationIndex> rotationIndices;
segptr_t rotationValuesSeg = 0;
segptr_t rotationIndicesSeg = 0;
offset_t rotationValuesOffset = 0;
offset_t rotationIndicesOffset = 0;
int16_t limit = 0;
ZNormalAnimation(ZFile* nParent);
void DeclareReferences(const std::string& prefix) override;
std::string GetBodySourceCode() const override;
size_t GetRawDataSize() const override;
std::string GetSourceTypeName() const override;
void ParseRawData() override;
};
class ZLinkAnimation : public ZAnimation
{
public:
segptr_t segmentAddress;
ZLinkAnimation(ZFile* nParent);
std::string GetBodySourceCode() const override;
size_t GetRawDataSize() const override;
std::string GetSourceTypeName() const override;
void ParseRawData() override;
};
class CurveInterpKnot
{
public:
ZFile* parent;
///* 0x0000 */ u16 unk_00; // appears to be flags
uint16_t unk_00;
///* 0x0002 */ s16 unk_02;
int16_t unk_02;
///* 0x0004 */ s16 unk_04;
int16_t unk_04;
///* 0x0006 */ s16 unk_06;
int16_t unk_06;
///* 0x0008 */ f32 unk_08;
float unk_08;
public:
CurveInterpKnot() = default;
CurveInterpKnot(ZFile* parent, const std::vector<uint8_t>& rawData, uint32_t fileOffset);
CurveInterpKnot(ZFile* parent, const std::vector<uint8_t>& rawData, uint32_t fileOffset,
size_t index);
[[nodiscard]] std::string GetBody(const std::string& prefix) const;
size_t GetRawDataSize() const;
std::string GetSourceTypeName();
};
class ZCurveAnimation : public ZAnimation
{
public:
segptr_t skelOffset = 0;
///* 0x0000 */ u8* refIndex;
segptr_t refIndex = 0;
///* 0x0004 */ CurveInterpKnot* transformData;
segptr_t transformData = 0;
///* 0x0008 */ s16* copyValues;
segptr_t copyValues = 0;
///* 0x000C */ s16 unk_0C;
int16_t unk_0C;
///* 0x000E */ s16 unk_10;
int16_t unk_10;
uint8_t limbCount = 0;
std::vector<uint8_t> refIndexArr;
std::vector<CurveInterpKnot> transformDataArr;
std::vector<int16_t> copyValuesArr;
public:
ZCurveAnimation(ZFile* nParent);
void ParseXML(tinyxml2::XMLElement* reader) override;
void ParseRawData() override;
void DeclareReferences(const std::string& prefix) override;
std::string GetBodySourceCode() const override;
size_t GetRawDataSize() const override;
DeclarationAlignment GetDeclarationAlignment() const override;
std::string GetSourceTypeName() const override;
};
// CurveAnimationHeader
/* ZLegacyAnimation */
class LegacyJointKey : public ZResource
{
public:
LegacyJointKey(ZFile* nParent);
void ParseRawData() override;
std::string GetBodySourceCode() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
protected:
int16_t xMax, x;
int16_t yMax, y;
int16_t zMax, z;
};
class ZLegacyAnimation : public ZAnimation
{
public:
ZLegacyAnimation(ZFile* nParent);
void ParseRawData() override;
void DeclareReferences(const std::string& prefix) override;
std::string GetBodySourceCode() const override;
std::string GetSourceTypeName() const override;
size_t GetRawDataSize() const override;
protected:
int16_t limbCount;
segptr_t frameData; // s16*
segptr_t jointKey; // LegacyJointKey*
std::vector<uint16_t> frameDataArray;
std::vector<LegacyJointKey> jointKeyArray;
};

154
ZAPDTR/ZAPD/ZArray.cpp Normal file
View File

@@ -0,0 +1,154 @@
#include "ZArray.h"
#include <cassert>
#include "Globals.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Array, ZArray);
ZArray::ZArray(ZFile* nParent) : ZResource(nParent)
{
canHaveInner = true;
genOTRDef = true;
RegisterRequiredAttribute("Count");
}
ZArray::~ZArray()
{
for (auto res : resList)
delete res;
}
void ZArray::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
arrayCnt = reader->IntAttribute("Count", 0);
if (arrayCnt <= 0)
{
HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex,
"invalid value found for 'Count' attribute", "");
}
tinyxml2::XMLElement* child = reader->FirstChildElement();
if (child == nullptr)
{
HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex,
"<Array> needs one sub-element", "");
}
childName = child->Name();
auto nodeMap = ZFile::GetNodeMap();
size_t childIndex = rawDataIndex;
resList.reserve(arrayCnt);
for (size_t i = 0; i < arrayCnt; i++)
{
ZResource* res = nodeMap->at(childName)(parent);
if (!res->DoesSupportArray())
{
std::string errorHeader = StringHelper::Sprintf(
"resource <%s> does not support being wrapped in an <Array>", childName.c_str());
HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, errorHeader,
"");
}
res->parent = parent;
res->SetInnerNode(true);
res->ExtractWithXML(child, childIndex);
childIndex += res->GetRawDataSize();
resList.push_back(res);
}
}
Declaration* ZArray::DeclareVar(const std::string& prefix, const std::string& bodyStr)
{
std::string auxName = name;
if (name == "")
auxName = GetDefaultName(prefix);
ZResource* res = resList.at(0);
Declaration* decl;
if (res->IsExternalResource())
{
auto filepath = Globals::Instance->outputPath / name;
std::string includePath = StringHelper::Sprintf("%s.%s.inc", filepath.string().c_str(),
res->GetExternalExtension().c_str());
decl = parent->AddDeclarationIncludeArray(rawDataIndex, includePath, GetRawDataSize(),
GetSourceTypeName(), name, arrayCnt);
decl->declBody = bodyStr;
decl->isExternal = true;
}
else
{
decl =
parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(),
GetSourceTypeName(), name, arrayCnt, bodyStr);
}
decl->staticConf = staticConf;
return decl;
}
std::string ZArray::GetBodySourceCode() const
{
std::string output;
for (size_t i = 0; i < arrayCnt; i++)
{
const auto& res = resList[i];
output += "\t";
switch (res->GetResourceType())
{
case ZResourceType::Pointer:
case ZResourceType::Scalar:
case ZResourceType::Vertex:
case ZResourceType::CollisionPoly:
case ZResourceType::SurfaceType:
case ZResourceType::Waterbox:
output += resList.at(i)->GetBodySourceCode();
break;
default:
output += StringHelper::Sprintf("{ %s }", resList.at(i)->GetBodySourceCode().c_str());
break;
}
if (i < arrayCnt - 1 || res->IsExternalResource())
output += ",\n";
}
return output;
}
size_t ZArray::GetRawDataSize() const
{
size_t size = 0;
for (const auto res : resList)
size += res->GetRawDataSize();
return size;
}
std::string ZArray::GetSourceTypeName() const
{
return resList.at(0)->GetSourceTypeName();
}
ZResourceType ZArray::GetResourceType() const
{
return ZResourceType::Array;
}
DeclarationAlignment ZArray::GetDeclarationAlignment() const
{
if (resList.size() == 0)
{
return DeclarationAlignment::Align4;
}
return resList.at(0)->GetDeclarationAlignment();
}

31
ZAPDTR/ZAPD/ZArray.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "ZResource.h"
#include "tinyxml2.h"
class ZArray : public ZResource
{
public:
ZArray(ZFile* nParent);
~ZArray();
void ParseXML(tinyxml2::XMLElement* reader) override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
size_t GetRawDataSize() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
DeclarationAlignment GetDeclarationAlignment() const override;
size_t arrayCnt;
std::vector<ZResource*> resList;
protected:
std::string childName;
};

416
ZAPDTR/ZAPD/ZAudio.cpp Normal file
View File

@@ -0,0 +1,416 @@
#include "ZAudio.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include <Utils/DiskFile.h>
#include "Utils/Path.h"
#include "Utils/StringHelper.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Audio, ZAudio);
ZAudio::ZAudio(ZFile* nParent) : ZResource(nParent)
{
RegisterRequiredAttribute("SoundFontTableOffset");
RegisterRequiredAttribute("SequenceTableOffset");
RegisterRequiredAttribute("SampleBankTableOffset");
RegisterRequiredAttribute("SequenceFontTableOffset");
}
void ZAudio::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
auto t = reader->Name();
auto child = reader->FirstChildElement();
while (child != nullptr)
{
if (strcmp(child->Value(), "Sequences") == 0)
{
auto seqChild = child->FirstChildElement();
while (seqChild != nullptr)
{
if (strcmp(seqChild->Value(), "Sequence") == 0)
{
seqNames.push_back(seqChild->Attribute("Name"));
}
seqChild = seqChild->NextSiblingElement();
}
}
if (strcmp(child->Value(), "Samples") == 0)
{
int bankId = child->IntAttribute("Bank", 0);
auto sampChild = child->FirstChildElement();
while (sampChild != nullptr)
{
if (strcmp(sampChild->Value(), "Sample") == 0)
{
uint32_t atOffset = sampChild->UnsignedAttribute("Offset");
sampleOffsets[bankId][atOffset] = sampChild->Attribute("Name");
}
sampChild = sampChild->NextSiblingElement();
}
}
if (strcmp(child->Value(), "Soundfont") == 0)
{
auto name = child->Attribute("Name");
auto index = child->IntAttribute("Index", 0);
soundFontNames[index] = name;
}
child = child->NextSiblingElement();
}
}
std::vector<AdsrEnvelope*> ZAudio::ParseEnvelopeData(const std::vector<uint8_t>& audioBank, const std::vector<uint8_t>& audioTable, int envelopeOffset, int baseOffset)
{
std::vector<AdsrEnvelope*> result;
while (true)
{
AdsrEnvelope* env = new AdsrEnvelope();
env->delay = BitConverter::ToInt16BE(audioBank, envelopeOffset + 0);
env->arg = BitConverter::ToInt16BE(audioBank, envelopeOffset + 2);
envelopeOffset += 4;
result.push_back(env);
if (env->delay < 0)
break;
}
return result;
}
SoundFontEntry* ZAudio::ParseSoundFontEntry(const std::vector<uint8_t>& audioBank,
const std::vector<uint8_t>& audioTable,
AudioTableEntry audioSampleBankEntry, int bankIndex,
int soundFontOffset,
int baseOffset)
{
SoundFontEntry* soundFont = new SoundFontEntry();
int sampleOffset = BitConverter::ToInt32BE(audioBank, soundFontOffset + 0) + baseOffset;
if (sampleOffset == 0)
return nullptr;
soundFont->sampleEntry = ParseSampleEntry(
audioBank, audioTable, audioSampleBankEntry, bankIndex,
sampleOffset, baseOffset);
soundFont->tuning = BitConverter::ToFloatBE(audioBank, soundFontOffset + 4);
return soundFont;
}
SampleEntry* ZAudio::ParseSampleEntry(const std::vector<uint8_t>& audioBank,
const std::vector<uint8_t>& audioTable,
AudioTableEntry audioSampleBankEntry, int bankIndex,
int sampleOffset,
int baseOffset)
{
int sampleDataOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 4) + audioSampleBankEntry.ptr;
int sampleSize = BitConverter::ToInt32BE(audioBank, sampleOffset + 0) & 0x00FFFFFF;
int loopOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 8) + baseOffset;
int bookOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 12) + baseOffset;
if (samples.find(sampleDataOffset) == samples.end())
{
SampleEntry* sample = new SampleEntry();
sample->bankId = bankIndex;
sample->data = std::vector<uint8_t>(sampleSize);
memcpy(sample->data.data(), audioTable.data() + sampleDataOffset, sampleSize);
uint32_t origField = (BitConverter::ToUInt32BE(audioBank, sampleOffset + 0));
sample->codec = (origField >> 28) & 0x0F;
sample->medium = (origField >> 24) & 0x03;
sample->unk_bit26 = (origField >> 22) & 0x01;
sample->unk_bit25 = (origField >> 21) & 0x01;
sample->loop.start = BitConverter::ToInt32BE(audioBank, loopOffset + 0);
sample->loop.end = BitConverter::ToInt32BE(audioBank, loopOffset + 4);
sample->loop.count = BitConverter::ToInt32BE(audioBank, loopOffset + 8);
if (sample->loop.count != 0)
{
for (int i = 0; i < 16; i++)
{
// TODO can loop.states be an array of size 16?
int16_t state = BitConverter::ToInt16BE(audioBank, loopOffset + 16 + (i * 2));
sample->loop.states.push_back(state);
}
}
sample->book.order = BitConverter::ToInt32BE(audioBank, bookOffset + 0);
sample->book.npredictors = BitConverter::ToInt32BE(audioBank, bookOffset + 4);
int32_t numBooks = sample->book.npredictors * sample->book.order * 8;
sample->book.books.reserve(numBooks);
for (int i = 0; i < numBooks; i++)
{
sample->book.books.push_back(
BitConverter::ToInt16BE(audioBank, bookOffset + 8 + (i * 2)));
}
sample->sampleDataOffset = sampleDataOffset;
sample->sampleLoopOffset = 0;
sample->fileName = sampleOffsets[bankIndex][sampleDataOffset];
samples[sampleDataOffset] = sample;
return sample;
}
else
{
return samples[sampleDataOffset];
}
}
std::vector<AudioTableEntry> ZAudio::ParseAudioTable(const std::vector<uint8_t>& codeData, int baseOffset)
{
std::vector<AudioTableEntry> entries;
int numEntries = BitConverter::ToInt16BE(codeData, baseOffset + 0);
int romAddr = BitConverter::ToInt16BE(codeData, baseOffset + 4);
int currentOffset = baseOffset + 16;
entries.reserve(numEntries);
for (int i = 0; i < numEntries; i++)
{
AudioTableEntry entry;
entry.ptr = BitConverter::ToInt32BE(codeData, currentOffset + 0);
entry.size = BitConverter::ToInt32BE(codeData, currentOffset + 4);
entry.medium = codeData[currentOffset + 8];
entry.cachePolicy = codeData[currentOffset + 9];
entry.data1 = BitConverter::ToInt16BE(codeData, currentOffset + 10);
entry.data2 = BitConverter::ToInt16BE(codeData, currentOffset + 12);
entry.data3 = BitConverter::ToInt16BE(codeData, currentOffset + 14);
entries.push_back(entry);
currentOffset += 16;
}
return entries;
}
void ZAudio::ParseSoundFont(const std::vector<uint8_t>& codeData, const std::vector<uint8_t>& audioTable,
const std::vector<AudioTableEntry>& audioSampleBank,
AudioTableEntry& entry)
{
int ptr = entry.ptr;
int size = entry.size;
int sampleBankId1 = (entry.data1 >> 8) & 0xFF;
int sampleBankId2 = (entry.data1) & 0xFF;
int numInstruments = (entry.data2 >> 8) & 0xFF;
int numDrums = entry.data2 & 0xFF;
int numSfx = entry.data3;
entry.drums.reserve(numDrums);
entry.soundEffects.reserve(numSfx);
entry.instruments.reserve(numInstruments);
int currentOffset = BitConverter::ToInt32BE(codeData, ptr) + ptr;
for (int i = 0; i < numDrums; i++)
{
DrumEntry drum = {0};
int samplePtr = BitConverter::ToInt32BE(codeData, currentOffset);
if (samplePtr != 0)
{
samplePtr += ptr;
drum.sample = ParseSampleEntry(codeData, audioTable, audioSampleBank[sampleBankId1], sampleBankId1,
BitConverter::ToInt32BE(codeData, samplePtr + 4) + ptr, ptr);
drum.releaseRate = codeData[samplePtr + 0];
drum.pan = codeData[samplePtr + 1];
drum.loaded = codeData[samplePtr + 2];
drum.tuning = BitConverter::ToFloatBE(codeData, samplePtr + 8);
drum.env = ParseEnvelopeData(codeData, audioTable, BitConverter::ToInt32BE(codeData, samplePtr + 12) + ptr, ptr);
}
entry.drums.push_back(drum);
currentOffset += 4;
}
currentOffset = BitConverter::ToInt32BE(codeData, ptr + 4) + ptr;
for (int i = 0; i < numSfx; i++)
{
SoundFontEntry* sfx;
sfx = ParseSoundFontEntry(codeData, audioTable, audioSampleBank[sampleBankId1], sampleBankId1,
currentOffset, ptr);
//if (sfx != nullptr)
entry.soundEffects.push_back(sfx);
currentOffset += 8;
}
for (int i = 0; i < numInstruments; i++)
{
InstrumentEntry instrument;
currentOffset = BitConverter::ToInt32BE(codeData, ptr + 8 + (i * 4));
instrument.isValidInstrument = currentOffset != 0;
if (currentOffset != 0)
{
currentOffset += ptr;
instrument.loaded = codeData[currentOffset + 0];
instrument.normalRangeLo = codeData[currentOffset + 1];
instrument.normalRangeHi = codeData[currentOffset + 2];
instrument.releaseRate = codeData[currentOffset + 3];
instrument.env = ParseEnvelopeData(codeData, audioTable, BitConverter::ToInt32BE(codeData, currentOffset + 4) + ptr, ptr);
if (BitConverter::ToInt32BE(codeData, currentOffset + 8) != 0)
instrument.lowNotesSound = ParseSoundFontEntry(
codeData, audioTable, audioSampleBank[sampleBankId1], sampleBankId1, currentOffset + 8, ptr);
if (BitConverter::ToInt32BE(codeData, currentOffset + 16) != 0)
instrument.normalNotesSound = ParseSoundFontEntry(
codeData, audioTable, audioSampleBank[sampleBankId1], sampleBankId1, currentOffset + 16, ptr);
if (BitConverter::ToInt32BE(codeData, currentOffset + 24) != 0 &&
instrument.normalRangeHi != 0x7F)
instrument.highNotesSound = ParseSoundFontEntry(
codeData, audioTable, audioSampleBank[sampleBankId1], sampleBankId1, currentOffset + 24, ptr);
}
// Interesting audio bug if you put this next line in the if block
entry.instruments.push_back(instrument);
}
}
void ZAudio::ParseRawData()
{
ZResource::ParseRawData();
std::vector<uint8_t> codeData;
std::vector<uint8_t> audioTableData;
std::vector<uint8_t> audioBankData;
std::vector<uint8_t> audioSeqData;
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
codeData = Globals::Instance->GetBaseromFile("code");
else
codeData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "code");
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
audioTableData = Globals::Instance->GetBaseromFile("Audiotable");
else
audioTableData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "Audiotable");
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
audioBankData = Globals::Instance->GetBaseromFile("Audiobank");
else
audioBankData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "Audiobank");
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
audioSeqData = Globals::Instance->GetBaseromFile("Audioseq");
else
audioSeqData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() +
"Audioseq");
// TABLE PARSING
// MQ DBG ROM
//int gSoundFontTableOffset = 0x138270;
//int gSequenceTableOffset = 0x1386A0;
//int gSampleBankTableOffset = 0x138D90;
//int gSequenceFontTableOffset = 0x1384E0;
// NTSC 1.0
//int gSoundFontTableOffset = 0x1026A0;
//int gSequenceTableOffset = 0x102AD0;
//int gSampleBankTableOffset = 0x1031C0;
//int gSequenceFontTableOffset = 0x102910;
int gSoundFontTableOffset = StringHelper::StrToL(registeredAttributes.at("SoundFontTableOffset").value, 16);
int gSequenceTableOffset = StringHelper::StrToL(registeredAttributes.at("SequenceTableOffset").value, 16);
int gSampleBankTableOffset = StringHelper::StrToL(registeredAttributes.at("SampleBankTableOffset").value, 16);
int gSequenceFontTableOffset = StringHelper::StrToL(registeredAttributes.at("SequenceFontTableOffset").value, 16);
soundFontTable = ParseAudioTable(codeData, gSoundFontTableOffset);
sequenceTable = ParseAudioTable(codeData, gSequenceTableOffset);
sampleBankTable = ParseAudioTable(codeData, gSampleBankTableOffset);
fontIndices.reserve(sequenceTable.size());
sequences.reserve(sequenceTable.size());
// SEQEUNCE FONT TABLE PARSING
for (int i = 0; i < sequenceTable.size(); i++)
{
uint16_t idx = BitConverter::ToUInt16BE(codeData, gSequenceFontTableOffset + (i * 2));
uint8_t numFonts = codeData[gSequenceFontTableOffset + (idx++)];
std::vector<uint32_t> fontIds;
for (int j = 0; j < numFonts; j++)
{
uint8_t fontId = codeData[gSequenceFontTableOffset + (idx++)];
fontIds.push_back(fontId);
}
fontIndices.push_back(fontIds);
}
// SAMPLE/FONT PARSING
for (auto& sft : soundFontTable)
{
ParseSoundFont(audioBankData, audioTableData, sampleBankTable, sft);
}
// SEQUENCE PARSING
for (int i = 0; i < sequenceTable.size(); i++)
{
int seqDestIdx = i;
if (sequenceTable[i].size == 0)
seqDestIdx = sequenceTable[i].ptr;
std::vector<char> seqVec = std::vector<char>(sequenceTable[seqDestIdx].size);
memcpy(seqVec.data(), audioSeqData.data() + sequenceTable[seqDestIdx].ptr,
sequenceTable[seqDestIdx].size);
sequences.push_back(seqVec);
}
}
std::string ZAudio::GetSourceTypeName() const
{
return "u8";
}
size_t ZAudio::GetRawDataSize() const
{
return 1;
}
ZResourceType ZAudio::GetResourceType() const
{
return ZResourceType::Audio;
}

130
ZAPDTR/ZAPD/ZAudio.h Normal file
View File

@@ -0,0 +1,130 @@
#pragma once
#include "ZResource.h"
#include "tinyxml2.h"
struct AdsrEnvelope
{
int16_t delay;
int16_t arg;
};
struct AdpcmBook
{
/* 0x00 */ int32_t order;
/* 0x04 */ int32_t npredictors;
/* 0x08 */ std::vector<int16_t> books; // size 8 * order * npredictors. 8-byte aligned
};
struct AdpcmLoop
{
/* 0x00 */ uint32_t start;
/* 0x04 */ uint32_t end;
/* 0x08 */ uint32_t count;
/* 0x10 */ std::vector<int16_t> states;
};
struct SampleEntry
{
std::string fileName;
uint8_t bankId;
uint32_t sampleDataOffset;
uint32_t sampleLoopOffset = 0xFFFFFFFF;
uint8_t codec;
uint8_t medium;
uint8_t unk_bit26;
uint8_t unk_bit25;
std::vector<uint8_t> data;
AdpcmLoop loop;
AdpcmBook book;
};
struct SoundFontEntry
{
SampleEntry* sampleEntry = nullptr;
float tuning;
};
struct DrumEntry
{
uint8_t releaseRate;
uint8_t pan;
uint8_t loaded;
uint32_t offset;
float tuning;
std::vector<AdsrEnvelope*> env;
SampleEntry* sample = nullptr;
};
struct InstrumentEntry
{
bool isValidInstrument;
uint8_t loaded;
uint8_t normalRangeLo;
uint8_t normalRangeHi;
uint8_t releaseRate;
std::vector<AdsrEnvelope*> env;
SoundFontEntry* lowNotesSound = nullptr;
SoundFontEntry* normalNotesSound = nullptr;
SoundFontEntry* highNotesSound = nullptr;
};
struct AudioTableEntry
{
uint32_t ptr;
uint32_t size;
uint8_t medium;
uint8_t cachePolicy;
uint16_t data1;
uint16_t data2;
uint16_t data3;
std::vector<DrumEntry> drums;
std::vector<SoundFontEntry*> soundEffects;
std::vector<InstrumentEntry> instruments;
};
class ZAudio : public ZResource
{
public:
std::vector<AudioTableEntry> soundFontTable;
std::vector<AudioTableEntry> sequenceTable;
std::vector<AudioTableEntry> sampleBankTable;
std::vector<std::vector<char>> sequences;
std::map<uint32_t, SampleEntry*> samples;
std::vector<std::vector<uint32_t>> fontIndices;
std::vector<std::string> seqNames;
std::map<uint32_t, std::string> soundFontNames;
// First Key = Bank ID, Sec Key = Sample Data Offset.
std::map<uint32_t, std::map<uint32_t, std::string>> sampleOffsets;
ZAudio(ZFile* nParent);
void ParseXML(tinyxml2::XMLElement* reader) override;
std::vector<AdsrEnvelope*> ParseEnvelopeData(const std::vector<uint8_t>& audioBank, const std::vector<uint8_t>& audioTable,
int envelopeOffset, int baseOffset);
SoundFontEntry* ParseSoundFontEntry(const std::vector<uint8_t>& audioBank,
const std::vector<uint8_t>& audioTable,
AudioTableEntry audioSampleBankEntry, int bankIndex,
int soundFontOffset,
int baseOffset);
SampleEntry* ParseSampleEntry(const std::vector<uint8_t>& audioBank, const std::vector<uint8_t>& audioTable,
AudioTableEntry audioSampleBankEntry, int bankIndex,
int sampleOffset, int baseOffset);
std::vector<AudioTableEntry> ParseAudioTable(const std::vector<uint8_t>& codeData, int baseOffset);
void ParseSoundFont(const std::vector<uint8_t>& codeData, const std::vector<uint8_t>& audioTable,
const std::vector<AudioTableEntry>& audioSampleBank, AudioTableEntry& entry);
void ParseRawData() override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
};

View File

@@ -0,0 +1,670 @@
/**
* Bruteforcing decoder for converting ADPCM-encoded AIFC into AIFF, in a way
* that roundtrips with vadpcm_enc.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <unistd.h>
typedef signed char s8;
typedef short s16;
typedef int s32;
typedef long long s64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef float f32;
typedef double f64;
#ifdef _MSC_VER
#define __builtin_bswap16 _byteswap_ushort
#define __builtin_bswap32 _byteswap_ulong
#endif
#define bswap16(x) __builtin_bswap16(x)
#define bswap32(x) __builtin_bswap32(x)
#define BSWAP16(x) x = __builtin_bswap16(x)
#define BSWAP32(x) x = __builtin_bswap32(x)
#define BSWAP16_MANY(x, n) \
for (s32 _i = 0; _i < n; _i++) \
BSWAP16((x)[_i])
#define NORETURN __attribute__((noreturn))
#define UNUSED __attribute__((unused))
typedef struct
{
u32 ckID;
u32 ckSize;
} ChunkHeader;
typedef struct
{
u32 ckID;
u32 ckSize;
u32 formType;
} Chunk;
typedef struct
{
s16 numChannels;
u16 numFramesH;
u16 numFramesL;
s16 sampleSize;
s16 sampleRate[5]; // 80-bit float
u16 compressionTypeH;
u16 compressionTypeL;
} CommonChunk;
typedef struct
{
s16 MarkerID;
u16 positionH;
u16 positionL;
} Marker;
typedef struct
{
s16 playMode;
s16 beginLoop;
s16 endLoop;
} Loop;
typedef struct
{
s8 baseNote;
s8 detune;
s8 lowNote;
s8 highNote;
s8 lowVelocity;
s8 highVelocity;
s16 gain;
Loop sustainLoop;
Loop releaseLoop;
} InstrumentChunk;
typedef struct
{
s32 offset;
s32 blockSize;
} SoundDataChunk;
typedef struct
{
s16 version;
s16 order;
s16 nEntries;
} CodeChunk;
typedef struct
{
u32 start;
u32 end;
u32 count;
s16 state[16];
} ALADPCMloop;
static char usage[] = "input.aifc output.aiff";
static const char *progname, *infilename;
static int framesize = 9;
void fail_parse(const char* fmt, ...)
{
char* formatted = NULL;
va_list ap;
va_start(ap, fmt);
int size = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (size >= 0)
{
size++;
formatted = (char*)malloc(size);
if (formatted != NULL)
{
va_start(ap, fmt);
size = vsnprintf(formatted, size, fmt, ap);
va_end(ap);
if (size < 0)
{
free(formatted);
formatted = NULL;
}
}
}
if (formatted != NULL)
{
fprintf(stderr, "%s: %s [%s]\n", progname, formatted, infilename);
free(formatted);
}
exit(1);
}
s32 myrand()
{
static u64 state = 1619236481962341ULL;
state *= 3123692312237ULL;
state += 1;
return state >> 33;
}
s16 qsample(f32 x, s32 scale)
{
if (x > 0.0f)
{
return (s16)((x / scale) + 0.4999999);
}
else
{
return (s16)((x / scale) - 0.4999999);
}
}
void clamp_to_s16(f32* in, s32* out)
{
f32 llevel = -0x8000;
f32 ulevel = 0x7fff;
for (s32 i = 0; i < 16; i++)
{
if (in[i] > ulevel)
in[i] = ulevel;
if (in[i] < llevel)
in[i] = llevel;
if (in[i] > 0.0f)
{
out[i] = (s32)(in[i] + 0.5);
}
else
{
out[i] = (s32)(in[i] - 0.5);
}
}
}
s16 clamp_bits(s32 x, s32 bits)
{
s32 lim = 1 << (bits - 1);
if (x < -lim)
return -lim;
if (x > lim - 1)
return lim - 1;
return x;
}
s32 readaifccodebook(FILE* fhandle, s32**** table, s16* order, s16* npredictors)
{
BSWAP16(*order);
BSWAP16(*npredictors);
*table = (s32***)malloc(*npredictors * sizeof(s32**));
for (s32 i = 0; i < *npredictors; i++)
{
(*table)[i] = (s32**)malloc(8 * sizeof(s32*));
for (s32 j = 0; j < 8; j++)
{
(*table)[i][j] = (s32*)malloc((*order + 8) * sizeof(s32));
}
}
for (s32 i = 0; i < *npredictors; i++)
{
s32** table_entry = (*table)[i];
for (s32 j = 0; j < *order; j++)
{
for (s32 k = 0; k < 8; k++)
{
s16 ts = 0;
BSWAP16(ts);
table_entry[k][j] = ts;
}
}
for (s32 k = 1; k < 8; k++)
{
table_entry[k][*order] = table_entry[k - 1][*order - 1];
}
table_entry[0][*order] = 1 << 11;
for (s32 k = 1; k < 8; k++)
{
s32 j = 0;
for (; j < k; j++)
{
table_entry[j][k + *order] = 0;
}
for (; j < 8; j++)
{
table_entry[j][k + *order] = table_entry[j - k][*order];
}
}
}
return 0;
}
ALADPCMloop* readlooppoints(FILE* ifile, s16* nloops)
{
BSWAP16(*nloops);
ALADPCMloop* al = (ALADPCMloop*)malloc(*nloops * sizeof(ALADPCMloop));
for (s32 i = 0; i < *nloops; i++)
{
BSWAP32(al[i].start);
BSWAP32(al[i].end);
BSWAP32(al[i].count);
BSWAP16_MANY(al[i].state, 16);
}
return al;
}
s32 inner_product(s32 length, s32* v1, s32* v2)
{
s32 out = 0;
for (s32 i = 0; i < length; i++)
{
out += v1[i] * v2[i];
}
// Compute "out / 2^11", rounded down.
s32 dout = out / (1 << 11);
s32 fiout = dout * (1 << 11);
return dout - (out - fiout < 0);
}
void my_decodeframe(u8* frame, s32* decompressed, s32* state, s32 order, s32*** coefTable)
{
s32 ix[16];
u8 header = frame[0];
s32 scale = 1 << (header >> 4);
s32 optimalp = header & 0xf;
if (framesize == 5)
{
for (s32 i = 0; i < 16; i += 4)
{
u8 c = frame[1 + i / 4];
ix[i] = c >> 6;
ix[i + 1] = (c >> 4) & 0x3;
ix[i + 2] = (c >> 2) & 0x3;
ix[i + 3] = c & 0x3;
}
}
else
{
for (s32 i = 0; i < 16; i += 2)
{
u8 c = frame[1 + i / 2];
ix[i] = c >> 4;
ix[i + 1] = c & 0xf;
}
}
for (s32 i = 0; i < 16; i++)
{
if (framesize == 5)
{
if (ix[i] >= 2)
ix[i] -= 4;
}
else
{
if (ix[i] >= 8)
ix[i] -= 16;
}
decompressed[i] = ix[i];
ix[i] *= scale;
}
for (s32 j = 0; j < 2; j++)
{
s32 in_vec[16];
if (j == 0)
{
for (s32 i = 0; i < order; i++)
{
in_vec[i] = state[16 - order + i];
}
}
else
{
for (s32 i = 0; i < order; i++)
{
in_vec[i] = state[8 - order + i];
}
}
for (s32 i = 0; i < 8; i++)
{
s32 ind = j * 8 + i;
in_vec[order + i] = ix[ind];
state[ind] = inner_product(order + i, coefTable[optimalp][i], in_vec) + ix[ind];
}
}
}
void get_bounds(s32* in, s32* decompressed, s32 scale, s32* minVals, s32* maxVals)
{
s32 minv, maxv;
if (framesize == 9)
{
minv = -8;
maxv = 7;
}
else
{
minv = -2;
maxv = 1;
}
for (s32 i = 0; i < 16; i++)
{
s32 lo = in[i] - scale / 2;
s32 hi = in[i] + scale / 2;
lo -= scale;
hi += scale;
if (decompressed[i] == minv)
lo -= scale;
else if (decompressed[i] == maxv)
hi += scale;
minVals[i] = lo;
maxVals[i] = hi;
}
}
void write_header(FILE* ofile, const char* id, s32 size)
{
fwrite(id, 4, 1, ofile);
BSWAP32(size);
fwrite(&size, sizeof(s32), 1, ofile);
}
char* OldMain(char* infilename)
{
s16 order = -1;
s16 nloops = 0;
ALADPCMloop* aloops = NULL;
s16 npredictors = -1;
s32*** coefTable = NULL;
s32 state[16];
s32 decompressed[16];
s32 soundPointer = -1;
s32 currPos = 0;
s32 nSamples = 0;
Chunk FormChunk = Chunk();
ChunkHeader Header = ChunkHeader();
CommonChunk CommChunk = CommonChunk();
InstrumentChunk InstChunk;
SoundDataChunk SndDChunk = SoundDataChunk();
FILE* ifile = NULL;
FILE* ofile = NULL;
if ((ifile = fopen(infilename, "rb")) == NULL)
{
fail_parse("AIFF-C file could not be opened");
exit(1);
}
memset(&InstChunk, 0, sizeof(InstChunk));
BSWAP32(FormChunk.ckID);
BSWAP32(FormChunk.formType);
if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643))
{ // FORM, AIFC
fail_parse("not an AIFF-C file");
}
for (;;)
{
s32 num = fread(&Header, sizeof(Header), 1, ifile);
u32 ts = 0;
if (num <= 0)
break;
BSWAP32(Header.ckID);
BSWAP32(Header.ckSize);
Header.ckSize++;
Header.ckSize &= ~1;
s32 offset = ftell(ifile);
switch (Header.ckID)
{
case 0x434f4d4d: // COMM
{
BSWAP16(CommChunk.numChannels);
BSWAP16(CommChunk.numFramesH);
BSWAP16(CommChunk.numFramesL);
BSWAP16(CommChunk.sampleSize);
BSWAP16(CommChunk.compressionTypeH);
BSWAP16(CommChunk.compressionTypeL);
s32 cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL;
if (cType == 0x56415043 || cType == 0x41445039)
{ // VAPC or ADP9
framesize = 9;
}
else if (cType == 0x41445035)
{ // ADP5
framesize = 5;
}
else if (cType == 0x4850434d)
{ // HPCM
framesize = 16;
}
else
{
char comprType[5] = {
static_cast<char>(CommChunk.compressionTypeH >> 8), static_cast<char>(CommChunk.compressionTypeH & 0xFF),
static_cast<char>(CommChunk.compressionTypeL >> 8), static_cast<char>(CommChunk.compressionTypeL & 0xFF), 0};
fail_parse("file is of the wrong compression type [got %s (%08x)]", &comprType,
cType);
}
if (CommChunk.numChannels != 1)
{
fail_parse("file contains %d channels, only 1 channel supported",
CommChunk.numChannels);
}
if (CommChunk.sampleSize != 16)
{
fail_parse("file contains %d bit samples, only 16 bit samples supported",
CommChunk.sampleSize);
}
nSamples = (CommChunk.numFramesH << 16) + CommChunk.numFramesL;
// Allow broken input lengths
if (nSamples % 16)
{
nSamples -= (nSamples % 16);
}
if (nSamples % 16 != 0)
{
fail_parse("number of chunks must be a multiple of 16, found %d with remainder %d",
nSamples, nSamples % 16);
}
}
break;
case 0x53534e44: // SSND
BSWAP32(SndDChunk.offset);
BSWAP32(SndDChunk.blockSize);
assert(SndDChunk.offset == 0);
assert(SndDChunk.blockSize == 0);
soundPointer = ftell(ifile);
break;
case 0x4150504c: // APPL
BSWAP32(ts);
if (ts == 0x73746f63)
{ // stoc
u8 len = 0;
if (len == 11)
{
char ChunkName[12];
s16 version;
ChunkName[11] = '\0';
if (strcmp("VADPCMCODES", ChunkName) == 0)
{
BSWAP16(version);
if (version != 1)
{
fail_parse("Unknown codebook chunk version");
}
readaifccodebook(ifile, &coefTable, &order, &npredictors);
}
else if (strcmp("VADPCMLOOPS", ChunkName) == 0)
{
BSWAP16(version);
if (version != 1)
{
fail_parse("Unknown loop chunk version");
}
aloops = readlooppoints(ifile, &nloops);
if (nloops != 1)
{
fail_parse("Only a single loop supported");
}
}
}
}
break;
}
fseek(ifile, offset + Header.ckSize, SEEK_SET);
}
if (coefTable == NULL)
{
fail_parse("Codebook missing from bitstream");
}
for (s32 i = 0; i < order; i++)
{
state[15 - i] = 0;
}
u32 outputBytes = nSamples * sizeof(s16);
u8* outputBuf = (u8*)malloc(outputBytes);
fseek(ifile, soundPointer, SEEK_SET);
s32 fails = 0;
while (currPos < nSamples)
{
u8 input[9];
u8 encoded[9];
s32 lastState[16];
s32 decoded[16];
s16 guess[16];
s16 origGuess[16];
memcpy(lastState, state, sizeof(state));
// Decode for real
my_decodeframe(input, decompressed, state, order, coefTable);
memcpy(decoded, state, sizeof(state));
// Create a guess from that, by clamping to 16 bits
for (s32 i = 0; i < 16; i++)
{
origGuess[i] = clamp_bits(state[i], 16);
}
memcpy(state, decoded, sizeof(state));
memcpy(outputBuf + currPos * 2, decoded, sizeof(decoded));
currPos += 16;
}
if (fails)
{
fprintf(stderr, "%s %d\n", infilename, fails);
}
// Write an incomplete file header. We'll fill in the size later.
fwrite("FORM\0\0\0\0AIFF", 12, 1, ofile);
// Subtract 4 from the COMM size to skip the compression field.
write_header(ofile, "COMM", sizeof(CommonChunk) - 4);
CommChunk.numFramesH = nSamples >> 16;
CommChunk.numFramesL = nSamples & 0xffff;
BSWAP16(CommChunk.numChannels);
BSWAP16(CommChunk.numFramesH);
BSWAP16(CommChunk.numFramesL);
BSWAP16(CommChunk.sampleSize);
fwrite(&CommChunk, sizeof(CommonChunk) - 4, 1, ofile);
if (nloops > 0)
{
s32 startPos = aloops[0].start, endPos = aloops[0].end;
const char* markerNames[2] = {"start", "end"};
Marker markers[2] = {{1, static_cast<u16>(startPos >> 16), static_cast<u16>(startPos & 0xffff)},
{2, static_cast<u16>(endPos >> 16), static_cast<u16>(endPos & 0xffff)}};
write_header(ofile, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3);
s16 numMarkers = bswap16(2);
fwrite(&numMarkers, sizeof(s16), 1, ofile);
for (s32 i = 0; i < 2; i++)
{
u8 len = (u8)strlen(markerNames[i]);
BSWAP16(markers[i].MarkerID);
BSWAP16(markers[i].positionH);
BSWAP16(markers[i].positionL);
fwrite(&markers[i], sizeof(Marker), 1, ofile);
fwrite(&len, 1, 1, ofile);
fwrite(markerNames[i], len, 1, ofile);
}
write_header(ofile, "INST", sizeof(InstrumentChunk));
InstChunk.sustainLoop.playMode = bswap16(1);
InstChunk.sustainLoop.beginLoop = bswap16(1);
InstChunk.sustainLoop.endLoop = bswap16(2);
InstChunk.releaseLoop.playMode = 0;
InstChunk.releaseLoop.beginLoop = 0;
InstChunk.releaseLoop.endLoop = 0;
fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile);
}
// Save the coefficient table for use when encoding. Ideally this wouldn't
// be needed and "tabledesign -s 1" would generate the right table, but in
// practice it's difficult to adjust samples to make that happen.
write_header(ofile, "APPL", 4 + 12 + sizeof(CodeChunk) + npredictors * order * 8 * 2);
fwrite("stoc", 4, 1, ofile);
CodeChunk cChunk;
cChunk.version = bswap16(1);
cChunk.order = bswap16(order);
cChunk.nEntries = bswap16(npredictors);
fwrite("\x0bVADPCMCODES", 12, 1, ofile);
fwrite(&cChunk, sizeof(CodeChunk), 1, ofile);
for (s32 i = 0; i < npredictors; i++)
{
for (s32 j = 0; j < order; j++)
{
for (s32 k = 0; k < 8; k++)
{
s16 ts = bswap16(coefTable[i][k][j]);
fwrite(&ts, sizeof(s16), 1, ofile);
}
}
}
write_header(ofile, "SSND", outputBytes + 8);
SndDChunk.offset = 0;
SndDChunk.blockSize = 0;
fwrite(&SndDChunk, sizeof(SoundDataChunk), 1, ofile);
fwrite(outputBuf, outputBytes, 1, ofile);
// Fix the size in the header
s32 fileSize = bswap32(ftell(ofile) - 8);
fseek(ofile, 4, SEEK_SET);
fwrite(&fileSize, 4, 1, ofile);
fclose(ifile);
fclose(ofile);
return 0;
}

200
ZAPDTR/ZAPD/ZBackground.cpp Normal file
View File

@@ -0,0 +1,200 @@
#include "ZBackground.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include <Utils/DiskFile.h>
#include "Utils/Path.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Background, ZBackground);
#define JPEG_MARKER 0xFFD8FFE0
#define MARKER_DQT 0xFFDB
#define MARKER_EOI 0xFFD9
ZBackground::ZBackground(ZFile* nParent) : ZResource(nParent)
{
}
void ZBackground::ParseRawData()
{
ZResource::ParseRawData();
const auto& rawData = parent->GetRawData();
size_t i = 0;
while (true)
{
uint8_t val = rawData.at(rawDataIndex + i);
data.push_back(val);
if (BitConverter::ToUInt16BE(rawData, rawDataIndex + i) == MARKER_EOI)
{
data.push_back(rawData.at(rawDataIndex + i + 1));
break;
}
i++;
}
}
void ZBackground::ParseBinaryFile(const std::string& inFolder, bool appendOutName)
{
fs::path filepath(inFolder);
if (appendOutName)
filepath = filepath / (outName + "." + GetExternalExtension());
data = DiskFile::ReadAllBytes(filepath.string());
// Add padding.
data.insert(data.end(), GetRawDataSize() - data.size(), 0x00);
CheckValidJpeg(filepath.generic_string());
}
void ZBackground::CheckValidJpeg(const std::string& filepath)
{
std::string filename = outName;
if (filepath != "")
{
filename = filepath;
}
uint32_t jpegMarker = BitConverter::ToUInt32BE(data, 0);
if (jpegMarker != JPEG_MARKER)
{
HANDLE_WARNING_PROCESS(
WarningType::InvalidJPEG,
StringHelper::Sprintf("missing jpeg marker at beginning of file: '%s'",
filename.c_str()),
"The game will skip this jpeg.");
}
if (data.at(6) != 'J' || data.at(7) != 'F' || data.at(8) != 'I' || data.at(9) != 'F' ||
data.at(10) != '\0')
{
std::string jfifIdentifier(data.begin() + 6, data.begin() + 6 + 5);
HANDLE_WARNING_PROCESS(
WarningType::InvalidJPEG, "missing 'JFIF' identifier",
StringHelper::Sprintf(
"This image may be corrupted, or not a jpeg. The identifier found was: '%s'",
jfifIdentifier.c_str()));
}
uint8_t majorVersion = data.at(11);
uint8_t minorVersion = data.at(12);
if (majorVersion != 0x01 || minorVersion != 0x01)
{
HANDLE_WARNING_PROCESS(
WarningType::InvalidJPEG,
StringHelper::Sprintf("wrong JFIF version '%i.%02i'", majorVersion, minorVersion),
"The expected version is '1.01'. The game may be unable to decode this image "
"correctly.");
}
if (BitConverter::ToUInt16BE(data, 20) != MARKER_DQT)
{
// This may happen when creating a custom image with Exif, XMP, thumbnail, progressive, etc.
// enabled.
HANDLE_WARNING_PROCESS(WarningType::InvalidJPEG,
"there seems to be extra data before the image data in this file",
"The game may not be able to decode this image correctly.");
}
if (data.size() > GetRawDataSize())
{
HANDLE_WARNING_PROCESS(
WarningType::InvalidJPEG, "the image is bigger than the screen buffer",
StringHelper::Sprintf("Image size: %zu bytes\nScreen buffer size: %zu bytes",
data.size(), GetRawDataSize()));
}
}
size_t ZBackground::GetRawDataSize() const
{
// Jpgs use the whole sceen buffer, which is a u16 matrix.
return Globals::Instance->cfg.bgScreenHeight * Globals::Instance->cfg.bgScreenWidth * 2;
}
Declaration* ZBackground::DeclareVar(const std::string& prefix,
[[maybe_unused]] const std::string& bodyStr)
{
std::string auxName = name;
std::string auxOutName = outName;
if (auxName == "")
auxName = GetDefaultName(prefix);
if (auxOutName == "")
auxOutName = GetDefaultName(prefix);
auto filepath = Globals::Instance->outputPath / fs::path(auxOutName).stem();
std::string incStr =
StringHelper::Sprintf("%s.%s.inc.c", filepath.c_str(), GetExternalExtension().c_str());
Declaration* decl = parent->AddDeclarationIncludeArray(rawDataIndex, incStr, GetRawDataSize(),
GetSourceTypeName(), auxName, 0);
if (Globals::Instance->cfg.useScreenWidthHeightConstants)
{
decl->arrayItemCntStr = "SCREEN_WIDTH * SCREEN_HEIGHT / 4";
decl->forceArrayCnt = true;
}
decl->staticConf = staticConf;
return decl;
}
bool ZBackground::IsExternalResource() const
{
return true;
}
std::string ZBackground::GetExternalExtension() const
{
return "jpg";
}
void ZBackground::Save(const fs::path& outFolder)
{
if (!Globals::Instance->otrMode)
{
fs::path filepath = outFolder / (outName + "." + GetExternalExtension());
DiskFile::WriteAllBytes(filepath.string(), data);
}
}
std::string ZBackground::GetBodySourceCode() const
{
std::string bodyStr = " ";
for (size_t i = 0; i < data.size() / 8; ++i)
{
bodyStr += StringHelper::Sprintf("0x%016llX, ", BitConverter::ToUInt64BE(data, i * 8));
if (i % 8 == 7)
bodyStr += "\n ";
}
bodyStr += "\n";
return bodyStr;
}
std::string ZBackground::GetDefaultName(const std::string& prefix) const
{
return StringHelper::Sprintf("%sBackground_%06X", prefix.c_str(), rawDataIndex);
}
std::string ZBackground::GetSourceTypeName() const
{
return "u64";
}
ZResourceType ZBackground::GetResourceType() const
{
return ZResourceType::Background;
}
DeclarationAlignment ZBackground::GetDeclarationAlignment() const
{
return DeclarationAlignment::Align8;
}

34
ZAPDTR/ZAPD/ZBackground.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#include <vector>
#include "ZResource.h"
class ZBackground : public ZResource
{
protected:
std::vector<uint8_t> data;
public:
ZBackground(ZFile* nParent);
void ParseBinaryFile(const std::string& inFolder, bool appendOutName);
void ParseRawData() override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
std::string GetDefaultName(const std::string& prefix) const override;
void Save(const fs::path& outFolder) override;
bool IsExternalResource() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
std::string GetExternalExtension() const override;
size_t GetRawDataSize() const override;
DeclarationAlignment GetDeclarationAlignment() const override;
void CheckValidJpeg(const std::string& filepath);
};

116
ZAPDTR/ZAPD/ZBlob.cpp Normal file
View File

@@ -0,0 +1,116 @@
#include "ZBlob.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include <Utils/DiskFile.h>
#include "Utils/Path.h"
#include "Utils/StringHelper.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Blob, ZBlob);
ZBlob::ZBlob(ZFile* nParent) : ZResource(nParent)
{
genOTRDef = true;
RegisterRequiredAttribute("Size");
}
ZBlob* ZBlob::FromFile(const std::string& filePath)
{
ZBlob* blob = new ZBlob(nullptr);
blob->name = StringHelper::Split(Path::GetFileNameWithoutExtension(filePath), ".")[0];
blob->blobData = DiskFile::ReadAllBytes(filePath);
return blob;
}
void ZBlob::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
blobSize = StringHelper::StrToL(registeredAttributes.at("Size").value, 16);
}
void ZBlob::ParseRawData()
{
blobData.assign(parent->GetRawData().begin() + rawDataIndex,
parent->GetRawData().begin() + rawDataIndex + blobSize);
}
Declaration* ZBlob::DeclareVar(const std::string& prefix,
[[maybe_unused]] const std::string& bodyStr)
{
std::string auxName = name;
std::string auxOutName = outName;
if (auxName == "")
auxName = GetDefaultName(prefix);
if (auxOutName == "")
auxOutName = GetDefaultName(prefix);
std::string path = Path::GetFileNameWithoutExtension(auxOutName);
std::string assetOutDir =
(Globals::Instance->outputPath / Path::GetFileNameWithoutExtension(GetOutName())).string();
std::string incStr =
StringHelper::Sprintf("%s.%s.inc.c", assetOutDir.c_str(), GetExternalExtension().c_str());
return parent->AddDeclarationIncludeArray(rawDataIndex, incStr, GetRawDataSize(),
GetSourceTypeName(), auxName, blobData.size());
}
std::string ZBlob::GetBodySourceCode() const
{
std::string sourceOutput;
for (size_t i = 0; i < blobData.size(); i += 1)
{
if (i % 16 == 0)
sourceOutput += "\t";
sourceOutput += StringHelper::Sprintf("0x%02X, ", blobData[i]);
if (i % 16 == 15)
sourceOutput += "\n";
}
// Ensure there's always a trailing line feed to prevent dumb warnings.
// Please don't remove this line, unless you somehow made a way to prevent
// that warning when building the OoT repo.
sourceOutput += "\n";
return sourceOutput;
}
void ZBlob::Save(const fs::path& outFolder)
{
if (!Globals::Instance->otrMode)
DiskFile::WriteAllBytes((outFolder / (name + ".bin")).string(), blobData);
}
bool ZBlob::IsExternalResource() const
{
return true;
}
std::string ZBlob::GetExternalExtension() const
{
return "bin";
}
std::string ZBlob::GetSourceTypeName() const
{
return "u8";
}
ZResourceType ZBlob::GetResourceType() const
{
return ZResourceType::Blob;
}
size_t ZBlob::GetRawDataSize() const
{
return blobSize;
}

31
ZAPDTR/ZAPD/ZBlob.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include "ZResource.h"
#include "tinyxml2.h"
class ZBlob : public ZResource
{
public:
ZBlob(ZFile* nParent);
static ZBlob* FromFile(const std::string& filePath);
void ParseXML(tinyxml2::XMLElement* reader) override;
void ParseRawData() override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
void Save(const fs::path& outFolder) override;
bool IsExternalResource() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
std::string GetExternalExtension() const override;
size_t GetRawDataSize() const override;
protected:
std::vector<uint8_t> blobData;
size_t blobSize = 0;
};

307
ZAPDTR/ZAPD/ZCKeyFrame.cpp Normal file
View File

@@ -0,0 +1,307 @@
#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");
genOTRDef = true;
}
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<ZKeyFrameLimbList>(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,
parent->workerID);
else
Globals::Instance->GetSegmentedPtrName(limbsPtr, parent, "KeyFrameFlexLimb", limbStr,
parent->workerID);
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,
parent->workerID);
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,
parent->workerID);
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;
}
}

121
ZAPDTR/ZAPD/ZCKeyFrame.h Normal file
View File

@@ -0,0 +1,121 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <memory>
#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<ZKeyFrameLimb*> 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<ZKeyFrameLimbList> 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;
};

View File

@@ -0,0 +1,221 @@
#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");
genOTRDef = true;
}
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<ZKeyFrameSkel*>(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, parent->workerID);
Globals::Instance->GetSegmentedPtrName(keyFramesAddr, parent, "", keyFrameStr, parent->workerID);
Globals::Instance->GetSegmentedPtrName(kfNumsAddr, parent, "", kfNumsStr, parent->workerID);
Globals::Instance->GetSegmentedPtrName(presentValuesAddr, parent, "", presetValuesStr,
parent->workerID);
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 <typename T>
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;
}

View File

@@ -0,0 +1,52 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <memory>
#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<uint8_t> bitFlags; // Standard only
std::vector<uint16_t> bitFlagsFlex; // Flex only
std::vector<KeyFrame> keyFrames;
std::vector<int16_t> kfNums;
std::vector<int16_t> 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 <typename T>
uint32_t GetSetBits(T data) const;
};

451
ZAPDTR/ZAPD/ZCollision.cpp Normal file
View File

@@ -0,0 +1,451 @@
#include "ZCollision.h"
#include "ZWaterbox.h"
#include <cassert>
#include <cstdint>
#include <string>
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
REGISTER_ZFILENODE(Collision, ZCollisionHeader);
ZCollisionHeader::ZCollisionHeader(ZFile* nParent) : ZResource(nParent)
{
genOTRDef = true;
}
ZCollisionHeader::~ZCollisionHeader()
{
delete camData;
}
void ZCollisionHeader::ParseRawData()
{
const auto& rawData = parent->GetRawData();
absMinX = BitConverter::ToInt16BE(rawData, rawDataIndex + 0);
absMinY = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
absMinZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 4);
absMaxX = BitConverter::ToInt16BE(rawData, rawDataIndex + 6);
absMaxY = BitConverter::ToInt16BE(rawData, rawDataIndex + 8);
absMaxZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 10);
numVerts = BitConverter::ToUInt16BE(rawData, rawDataIndex + 12);
vtxAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 16);
numPolygons = BitConverter::ToUInt16BE(rawData, rawDataIndex + 20);
polyAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 24);
polyTypeDefAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 28);
camDataAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 32);
numWaterBoxes = BitConverter::ToUInt16BE(rawData, rawDataIndex + 36);
waterBoxAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 40);
vtxSegmentOffset = Seg2Filespace(vtxAddress, parent->baseAddress);
polySegmentOffset = Seg2Filespace(polyAddress, parent->baseAddress);
polyTypeDefSegmentOffset = Seg2Filespace(polyTypeDefAddress, parent->baseAddress);
camDataSegmentOffset = Seg2Filespace(camDataAddress, parent->baseAddress);
waterBoxSegmentOffset = Seg2Filespace(waterBoxAddress, parent->baseAddress);
vertices.reserve(numVerts);
polygons.reserve(numPolygons);
waterBoxes.reserve(numWaterBoxes);
offset_t currentPtr = vtxSegmentOffset;
for (uint16_t i = 0; i < numVerts; i++)
{
ZVector vec(parent);
vec.ExtractFromBinary(currentPtr, ZScalarType::ZSCALAR_S16, 3);
currentPtr += vec.GetRawDataSize();
vertices.push_back(vec);
}
for (uint16_t i = 0; i < numPolygons; i++)
{
ZCollisionPoly poly(parent);
poly.SetRawDataIndex(polySegmentOffset + (i * 16));
poly.ParseRawData();
polygons.push_back(poly);
}
uint16_t highestPolyType = 0;
for (const ZCollisionPoly& poly : polygons)
{
if (poly.type > highestPolyType)
highestPolyType = poly.type;
}
for (uint16_t i = 0; i < highestPolyType + 1; i++)
{
ZSurfaceType surfaceType(parent);
surfaceType.SetRawDataIndex(polyTypeDefSegmentOffset + (i * 8));
surfaceType.ParseRawData();
polygonTypes.push_back(surfaceType);
}
// polygonTypes.push_back(
// BitConverter::ToUInt64BE(rawData, polyTypeDefSegmentOffset + (i * 8)));
if (camDataAddress != SEGMENTED_NULL)
{
// Try to guess how many elements the CamDataList array has.
// The "guessing algorithm" is basically a "best effort" one and it
// is error-prone.
// This is based mostly on observation of how CollisionHeader data is
// usually ordered. If for some reason the data was in some other funny
// order, this would probably break.
// The most common ordering is:
// - *BgCamInfo*
// - SurfaceType
// - CollisionPoly
// - Vertices
// - WaterBoxes
// - CollisionHeader
offset_t upperCameraBoundary = polyTypeDefSegmentOffset;
if (upperCameraBoundary == SEGMENTED_NULL)
{
upperCameraBoundary = polySegmentOffset;
}
if (upperCameraBoundary == SEGMENTED_NULL)
{
upperCameraBoundary = vtxSegmentOffset;
}
if (upperCameraBoundary == SEGMENTED_NULL)
{
upperCameraBoundary = waterBoxSegmentOffset;
}
if (upperCameraBoundary == SEGMENTED_NULL)
{
upperCameraBoundary = rawDataIndex;
}
// Sharp Ocarina places the CamDataEntries above the list so we need to calculate the number
// of cameras differently.
if (upperCameraBoundary < camDataSegmentOffset)
{
offset_t offset = camDataSegmentOffset;
while (rawData[offset] == 0x00 && rawData[offset + 0x4] == 0x02)
{
offset += 0x08;
}
upperCameraBoundary = offset;
}
camData =
new CameraDataList(parent, name, rawData, camDataSegmentOffset, upperCameraBoundary);
}
for (int32_t i = 0; i < numWaterBoxes; i++)
{
ZWaterbox waterbox(parent);
waterbox.SetRawDataIndex(waterBoxSegmentOffset +
(i * (Globals::Instance->game == ZGame::OOT_SW97 ? 12 : 16)));
waterbox.ParseRawData();
waterBoxes.emplace_back(waterbox);
}
}
void ZCollisionHeader::DeclareReferences(const std::string& prefix)
{
std::string declaration = "";
std::string auxName = name;
if (name == "")
auxName = GetDefaultName(prefix);
if (waterBoxes.size() > 0)
{
if (!Globals::Instance->otrMode)
{
for (size_t i = 0; i < waterBoxes.size(); i++)
{
declaration +=
StringHelper::Sprintf("\t{ %s },", waterBoxes[i].GetBodySourceCode().c_str());
if (i + 1 < waterBoxes.size())
declaration += "\n";
}
}
parent->AddDeclarationArray(waterBoxSegmentOffset, DeclarationAlignment::Align4,
waterBoxes[0].GetRawDataSize() * waterBoxes.size(),
waterBoxes[0].GetSourceTypeName().c_str(),
StringHelper::Sprintf("%sWaterBoxes", auxName.c_str()),
waterBoxes.size(), declaration);
}
if (polygons.size() > 0)
{
declaration.clear();
if (!Globals::Instance->otrMode)
{
for (size_t i = 0; i < polygons.size(); i++)
{
declaration += StringHelper::Sprintf("\t%s,", polygons[i].GetBodySourceCode().c_str());
if (i + 1 < polygons.size())
declaration += "\n";
}
}
parent->AddDeclarationArray(polySegmentOffset, DeclarationAlignment::Align4,
polygons.size() * 16, polygons[0].GetSourceTypeName().c_str(),
StringHelper::Sprintf("%sPolygons", auxName.c_str()),
polygons.size(), declaration);
}
declaration.clear();
for (const auto& polyType : polygonTypes)
{
declaration += StringHelper::Sprintf("\t%s,", polyType.GetBodySourceCode().c_str());
}
if (polyTypeDefAddress != SEGMENTED_NULL)
parent->AddDeclarationArray(polyTypeDefSegmentOffset, DeclarationAlignment::Align4,
polygonTypes.size() * 8,
polygonTypes[0].GetSourceTypeName().c_str(),
StringHelper::Sprintf("%sSurfaceType", auxName.c_str()),
polygonTypes.size(), declaration);
declaration.clear();
if (vertices.size() > 0)
{
declaration.clear();
if (!Globals::Instance->otrMode)
{
for (size_t i = 0; i < vertices.size(); i++)
{
declaration +=
StringHelper::Sprintf("\t{ %s },", vertices[i].GetBodySourceCode().c_str());
if (i < vertices.size() - 1)
declaration += "\n";
}
}
const auto& first = vertices.front();
if (vtxAddress != 0)
parent->AddDeclarationArray(
vtxSegmentOffset, first.GetDeclarationAlignment(),
vertices.size() * first.GetRawDataSize(), first.GetSourceTypeName(),
StringHelper::Sprintf("%sVertices", auxName.c_str()), vertices.size(), declaration);
}
}
std::string ZCollisionHeader::GetBodySourceCode() const
{
std::string declaration = "";
if (Globals::Instance->otrMode)
return declaration;
declaration += "\n";
declaration += StringHelper::Sprintf("\t{ %i, %i, %i },\n", absMinX, absMinY, absMinZ);
declaration += StringHelper::Sprintf("\t{ %i, %i, %i },\n", absMaxX, absMaxY, absMaxZ);
std::string vtxName;
Globals::Instance->GetSegmentedPtrName(vtxAddress, parent, "Vec3s", vtxName, parent->workerID);
if (numVerts > 0)
declaration +=
StringHelper::Sprintf("\tARRAY_COUNT(%s), %s,\n", vtxName.c_str(), vtxName.c_str());
else
declaration += StringHelper::Sprintf("\t%i, %s,\n", numVerts, vtxName.c_str());
std::string polyName;
Globals::Instance->GetSegmentedPtrName(polyAddress, parent, "CollisionPoly", polyName, parent->workerID);
if (numPolygons > 0)
declaration +=
StringHelper::Sprintf("\tARRAY_COUNT(%s), %s,\n", polyName.c_str(), polyName.c_str());
else
declaration += StringHelper::Sprintf("\t%i, %s,\n", numPolygons, polyName.c_str());
std::string surfaceName;
Globals::Instance->GetSegmentedPtrName(polyTypeDefAddress, parent, "SurfaceType", surfaceName, parent->workerID);
declaration += StringHelper::Sprintf("\t%s,\n", surfaceName.c_str());
std::string camName;
Globals::Instance->GetSegmentedPtrName(camDataAddress, parent, "BgCamInfo", camName, parent->workerID);
declaration += StringHelper::Sprintf("\t%s,\n", camName.c_str());
std::string waterBoxName;
Globals::Instance->GetSegmentedPtrName(waterBoxAddress, parent, "WaterBox", waterBoxName, parent->workerID);
if (numWaterBoxes > 0)
declaration += StringHelper::Sprintf("\tARRAY_COUNT(%s), %s\n", waterBoxName.c_str(),
waterBoxName.c_str());
else
declaration += StringHelper::Sprintf("\t%i, %s\n", numWaterBoxes, waterBoxName.c_str());
return declaration;
}
std::string ZCollisionHeader::GetDefaultName(const std::string& prefix) const
{
return StringHelper::Sprintf("%sCol_%06X", prefix.c_str(), rawDataIndex);
}
std::string ZCollisionHeader::GetSourceTypeName() const
{
return "CollisionHeader";
}
ZResourceType ZCollisionHeader::GetResourceType() const
{
return ZResourceType::CollisionHeader;
}
size_t ZCollisionHeader::GetRawDataSize() const
{
return 44;
}
#if 0
WaterBoxHeader::WaterBoxHeader(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex)
{
xMin = BitConverter::ToInt16BE(rawData, rawDataIndex + 0);
ySurface = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
zMin = BitConverter::ToInt16BE(rawData, rawDataIndex + 4);
xLength = BitConverter::ToInt16BE(rawData, rawDataIndex + 6);
zLength = BitConverter::ToInt16BE(rawData, rawDataIndex + 8);
if (Globals::Instance->game == ZGame::OOT_SW97)
properties = BitConverter::ToInt16BE(rawData, rawDataIndex + 10);
else
properties = BitConverter::ToInt32BE(rawData, rawDataIndex + 12);
}
std::string WaterBoxHeader::GetBodySourceCode() const
{
return StringHelper::Sprintf("%i, %i, %i, %i, %i, 0x%08X", xMin, ySurface, zMin, xLength,
zLength, properties);
}
#endif
CameraDataList::CameraDataList(ZFile* parent, const std::string& prefix,
const std::vector<uint8_t>& rawData, offset_t rawDataIndex,
offset_t upperCameraBoundary)
{
std::string declaration;
// Parse CameraDataEntries
size_t numElements = (upperCameraBoundary - rawDataIndex) / 8;
assert(numElements < 10000);
offset_t cameraPosDataSeg = rawDataIndex;
uint32_t numDataTotal;
uint32_t cameraPosDataSegEnd = rawDataIndex;
bool isSharpOcarina = false;
for (size_t i = 0; i < numElements; i++)
{
CameraDataEntry entry;
entry.cameraSType =
BitConverter::ToInt16BE(rawData, rawDataIndex + (entries.size() * 8) + 0);
entry.numData = BitConverter::ToInt16BE(rawData, rawDataIndex + (entries.size() * 8) + 2);
entry.cameraPosDataSeg =
BitConverter::ToInt32BE(rawData, rawDataIndex + (entries.size() * 8) + 4);
if (entry.cameraPosDataSeg != 0 && GETSEGNUM(entry.cameraPosDataSeg) != SEGMENT_SCENE)
{
cameraPosDataSeg = rawDataIndex + (entries.size() * 8);
break;
}
if (rawDataIndex > GETSEGOFFSET(entry.cameraPosDataSeg))
{
if (entry.cameraPosDataSeg != 0 &&
cameraPosDataSeg > GETSEGOFFSET(entry.cameraPosDataSeg))
cameraPosDataSeg = GETSEGOFFSET(entry.cameraPosDataSeg);
}
else
{
// Sharp Ocarina will place the cam data after the list as opposed to the original maps
// which have it before.
isSharpOcarina = true;
cameraPosDataSeg = rawDataIndex + (numElements * 0x8);
if (cameraPosDataSegEnd < GETSEGOFFSET(entry.cameraPosDataSeg))
cameraPosDataSegEnd = GETSEGOFFSET(entry.cameraPosDataSeg);
}
entries.emplace_back(entry);
}
// Setting cameraPosDataAddr to rawDataIndex give a pos list length of 0
uint32_t cameraPosDataOffset = GETSEGOFFSET(cameraPosDataSeg);
for (size_t i = 0; i < entries.size(); i++)
{
char camSegLine[2048];
if (entries[i].cameraPosDataSeg != 0)
{
uint32_t index =
(GETSEGOFFSET(entries[i].cameraPosDataSeg) - cameraPosDataOffset) / 0x6;
snprintf(camSegLine, 2048, "&%sCamPosData[%i]", prefix.c_str(), index);
}
else
snprintf(camSegLine, 2048, "NULL");
declaration +=
StringHelper::Sprintf(" { 0x%04X, %i, %s },", entries[i].cameraSType,
entries[i].numData, camSegLine, rawDataIndex + (i * 8));
if (i < entries.size() - 1)
declaration += "\n";
}
parent->AddDeclarationArray(
rawDataIndex, DeclarationAlignment::Align4, entries.size() * 8, "BgCamInfo",
StringHelper::Sprintf("%sCamDataList", prefix.c_str(), rawDataIndex), entries.size(),
declaration);
if (!isSharpOcarina)
numDataTotal = (rawDataIndex - cameraPosDataOffset) / 0x6;
else
numDataTotal = ((cameraPosDataSegEnd - cameraPosDataSeg) + 18) / 0x6;
if (numDataTotal > 0)
{
declaration.clear();
cameraPositionData.reserve(numDataTotal);
for (uint32_t i = 0; i < numDataTotal; i++)
{
CameraPositionData data = CameraPositionData(rawData, cameraPosDataOffset + (i * 6));
declaration += StringHelper::Sprintf("\t{ %6i, %6i, %6i },", data.x, data.y, data.z);
cameraPositionData.emplace_back(data);
if (i + 1 < numDataTotal)
declaration += "\n";
}
uint32_t cameraPosDataIndex = GETSEGOFFSET(cameraPosDataSeg);
uint32_t entrySize = numDataTotal * 0x6;
parent->AddDeclarationArray(cameraPosDataIndex, DeclarationAlignment::Align4, entrySize,
"Vec3s", StringHelper::Sprintf("%sCamPosData", prefix.c_str()),
numDataTotal, declaration);
}
}
CameraDataList::~CameraDataList()
{
//for (auto entry : entries)
// delete entry;
//
//for (auto camPosData : cameraPositionData)
// delete camPosData;
}
CameraPositionData::CameraPositionData(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex)
{
x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0);
y = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
z = BitConverter::ToInt16BE(rawData, rawDataIndex + 4);
}

75
ZAPDTR/ZAPD/ZCollision.h Normal file
View File

@@ -0,0 +1,75 @@
#pragma once
#include "ZCollisionPoly.h"
#include "ZFile.h"
#include "ZResource.h"
#include "ZRoom/ZRoom.h"
#include "ZSurfaceType.h"
#include "ZVector.h"
#include "ZWaterbox.h"
class CameraPositionData
{
public:
int16_t x, y, z;
CameraPositionData(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex);
};
class CameraDataEntry
{
public:
int16_t cameraSType;
int16_t numData;
offset_t cameraPosDataSeg;
};
class CameraDataList
{
public:
std::vector<CameraDataEntry> entries;
std::vector<CameraPositionData> cameraPositionData;
CameraDataList(ZFile* parent, const std::string& prefix, const std::vector<uint8_t>& rawData,
offset_t rawDataIndex, offset_t upperCameraBoundary);
~CameraDataList();
};
class ZCollisionHeader : public ZResource
{
public:
int16_t absMinX, absMinY, absMinZ;
int16_t absMaxX, absMaxY, absMaxZ;
uint16_t numVerts;
segptr_t vtxAddress;
uint16_t numPolygons;
segptr_t polyAddress;
segptr_t polyTypeDefAddress;
segptr_t camDataAddress;
int32_t numWaterBoxes;
segptr_t waterBoxAddress;
uint32_t vtxSegmentOffset, polySegmentOffset, polyTypeDefSegmentOffset, camDataSegmentOffset,
waterBoxSegmentOffset;
std::vector<ZVector> vertices;
std::vector<ZCollisionPoly> polygons;
std::vector<ZSurfaceType> polygonTypes;
std::vector<ZWaterbox> waterBoxes;
CameraDataList* camData = nullptr;
ZCollisionHeader(ZFile* nParent);
~ZCollisionHeader();
void ParseRawData() override;
void DeclareReferences(const std::string& prefix) override;
std::string GetBodySourceCode() const override;
std::string GetDefaultName(const std::string& prefix) const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
};

View File

@@ -0,0 +1,78 @@
#include "ZCollisionPoly.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
REGISTER_ZFILENODE(CollisionPoly, ZCollisionPoly);
ZCollisionPoly::ZCollisionPoly(ZFile* nParent) : ZResource(nParent)
{
}
ZCollisionPoly::~ZCollisionPoly()
{
}
void ZCollisionPoly::ParseRawData()
{
const auto& rawData = parent->GetRawData();
type = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0);
vtxA = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
vtxB = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4);
vtxC = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6);
normX = BitConverter::ToUInt16BE(rawData, rawDataIndex + 8);
normY = BitConverter::ToUInt16BE(rawData, rawDataIndex + 10);
normZ = BitConverter::ToUInt16BE(rawData, rawDataIndex + 12);
dist = BitConverter::ToUInt16BE(rawData, rawDataIndex + 14);
}
void ZCollisionPoly::DeclareReferences(const std::string& prefix)
{
std::string declaration;
std::string auxName = name;
if (name == "")
auxName = GetDefaultName(prefix);
parent->AddDeclaration(rawDataIndex, DeclarationAlignment::Align4, GetRawDataSize(),
GetSourceTypeName(), name.c_str(), GetBodySourceCode());
}
std::string ZCollisionPoly::GetBodySourceCode() const
{
std::string declaration;
declaration +=
StringHelper::Sprintf("{0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X}",
type, vtxA, vtxB, vtxC, normX, normY, normZ, dist);
return declaration;
}
std::string ZCollisionPoly::GetDefaultName(const std::string& prefix) const
{
return StringHelper::Sprintf("%sCollisionPoly_%06X", prefix.c_str(), rawDataIndex);
}
ZResourceType ZCollisionPoly::GetResourceType() const
{
return ZResourceType::CollisionPoly;
}
size_t ZCollisionPoly::GetRawDataSize() const
{
return 16;
}
std::string ZCollisionPoly::GetSourceTypeName() const
{
return "CollisionPoly";
}
bool ZCollisionPoly::DoesSupportArray() const
{
return true;
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "ZFile.h"
#include "ZResource.h"
class ZCollisionPoly : public ZResource
{
public:
uint16_t type;
uint16_t vtxA, vtxB, vtxC;
uint16_t normX, normY, normZ;
uint16_t dist;
ZCollisionPoly(ZFile* nParent);
~ZCollisionPoly();
void ParseRawData() override;
void DeclareReferences(const std::string& prefix) override;
std::string GetBodySourceCode() const override;
std::string GetDefaultName(const std::string& prefix) const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
bool DoesSupportArray() const override;
size_t GetRawDataSize() const override;
};

375
ZAPDTR/ZAPD/ZCutscene.cpp Normal file
View File

@@ -0,0 +1,375 @@
#include "ZCutscene.h"
#include <cassert>
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZResource.h"
REGISTER_ZFILENODE(Cutscene, ZCutscene);
ZCutscene::ZCutscene(ZFile* nParent) : ZResource(nParent)
{
genOTRDef = true;
}
ZCutscene::~ZCutscene()
{
for (CutsceneCommand* cmd : commands)
delete cmd;
}
std::string ZCutscene::GetBodySourceCode() const
{
std::string output = "";
output += StringHelper::Sprintf(" CS_BEGIN_CUTSCENE(%i, %i),\n", commands.size(), endFrame);
for (size_t i = 0; i < commands.size(); i++)
{
CutsceneCommand* cmd = commands[i];
output += " " + cmd->GenerateSourceCode();
}
output += StringHelper::Sprintf(" CS_END(),", commands.size(), endFrame);
return output;
}
size_t ZCutscene::GetRawDataSize() const
{
size_t size = 0;
// Beginning
size += 8;
for (size_t i = 0; i < commands.size(); i++)
{
CutsceneCommand* cmd = commands[i];
size += cmd->GetCommandSize();
}
// End
if (Globals::Instance->game == ZGame::MM_RETAIL)
{
size += 4;
}
else
{
size += 8;
}
return size;
}
void ZCutscene::ParseRawData()
{
ZResource::ParseRawData();
const auto& rawData = parent->GetRawData();
numCommands = BitConverter::ToInt32BE(rawData, rawDataIndex + 0);
commands = std::vector<CutsceneCommand*>();
endFrame = BitConverter::ToInt32BE(rawData, rawDataIndex + 4);
offset_t currentPtr = rawDataIndex + 8;
commands.reserve(numCommands);
for (int32_t i = 0; i < numCommands; i++)
{
uint32_t id = BitConverter::ToUInt32BE(rawData, currentPtr);
if (id == 0xFFFFFFFF)
break;
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG)
{
printf("Cutscene Command: 0x%X (%i)\n", id, id);
}
currentPtr += 4;
CutsceneCommand* cmd = nullptr;
if (Globals::Instance->game == ZGame::MM_RETAIL)
{
cmd = GetCommandMM(id, currentPtr);
}
else
{
cmd = GetCommandOoT(id, currentPtr);
}
if (cmd == nullptr)
{
HANDLE_WARNING_RESOURCE(
WarningType::NotImplemented, parent, this, rawDataIndex,
StringHelper::Sprintf("Cutscene command not implemented"),
StringHelper::Sprintf("Command ID: 0x%X\nIndex: %d\ncurrentPtr-rawDataIndex: 0x%X",
id, i, currentPtr - rawDataIndex));
cmd = new CutsceneMMCommand_NonImplemented(rawData, currentPtr);
}
assert(cmd != nullptr);
cmd->commandIndex = i;
cmd->SetCommandID(id);
size_t commmandSize = cmd->GetCommandSize();
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG)
{
printf("\t Command size: 0x%zX (%zu)\n", commmandSize, commmandSize);
}
currentPtr += commmandSize - 4;
commands.push_back(cmd);
}
}
CutsceneCommand* ZCutscene::GetCommandOoT(uint32_t id, offset_t currentPtr) const
{
CutsceneOoT_CommandType cmdID = static_cast<CutsceneOoT_CommandType>(id);
const auto& rawData = parent->GetRawData();
switch (cmdID)
{
case CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_1:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_8_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_7:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_7:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_8:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_7:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_8:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_7:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_9:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_10:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_8:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_9:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_8:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_2:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_9:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_11:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_10:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_9:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_11:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_10:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_12:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_3:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_4:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_12:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_10:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_13:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_13:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_14:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_11:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_14:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_15:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_12:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_11:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_7:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_16:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_13:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_12:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_5:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_8:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_7:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_15:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_16:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_17:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_6:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_9_0:
case CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_17:
return new CutsceneOoTCommand_ActorCue(rawData, currentPtr);
case CutsceneOoT_CommandType::CS_CMD_MISC:
case CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING:
case CutsceneOoT_CommandType::CS_CMD_START_SEQ:
case CutsceneOoT_CommandType::CS_CMD_STOP_SEQ:
case CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ:
return new CutsceneOoTCommand_GenericCmd(rawData, currentPtr, cmdID);
case CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE:
case CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE:
case CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER:
case CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER:
return new CutsceneOoTCommand_GenericCameraCmd(rawData, currentPtr);
case CutsceneOoT_CommandType::CS_CMD_RUMBLE_CONTROLLER:
return new CutsceneOoTCommand_Rumble(rawData, currentPtr);
case CutsceneOoT_CommandType::CS_CMD_TEXT:
return new CutsceneOoTCommand_Text(rawData, currentPtr);
case CutsceneOoT_CommandType::CS_CMD_TRANSITION:
return new CutsceneOoTCommand_Transition(rawData, currentPtr);
case CutsceneOoT_CommandType::CS_CMD_TIME:
return new CutsceneCommand_Time(rawData, currentPtr);
case CutsceneOoT_CommandType::CS_CMD_DESTINATION:
return new CutsceneOoTCommand_Destination(rawData, currentPtr);
case CutsceneOoT_CommandType::CS_CMD_CAM_EYE:
case CutsceneOoT_CommandType::CS_CMD_CAM_AT:
break;
default:
std::string errorHeader =
StringHelper::Sprintf("Warning: Invalid cutscene command ID: '0x%04X'", cmdID);
return new CutsceneOoTCommand_GenericCmd(rawData, currentPtr, cmdID);
}
return nullptr;
}
CutsceneCommand* ZCutscene::GetCommandMM(uint32_t id, offset_t currentPtr) const
{
CutsceneMM_CommandType cmdID = static_cast<CutsceneMM_CommandType>(id);
const auto& rawData = parent->GetRawData();
if (((id >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_100) &&
(id <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_149)) ||
(id == (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_201) ||
((id >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_450) &&
(id <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_599)))
{
return new CutsceneMMCommand_ActorCue(rawData, currentPtr);
}
switch (cmdID)
{
case CutsceneMM_CommandType::CS_CMD_MISC:
case CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING:
case CutsceneMM_CommandType::CS_CMD_TRANSITION:
case CutsceneMM_CommandType::CS_CMD_MOTION_BLUR:
case CutsceneMM_CommandType::CS_CMD_GIVE_TATL:
case CutsceneMM_CommandType::CS_CMD_START_SEQ:
case CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_2:
case CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_1:
case CutsceneMM_CommandType::CS_CMD_MODIFY_SEQ:
case CutsceneMM_CommandType::CS_CMD_STOP_SEQ:
case CutsceneMM_CommandType::CS_CMD_START_AMBIENCE:
case CutsceneMM_CommandType::CS_CMD_FADE_OUT_AMBIENCE:
case CutsceneMM_CommandType::CS_CMD_DESTINATION:
case CutsceneMM_CommandType::CS_CMD_CHOOSE_CREDITS_SCENES:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FA:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FE:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FF:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_100:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_101:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_102:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_103:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_104:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_105:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_108:
case CutsceneMM_CommandType::CS_CMD_UNK_DATA_109:
return new CutsceneMMCommand_GenericCmd(rawData, currentPtr, cmdID);
case CutsceneMM_CommandType::CS_CMD_TEXT:
return new CutsceneMMCommand_Text(rawData, currentPtr);
case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE:
return new CutsceneMMCommand_Spline(rawData, currentPtr);
case CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL:
return new CutsceneMMCommand_TransitionGeneral(rawData, currentPtr);
case CutsceneMM_CommandType::CS_CMD_FADE_OUT_SEQ:
return new CutsceneMMCommand_FadeOutSeq(rawData, currentPtr);
case CutsceneMM_CommandType::CS_CMD_TIME:
return new CutsceneCommand_Time(rawData, currentPtr);
case CutsceneMM_CommandType::CS_CMD_PLAYER_CUE:
return new CutsceneMMCommand_ActorCue(rawData, currentPtr);
case CutsceneMM_CommandType::CS_CMD_RUMBLE:
return new CutsceneMMCommand_Rumble(rawData, currentPtr);
default:
std::string errorHeader =
StringHelper::Sprintf("Warning: Invalid cutscene command ID: '0x%04X'", cmdID);
return new CutsceneMMCommand_GenericCmd(rawData, currentPtr, cmdID);
}
return nullptr;
}
Declaration* ZCutscene::DeclareVar(const std::string& prefix, const std::string& bodyStr)
{
std::string auxName = name;
if (auxName == "")
auxName = GetDefaultName(prefix);
Declaration* decl =
parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(),
GetSourceTypeName(), auxName, 0, bodyStr);
decl->staticConf = staticConf;
return decl;
}
std::string ZCutscene::GetSourceTypeName() const
{
return "CutsceneData";
}
ZResourceType ZCutscene::GetResourceType() const
{
return ZResourceType::Cutscene;
}

37
ZAPDTR/ZAPD/ZCutscene.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "tinyxml2.h"
#include "OtherStructs/CutsceneOoT_Commands.h"
#include "OtherStructs/CutsceneMM_Commands.h"
#include "ZFile.h"
#include "ZResource.h"
class ZCutscene : public ZResource
{
public:
ZCutscene(ZFile* nParent);
~ZCutscene();
void ParseRawData() override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
size_t GetRawDataSize() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
int32_t numCommands;
int32_t endFrame;
std::vector<CutsceneCommand*> commands;
protected:
CutsceneCommand* GetCommandOoT(uint32_t id, offset_t currentPtr) const;
CutsceneCommand* GetCommandMM(uint32_t id, offset_t currentPtr) const;
};

2324
ZAPDTR/ZAPD/ZDisplayList.cpp Normal file

File diff suppressed because it is too large Load Diff

265
ZAPDTR/ZAPD/ZDisplayList.h Normal file
View File

@@ -0,0 +1,265 @@
#pragma once
#include "ZMtx.h"
#include "ZResource.h"
#include "ZRoom/ZRoom.h"
#include "ZTexture.h"
#include "ZVtx.h"
#include "tinyxml2.h"
#include <map>
#include <string>
#include <vector>
enum class F3DEXOpcode
{
G_SPNOOP = 0x00,
G_MTX = 0x01,
G_MOVEMEM = 0x03,
G_VTX = 0x04,
G_DL = 0x06,
G_LOAD_UCODE = 0xAF,
G_BRANCH_Z = 0xB0,
G_TRI2 = 0xB1,
G_MODIFYVTX = 0xB2,
G_RDPHALF_2 = 0xB3,
G_RDPHALF_1 = 0xB4,
G_QUAD = 0xB5,
G_CLEARGEOMETRYMODE = 0xB6,
G_SETGEOMETRYMODE = 0xB7,
G_ENDDL = 0xB8,
G_SETOTHERMODE_L = 0xB9,
G_SETOTHERMODE_H = 0xBA,
G_TEXTURE = 0xBB,
G_MOVEWORD = 0xBC,
G_POPMTX = 0xBD,
G_CULLDL = 0xBE,
G_TRI1 = 0xBF,
G_NOOP = 0xC0,
G_TEXRECT = 0xE4,
G_TEXRECTFLIP = 0xE5,
G_RDPLOADSYNC = 0xE6,
G_RDPPIPESYNC = 0xE7,
G_RDPTILESYNC = 0xE8,
G_RDPFULLSYNC = 0xE9,
G_SETKEYGB = 0xEA,
G_SETKEYR = 0xEB,
G_SETCONVERT = 0xEC,
G_SETSCISSOR = 0xED,
G_SETPRIMDEPTH = 0xEE,
G_RDPSETOTHERMODE = 0xEF,
G_LOADTLUT = 0xF0,
G_SETTILESIZE = 0xF2,
G_LOADBLOCK = 0xF3,
G_LOADTILE = 0xF4,
G_SETTILE = 0xF5,
G_FILLRECT = 0xF6,
G_SETFILLCOLOR = 0xF7,
G_SETFOGCOLOR = 0xF8,
G_SETBLENDCOLOR = 0xF9,
G_SETPRIMCOLOR = 0xFA,
G_SETENVCOLOR = 0xFB,
G_SETCOMBINE = 0xFC,
G_SETTIMG = 0xFD,
G_SETZIMG = 0xFE,
G_SETCIMG = 0xFF
};
enum class F3DZEXOpcode
{
G_NOOP = 0x00,
G_VTX = 0x01,
G_MODIFYVTX = 0x02,
G_CULLDL = 0x03,
G_BRANCH_Z = 0x04,
G_TRI1 = 0x05,
G_TRI2 = 0x06,
G_QUAD = 0x07,
G_SPECIAL_3 = 0xD3,
G_SPECIAL_2 = 0xD4,
G_SPECIAL_1 = 0xD5,
G_DMA_IO = 0xD6,
G_TEXTURE = 0xD7,
G_POPMTX = 0xD8,
G_GEOMETRYMODE = 0xD9,
G_MTX = 0xDA,
G_MOVEWORD = 0xDB,
G_MOVEMEM = 0xDC,
G_LOAD_UCODE = 0xDD,
G_DL = 0xDE,
G_ENDDL = 0xDF,
G_SPNOOP = 0xE0,
G_RDPHALF_1 = 0xE1,
G_SETOTHERMODE_L = 0xE2,
G_SETOTHERMODE_H = 0xE3,
G_TEXRECT = 0xE4,
G_TEXRECTFLIP = 0xE5,
G_RDPLOADSYNC = 0xE6,
G_RDPPIPESYNC = 0xE7,
G_RDPTILESYNC = 0xE8,
G_RDPFULLSYNC = 0xE9,
G_SETKEYGB = 0xEA,
G_SETKEYR = 0xEB,
G_SETCONVERT = 0xEC,
G_SETSCISSOR = 0xED,
G_SETPRIMDEPTH = 0xEE,
G_RDPSETOTHERMODE = 0xEF,
G_LOADTLUT = 0xF0,
G_RDPHALF_2 = 0xF1,
G_SETTILESIZE = 0xF2,
G_LOADBLOCK = 0xF3,
G_LOADTILE = 0xF4,
G_SETTILE = 0xF5,
G_FILLRECT = 0xF6,
G_SETFILLCOLOR = 0xF7,
G_SETFOGCOLOR = 0xF8,
G_SETBLENDCOLOR = 0xF9,
G_SETPRIMCOLOR = 0xFA,
G_SETENVCOLOR = 0xFB,
G_SETCOMBINE = 0xFC,
G_SETTIMG = 0xFD,
G_SETZIMG = 0xFE,
G_SETCIMG = 0xFF,
};
enum class F3DZEXTexFormats
{
G_IM_FMT_RGBA,
G_IM_FMT_YUV,
G_IM_FMT_CI,
G_IM_FMT_IA,
G_IM_FMT_I
};
enum class F3DZEXTexSizes
{
G_IM_SIZ_4b,
G_IM_SIZ_8b,
G_IM_SIZ_16b,
G_IM_SIZ_32b
};
enum class DListType
{
F3DZEX,
F3DEX,
};
enum class OoTSegments
{
DirectReference = 0,
TitleStatic = 1,
Scene = 2,
Room = 3,
GameplayKeep = 4,
FieldDungeonKeep = 5,
Object = 6,
LinkAnimation = 7,
IconItemStatic = 8,
IconItem24Static = 9,
Unknown10 = 10,
Unknown11 = 11,
Unknown12 = 12,
IconFieldDungeonStatic = 13,
IconItemLanguageStatic = 14,
ZBuffer = 15,
FrameBuffer = 16,
};
class ZDisplayList : public ZResource
{
protected:
static TextureType TexFormatToTexType(F3DZEXTexFormats fmt, F3DZEXTexSizes siz);
void ParseF3DZEX(F3DZEXOpcode opcode, uint64_t data, int32_t i, const std::string& prefix,
char* line);
void ParseF3DEX(F3DEXOpcode opcode, uint64_t data, const std::string& prefix, char* line);
// Various Instruction Optimizations
bool SequenceCheck(std::vector<F3DZEXOpcode> sequence, int32_t startIndex);
int32_t OptimizationChecks(int32_t startIndex, std::string& output, const std::string& prefix);
int32_t OptimizationCheck_LoadTextureBlock(int32_t startIndex, std::string& output,
const std::string& prefix);
// int32_t OptimizationCheck_LoadMultiBlock(int32_t startIndex, std::string& output, std::string
// prefix);
// F3DEX Specific Opcode Values
void Opcode_F3DEX_G_SETOTHERMODE_L(uint64_t data, char* line);
// Shared Opcodes between F3DZEX and F3DEX
void Opcode_G_DL(uint64_t data, const std::string& prefix, char* line);
void Opcode_G_MODIFYVTX(uint64_t data, char* line);
void Opcode_G_CULLDL(uint64_t data, char* line);
void Opcode_G_TRI1(uint64_t data, char* line);
void Opcode_G_TRI2(uint64_t data, char* line);
void Opcode_G_MTX(uint64_t data, char* line);
void Opcode_G_VTX(uint64_t data, char* line);
void Opcode_G_TEXTURE(uint64_t data, char* line);
void Opcode_G_SETTIMG(uint64_t data, const std::string& prefix, char* line);
void Opcode_G_SETTILE(uint64_t data, char* line);
void Opcode_G_SETTILESIZE(uint64_t data, const std::string& prefix, char* line);
void Opcode_G_LOADBLOCK(uint64_t data, char* line);
void Opcode_G_SETCOMBINE(uint64_t data, char* line);
void Opcode_G_SETPRIMCOLOR(uint64_t data, char* line);
void Opcode_G_SETOTHERMODE_L(uint64_t data, char* line);
void Opcode_G_SETOTHERMODE_H(uint64_t data, char* line);
void Opcode_G_LOADTLUT(uint64_t data, const std::string& prefix, char* line);
void Opcode_G_ENDDL(const std::string& prefix, char* line);
public:
std::vector<uint64_t> instructions;
int32_t lastTexWidth, lastTexHeight, lastTexAddr, lastTexSeg;
F3DZEXTexFormats lastTexFmt;
F3DZEXTexSizes lastTexSiz, lastTexSizTest, lastCISiz;
bool lastTexLoaded;
bool lastTexIsPalette;
DListType dListType;
std::map<uint32_t, std::vector<ZVtx>> vertices;
std::vector<ZDisplayList*> otherDLists;
ZTexture* lastTexture = nullptr;
ZTexture* lastTlut = nullptr;
std::vector<segptr_t> references;
std::vector<ZMtx> mtxList;
ZDisplayList(ZFile* nParent);
~ZDisplayList();
void ExtractWithXML(tinyxml2::XMLElement* reader, uint32_t nRawDataIndex) override;
void ExtractFromBinary(uint32_t nRawDataIndex, int32_t rawDataSize);
void ParseRawData() override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetDefaultName(const std::string& prefix) const override;
void TextureGenCheck();
static bool TextureGenCheck(int32_t texWidth, int32_t texHeight, uint32_t texAddr,
uint32_t texSeg, F3DZEXTexFormats texFmt, F3DZEXTexSizes texSiz,
bool texLoaded, bool texIsPalette, ZDisplayList* self);
static int32_t GetDListLength(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex,
DListType dListType);
size_t GetRawDataSize() const override;
DeclarationAlignment GetDeclarationAlignment() const override;
void DeclareReferences(const std::string& prefix) override;
std::string ProcessLegacy(const std::string& prefix);
std::string ProcessGfxDis(const std::string& prefix);
// Combines vertex lists from the vertices map which touch or intersect
void MergeConnectingVertexLists();
bool IsExternalResource() const override;
std::string GetExternalExtension() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
protected:
size_t numInstructions;
};

1505
ZAPDTR/ZAPD/ZFile.cpp Normal file

File diff suppressed because it is too large Load Diff

150
ZAPDTR/ZAPD/ZFile.h Normal file
View File

@@ -0,0 +1,150 @@
#pragma once
#define NO_GDI
#define WIN32_LEAN_AND_MEAN
#include <string>
#include <vector>
#include "ZSymbol.h"
#include "ZTexture.h"
#include "tinyxml2.h"
#undef FindResource
enum class ZFileMode
{
BuildTexture,
BuildOverlay,
BuildBlob,
BuildSourceFile,
BuildBackground,
Extract,
ExternalFile,
ExtractDirectory,
Invalid,
Custom = 1000, // Used for exporter file modes
};
enum class ZGame
{
OOT_RETAIL,
OOT_SW97,
MM_RETAIL
};
class ZFile
{
public:
std::map<offset_t, Declaration*> declarations;
std::vector<ZResource*> resources;
std::string defines;
int workerID;
bool isCompilable = false;
// Default to using virtual addresses
uint32_t segment = 0x80;
uint32_t baseAddress, rangeStart, rangeEnd;
bool isExternalFile = false;
// Whether to make defines for texture dimensions, and possibly more in future
bool makeDefines = false;
ZFile(const fs::path& nOutPath, const std::string& nName);
ZFile(ZFileMode nMode, tinyxml2::XMLElement* reader, const fs::path& nBasePath,
const fs::path& nOutPath, const std::string& filename, const fs::path& nXmlFilePath, int nWorkerID);
~ZFile();
std::string GetName() const;
std::string GetOutName() const;
ZFileMode GetMode() const;
const fs::path& GetXmlFilePath() const;
const std::vector<uint8_t>& GetRawData() const;
void ExtractResources();
void BuildSourceFile();
void AddResource(ZResource* res);
ZResource* FindResource(offset_t rawDataIndex);
std::vector<ZResource*> GetResourcesOfType(ZResourceType resType);
Declaration* AddDeclaration(offset_t address, DeclarationAlignment alignment, size_t size,
const std::string& varType, const std::string& varName,
const std::string& body);
Declaration* AddDeclarationArray(offset_t address, DeclarationAlignment alignment, size_t size,
const std::string& varType, const std::string& varName,
size_t arrayItemCnt, const std::string& body);
Declaration* AddDeclarationArray(offset_t address, DeclarationAlignment alignment, size_t size,
const std::string& varType, const std::string& varName,
const std::string& arrayItemCntStr, const std::string& body);
Declaration* AddDeclarationPlaceholder(offset_t address, const std::string& varName);
Declaration* AddDeclarationInclude(offset_t address, const std::string& includePath,
size_t size, const std::string& varType,
const std::string& varName);
Declaration* AddDeclarationIncludeArray(offset_t address, std::string& includePath, size_t size,
const std::string& varType, const std::string& varName,
size_t arrayItemCnt);
Declaration* AddDeclarationIncludeArray(offset_t address, std::string& includePath, size_t size,
const std::string& varType, const std::string& varName,
const std::string& defines, size_t arrayItemCnt);
bool GetDeclarationPtrName(segptr_t segAddress, const std::string& expectedType,
std::string& declName) const;
bool GetDeclarationArrayIndexedName(segptr_t segAddress, size_t elementSize,
const std::string& expectedType,
std::string& declName) const;
Declaration* GetDeclaration(offset_t address) const;
Declaration* GetDeclarationRanged(offset_t address) const;
bool HasDeclaration(offset_t address);
size_t GetDeclarationSizeFromNeighbor(uint32_t declarationAddress);
std::string GetHeaderInclude() const;
std::string GetZRoomHeaderInclude() const;
std::string GetExternalFileHeaderInclude() const;
void GeneratePlaceholderDeclarations();
void AddTextureResource(uint32_t offset, ZTexture* tex);
ZTexture* GetTextureResource(uint32_t offset) const;
void AddSymbolResource(uint32_t offset, ZSymbol* sym);
ZSymbol* GetSymbolResource(uint32_t offset) const;
ZSymbol* GetSymbolResourceRanged(uint32_t offset) const;
fs::path GetSourceOutputFolderPath() const;
bool IsOffsetInFileRange(uint32_t offset) const;
bool IsSegmentedInFilespaceRange(segptr_t segAddress) const;
static std::map<std::string, ZResourceFactoryFunc*>* GetNodeMap();
static void RegisterNode(std::string nodeName, ZResourceFactoryFunc* nodeFunc);
protected:
std::string name;
fs::path outName = "";
fs::path basePath;
fs::path outputPath;
fs::path xmlFilePath;
std::vector<uint8_t> rawData;
// Keep track of every texture of this ZFile.
// The pointers declared here are "borrowed" (somebody else is the owner),
// so ZFile shouldn't delete/free those textures.
std::map<uint32_t, ZTexture*> texturesResources;
std::map<uint32_t, ZSymbol*> symbolResources;
ZFileMode mode = ZFileMode::Invalid;
ZFile();
void ParseXML(tinyxml2::XMLElement* reader, const std::string& filename);
void DeclareResourceSubReferences();
void GenerateSourceFiles();
void GenerateSourceHeaderFiles();
bool DeclarationSanityChecks(uint32_t address, const std::string& varName);
std::string ProcessDeclarations();
void MergeNeighboringDeclarations();
void ProcessDeclarationText(Declaration* decl);
std::string ProcessExterns();
std::string ProcessTextureIntersections(const std::string& prefix);
void HandleUnaccountedData();
bool HandleUnaccountedAddress(offset_t currentAddress, offset_t lastAddr, uint32_t& lastSize);
};

420
ZAPDTR/ZAPD/ZLimb.cpp Normal file
View File

@@ -0,0 +1,420 @@
#include "ZLimb.h"
#include <cassert>
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZSkeleton.h"
REGISTER_ZFILENODE(Limb, ZLimb);
ZLimb::ZLimb(ZFile* nParent) : ZResource(nParent), segmentStruct(nParent)
{
RegisterOptionalAttribute("EnumName");
RegisterOptionalAttribute("LimbType");
RegisterOptionalAttribute("Type");
}
void ZLimb::ExtractFromBinary(uint32_t nRawDataIndex, ZLimbType nType)
{
rawDataIndex = nRawDataIndex;
type = nType;
// Don't parse raw data of external files
if (parent->GetMode() == ZFileMode::ExternalFile)
return;
ParseRawData();
}
void ZLimb::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
auto& enumNameXml = registeredAttributes.at("EnumName").value;
if (enumNameXml != "")
{
enumName = enumNameXml;
}
// Reading from a <Skeleton/>
std::string limbType = registeredAttributes.at("LimbType").value;
if (limbType == "") // Reading from a <Limb/>
limbType = registeredAttributes.at("Type").value;
if (limbType == "")
{
HANDLE_ERROR_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex,
"missing 'LimbType' attribute in <Limb>", "");
}
type = GetTypeByAttributeName(limbType);
if (type == ZLimbType::Invalid)
{
HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex,
"invalid value found for 'LimbType' attribute", "");
}
}
void ZLimb::ParseRawData()
{
ZResource::ParseRawData();
const auto& rawData = parent->GetRawData();
if (type == ZLimbType::Curve)
{
childIndex = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0);
siblingIndex = BitConverter::ToUInt8BE(rawData, rawDataIndex + 1);
dListPtr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4);
dList2Ptr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8);
return;
}
if (type == ZLimbType::Legacy)
{
dListPtr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x00);
legTransX = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x04);
legTransY = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x08);
legTransZ = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x0C);
rotX = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x10);
rotY = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x12);
rotZ = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x14);
childPtr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x18);
siblingPtr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x1C);
return;
}
transX = BitConverter::ToInt16BE(rawData, rawDataIndex + 0);
transY = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
transZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 4);
childIndex = rawData.at(rawDataIndex + 6);
siblingIndex = rawData.at(rawDataIndex + 7);
switch (type)
{
case ZLimbType::LOD:
dList2Ptr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 12);
[[fallthrough]];
case ZLimbType::Standard:
dListPtr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8);
break;
case ZLimbType::Skin:
skinSegmentType =
static_cast<ZLimbSkinType>(BitConverter::ToInt32BE(rawData, rawDataIndex + 8));
skinSegment = BitConverter::ToUInt32BE(rawData, rawDataIndex + 12);
if (skinSegmentType == ZLimbSkinType::SkinType_Animated)
{
if (skinSegment != 0 && GETSEGNUM(skinSegment) == parent->segment)
{
uint32_t skinSegmentOffset = Seg2Filespace(skinSegment, parent->baseAddress);
segmentStruct.ExtractFromFile(skinSegmentOffset);
}
}
break;
case ZLimbType::Curve:
case ZLimbType::Legacy:
break;
case ZLimbType::Invalid:
assert(!"whoops");
break;
}
}
void ZLimb::DeclareReferences(const std::string& prefix)
{
std::string varPrefix = name;
if (varPrefix == "")
varPrefix = prefix;
ZResource::DeclareReferences(varPrefix);
std::string suffix;
switch (type)
{
case ZLimbType::Legacy:
if (childPtr != 0 && GETSEGNUM(childPtr) == parent->segment)
{
uint32_t childOffset = Seg2Filespace(childPtr, parent->baseAddress);
if (!parent->HasDeclaration(childOffset))
{
ZLimb* child = new ZLimb(parent);
child->ExtractFromBinary(childOffset, ZLimbType::Legacy);
child->DeclareVar(varPrefix, "");
child->DeclareReferences(varPrefix);
parent->AddResource(child);
}
}
if (siblingPtr != 0 && GETSEGNUM(siblingPtr) == parent->segment)
{
uint32_t siblingdOffset = Seg2Filespace(siblingPtr, parent->baseAddress);
if (!parent->HasDeclaration(siblingdOffset))
{
ZLimb* sibling = new ZLimb(parent);
sibling->ExtractFromBinary(siblingdOffset, ZLimbType::Legacy);
sibling->DeclareVar(varPrefix, "");
sibling->DeclareReferences(varPrefix);
parent->AddResource(sibling);
}
}
break;
case ZLimbType::Curve:
case ZLimbType::LOD:
suffix = "Far";
if (type == ZLimbType::Curve)
suffix = "Curve2";
DeclareDList(dList2Ptr, varPrefix, suffix);
[[fallthrough]];
case ZLimbType::Standard:
suffix = "";
if (type == ZLimbType::Curve)
suffix = "Curve";
DeclareDList(dListPtr, varPrefix, suffix);
break;
case ZLimbType::Skin:
switch (skinSegmentType)
{
case ZLimbSkinType::SkinType_Animated:
if (skinSegment != 0 && GETSEGNUM(skinSegment) == parent->segment)
{
segmentStruct.DeclareReferences(varPrefix);
segmentStruct.GetSourceOutputCode(varPrefix);
}
break;
case ZLimbSkinType::SkinType_Normal:
DeclareDList(skinSegment, varPrefix, "");
break;
default:
break;
}
break;
case ZLimbType::Invalid:
break;
}
}
size_t ZLimb::GetRawDataSize() const
{
switch (type)
{
case ZLimbType::Standard:
case ZLimbType::Curve:
return 0x0C;
case ZLimbType::LOD:
case ZLimbType::Skin:
return 0x10;
case ZLimbType::Legacy:
return 0x20;
case ZLimbType::Invalid:
break;
}
return 0x0C;
}
std::string ZLimb::GetBodySourceCode() const
{
if (Globals::Instance->otrMode)
return "";
std::string dListStr;
std::string dListStr2;
Globals::Instance->GetSegmentedArrayIndexedName(dListPtr, 8, parent, "Gfx", dListStr,
parent->workerID);
Globals::Instance->GetSegmentedArrayIndexedName(dList2Ptr, 8, parent, "Gfx", dListStr2,
parent->workerID);
std::string entryStr = "\n\t";
if (type == ZLimbType::Legacy)
{
std::string childName;
std::string siblingName;
Globals::Instance->GetSegmentedPtrName(childPtr, parent, "LegacyLimb", childName,
parent->workerID);
Globals::Instance->GetSegmentedPtrName(siblingPtr, parent, "LegacyLimb", siblingName,
parent->workerID);
entryStr += StringHelper::Sprintf("%s,\n", dListStr.c_str());
entryStr +=
StringHelper::Sprintf("\t{ %ff, %ff, %ff },\n", legTransX, legTransY, legTransZ);
entryStr += StringHelper::Sprintf("\t{ 0x%04X, 0x%04X, 0x%04X },\n", rotX, rotY, rotZ);
entryStr += StringHelper::Sprintf("\t%s,\n", childName.c_str());
entryStr += StringHelper::Sprintf("\t%s\n", siblingName.c_str());
}
else
{
std::string childStr;
std::string siblingStr;
if (limbsTable != nullptr)
{
childStr = limbsTable->GetLimbEnumName(childIndex);
siblingStr = limbsTable->GetLimbEnumName(siblingIndex);
}
else
{
childStr = StringHelper::Sprintf("0x%02X", childIndex);
siblingStr = StringHelper::Sprintf("0x%02X", siblingIndex);
}
if (type != ZLimbType::Curve)
{
entryStr += StringHelper::Sprintf("{ %i, %i, %i }, ", transX, transY, transZ);
}
entryStr += StringHelper::Sprintf("%s, %s,\n", childStr.c_str(), siblingStr.c_str());
switch (type)
{
case ZLimbType::Standard:
entryStr += StringHelper::Sprintf("\t%s\n", dListStr.c_str());
break;
case ZLimbType::LOD:
case ZLimbType::Curve:
entryStr +=
StringHelper::Sprintf("\t{ %s, %s }\n", dListStr.c_str(), dListStr2.c_str());
break;
case ZLimbType::Skin:
{
std::string skinSegmentStr;
Globals::Instance->GetSegmentedPtrName(skinSegment, parent, "", skinSegmentStr,
parent->workerID);
entryStr +=
StringHelper::Sprintf("\t0x%02X, %s\n", skinSegmentType, skinSegmentStr.c_str());
}
break;
case ZLimbType::Legacy:
break;
case ZLimbType::Invalid:
break;
}
}
return entryStr;
}
std::string ZLimb::GetDefaultName(const std::string& prefix) const
{
return StringHelper::Sprintf("%sLimb_%06X", prefix.c_str(), rawDataIndex);
}
std::string ZLimb::GetSourceTypeName() const
{
return GetSourceTypeName(type);
}
ZResourceType ZLimb::GetResourceType() const
{
return ZResourceType::Limb;
}
ZLimbType ZLimb::GetLimbType()
{
return type;
}
void ZLimb::SetLimbType(ZLimbType value)
{
type = value;
}
const char* ZLimb::GetSourceTypeName(ZLimbType limbType)
{
switch (limbType)
{
case ZLimbType::Standard:
return "StandardLimb";
case ZLimbType::LOD:
return "LodLimb";
case ZLimbType::Skin:
return "SkinLimb";
case ZLimbType::Curve:
return "SkelCurveLimb";
case ZLimbType::Legacy:
return "LegacyLimb";
default:
return "StandardLimb";
}
}
ZLimbType ZLimb::GetTypeByAttributeName(const std::string& attrName)
{
if (attrName == "Standard")
{
return ZLimbType::Standard;
}
if (attrName == "LOD")
{
return ZLimbType::LOD;
}
if (attrName == "Skin")
{
return ZLimbType::Skin;
}
if (attrName == "Curve")
{
return ZLimbType::Curve;
}
if (attrName == "Legacy")
{
return ZLimbType::Legacy;
}
return ZLimbType::Invalid;
}
void ZLimb::SetLimbIndex(uint8_t nLimbIndex)
{
limbIndex = nLimbIndex;
}
void ZLimb::DeclareDList(segptr_t dListSegmentedPtr, const std::string& prefix,
const std::string& limbSuffix)
{
if (dListSegmentedPtr == 0 || GETSEGNUM(dListSegmentedPtr) != parent->segment)
return;
uint32_t dlistOffset = Seg2Filespace(dListSegmentedPtr, parent->baseAddress);
if (parent->HasDeclaration(dlistOffset))
return;
if (!parent->IsOffsetInFileRange(dlistOffset) || dlistOffset >= parent->GetRawData().size())
return;
std::string dlistName;
bool declFound = Globals::Instance->GetSegmentedArrayIndexedName(dListSegmentedPtr, 8, parent,
"Gfx", dlistName, false, parent->workerID);
if (declFound)
return;
int32_t dlistLength = ZDisplayList::GetDListLength(
parent->GetRawData(), dlistOffset,
Globals::Instance->game == ZGame::OOT_SW97 ? DListType::F3DEX : DListType::F3DZEX);
ZDisplayList* dlist = new ZDisplayList(parent);
dlist->ExtractFromBinary(dlistOffset, dlistLength);
std::string dListStr =
StringHelper::Sprintf("%s%sDL_%06X", prefix.c_str(), limbSuffix.c_str(), dlistOffset);
dlist->SetName(dListStr);
dlist->DeclareVar(prefix, "");
parent->AddResource(dlist);
}

74
ZAPDTR/ZAPD/ZLimb.h Normal file
View File

@@ -0,0 +1,74 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "OtherStructs/SkinLimbStructs.h"
#include "ZDisplayList.h"
#include "ZFile.h"
enum class ZLimbType
{
Invalid,
Standard,
LOD,
Skin,
Curve,
Legacy,
};
class ZLimbTable;
class ZLimb : public ZResource
{
public:
std::string enumName;
ZLimbTable* limbsTable = nullptr; // borrowed pointer, do not delete!
ZLimbType type = ZLimbType::Standard;
ZLimbSkinType skinSegmentType = ZLimbSkinType::SkinType_Null; // Skin only
segptr_t skinSegment = 0; // Skin only
SkinAnimatedLimbData segmentStruct; // Skin only
// Legacy only
float legTransX = 0, legTransY = 0, legTransZ = 0; // Vec3f
uint16_t rotX = 0, rotY = 0, rotZ = 0; // Vec3s
segptr_t childPtr = 0; // LegacyLimb*
segptr_t siblingPtr = 0; // LegacyLimb*
segptr_t dListPtr = 0;
segptr_t dList2Ptr = 0; // LOD and Curve Only
int16_t transX = 0, transY = 0, transZ = 0;
uint8_t childIndex = 0, siblingIndex = 0;
uint8_t limbIndex = 0;
ZLimb(ZFile* nParent);
void ExtractFromBinary(uint32_t nRawDataIndex, ZLimbType nType);
void ParseXML(tinyxml2::XMLElement* reader) override;
void ParseRawData() override;
void DeclareReferences(const std::string& prefix) override;
std::string GetBodySourceCode() const override;
std::string GetDefaultName(const std::string& prefix) const override;
size_t GetRawDataSize() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
ZLimbType GetLimbType();
void SetLimbType(ZLimbType value);
static const char* GetSourceTypeName(ZLimbType limbType);
static ZLimbType GetTypeByAttributeName(const std::string& attrName);
void SetLimbIndex(uint8_t nLimbIndex);
protected:
void DeclareDList(segptr_t dListSegmentedPtr, const std::string& prefix,
const std::string& limbSuffix);
};

59
ZAPDTR/ZAPD/ZMtx.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include "ZMtx.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Mtx, ZMtx);
ZMtx::ZMtx(ZFile* nParent) : ZResource(nParent)
{
genOTRDef = true;
}
void ZMtx::ParseRawData()
{
ZResource::ParseRawData();
const auto& rawData = parent->GetRawData();
for (size_t i = 0; i < 4; ++i)
for (size_t j = 0; j < 4; ++j)
mtx[i][j] = BitConverter::ToInt32BE(rawData, rawDataIndex + (i * 4 + j) * 4);
}
size_t ZMtx::GetRawDataSize() const
{
return 64;
}
std::string ZMtx::GetBodySourceCode() const
{
std::string bodyStr = "\n";
for (const auto& row : mtx)
{
bodyStr += " ";
for (int32_t val : row)
bodyStr += StringHelper::Sprintf("%-11i, ", val);
bodyStr += "\n";
}
return bodyStr;
}
std::string ZMtx::GetSourceTypeName() const
{
return "Mtx";
}
ZResourceType ZMtx::GetResourceType() const
{
return ZResourceType::Mtx;
}
DeclarationAlignment ZMtx::GetDeclarationAlignment() const
{
return DeclarationAlignment::Align8;
}

24
ZAPDTR/ZAPD/ZMtx.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include <array>
#include <cstdint>
#include "ZResource.h"
class ZMtx : public ZResource
{
public:
ZMtx(ZFile* nParent);
void ParseRawData() override;
std::string GetBodySourceCode() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
DeclarationAlignment GetDeclarationAlignment() const override;
public:
std::array<std::array<int32_t, 4>, 4> mtx;
};

218
ZAPDTR/ZAPD/ZPath.cpp Normal file
View File

@@ -0,0 +1,218 @@
#include "ZPath.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Path, ZPath); // Old name that is being kept for backwards compatability
REGISTER_ZFILENODE(PathList, ZPath); // New name that may be used in future XMLs
ZPath::ZPath(ZFile* nParent) : ZResource(nParent)
{
numPaths = 1;
RegisterOptionalAttribute("NumPaths", "1");
}
void ZPath::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
numPaths = StringHelper::StrToL(registeredAttributes.at("NumPaths").value);
if (numPaths < 1)
{
HANDLE_ERROR_RESOURCE(
WarningType::InvalidAttributeValue, parent, this, rawDataIndex,
StringHelper::Sprintf("invalid value '%d' found for 'NumPaths' attribute", numPaths),
"Should be at least '1'");
}
}
void ZPath::ParseRawData()
{
ZResource::ParseRawData();
uint32_t currentPtr = rawDataIndex;
pathways.reserve(numPaths);
for (size_t pathIndex = 0; pathIndex < numPaths; pathIndex++)
{
PathwayEntry path(parent);
path.ExtractFromFile(currentPtr);
if (path.GetListAddress() == 0)
break;
currentPtr += path.GetRawDataSize();
pathways.push_back(path);
}
}
void ZPath::DeclareReferences(const std::string& prefix)
{
ZResource::DeclareReferences(prefix);
for (auto& entry : pathways)
entry.DeclareReferences(prefix);
}
Declaration* ZPath::DeclareVar(const std::string& prefix, const std::string& bodyStr)
{
std::string auxName = name;
if (name == "")
auxName = GetDefaultName(prefix);
Declaration* decl =
parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(),
GetSourceTypeName(), name, pathways.size(), bodyStr);
decl->staticConf = staticConf;
return decl;
}
std::string ZPath::GetBodySourceCode() const
{
std::string declaration;
size_t index = 0;
for (const auto& entry : pathways)
{
declaration += StringHelper::Sprintf("\t{ %s },", entry.GetBodySourceCode().c_str());
if (index < pathways.size() - 1)
declaration += "\n";
index++;
}
return declaration;
}
std::string ZPath::GetSourceTypeName() const
{
return "Path";
}
ZResourceType ZPath::GetResourceType() const
{
return ZResourceType::Path;
}
size_t ZPath::GetRawDataSize() const
{
return pathways.size() * pathways.at(0).GetRawDataSize();
}
void ZPath::SetNumPaths(uint32_t nNumPaths)
{
numPaths = nNumPaths;
}
/* PathwayEntry */
PathwayEntry::PathwayEntry(ZFile* nParent) : ZResource(nParent)
{
}
void PathwayEntry::ParseRawData()
{
ZResource::ParseRawData();
auto parentRawData = parent->GetRawData();
numPoints = parentRawData.at(rawDataIndex + 0);
unk1 = parentRawData.at(rawDataIndex + 1);
unk2 = BitConverter::ToInt16BE(parentRawData, rawDataIndex + 2);
listSegmentAddress = BitConverter::ToInt32BE(parentRawData, rawDataIndex + 4);
uint32_t currentPtr = GETSEGOFFSET(listSegmentAddress);
points.reserve(numPoints);
for (int32_t i = 0; i < numPoints; i++)
{
ZVector vec(parent);
vec.ExtractFromBinary(currentPtr, ZScalarType::ZSCALAR_S16, 3);
currentPtr += vec.GetRawDataSize();
points.push_back(vec);
}
}
void PathwayEntry::DeclareReferences(const std::string& prefix)
{
ZResource::DeclareReferences(prefix);
if (points.empty())
return;
std::string pointsName;
bool addressFound = Globals::Instance->GetSegmentedPtrName(listSegmentAddress, parent, "Vec3s",
pointsName, false, parent->workerID);
if (addressFound)
return;
std::string declaration = "";
size_t index = 0;
for (const auto& point : points)
{
declaration += StringHelper::Sprintf("\t{ %s },", point.GetBodySourceCode().c_str());
if (index < points.size() - 1)
declaration += "\n";
index++;
}
uint32_t pointsOffset = Seg2Filespace(listSegmentAddress, parent->baseAddress);
Declaration* decl = parent->GetDeclaration(pointsOffset);
if (decl == nullptr)
{
pointsName = StringHelper::Sprintf("%sPathwayList_%06X", prefix.c_str(), pointsOffset);
parent->AddDeclarationArray(pointsOffset, points.at(0).GetDeclarationAlignment(),
points.size() * 6, points.at(0).GetSourceTypeName(), pointsName,
points.size(), declaration);
}
else
decl->declBody = declaration;
}
std::string PathwayEntry::GetBodySourceCode() const
{
std::string declaration;
std::string listName;
Globals::Instance->GetSegmentedPtrName(listSegmentAddress, parent, "Vec3s", listName, parent->workerID);
if (Globals::Instance->game == ZGame::MM_RETAIL)
declaration +=
StringHelper::Sprintf("%i, %i, %i, %s", numPoints, unk1, unk2, listName.c_str());
else
{
if (numPoints > 0)
declaration +=
StringHelper::Sprintf("ARRAY_COUNT(%s), %s", listName.c_str(), listName.c_str());
else
declaration += StringHelper::Sprintf("%i, %s", numPoints, listName.c_str());
}
return declaration;
}
std::string PathwayEntry::GetSourceTypeName() const
{
return "Path";
}
ZResourceType PathwayEntry::GetResourceType() const
{
return ZResourceType::Path;
}
size_t PathwayEntry::GetRawDataSize() const
{
return 0x08;
}
segptr_t PathwayEntry::GetListAddress() const
{
return listSegmentAddress;
}

51
ZAPDTR/ZAPD/ZPath.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include "ZResource.h"
#include "ZVector.h"
class PathwayEntry : public ZResource
{
public:
PathwayEntry(ZFile* nParent);
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;
segptr_t GetListAddress() const;
public:
int32_t numPoints;
int8_t unk1; // (MM Only)
int16_t unk2; // (MM Only)
segptr_t listSegmentAddress;
std::vector<ZVector> points;
};
class ZPath : public ZResource
{
public:
ZPath(ZFile* nParent);
void ParseXML(tinyxml2::XMLElement* reader) override;
void ParseRawData() override;
void DeclareReferences(const std::string& prefix) override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
void SetNumPaths(uint32_t nNumPaths);
public:
uint32_t numPaths;
std::vector<PathwayEntry> pathways;
};

View File

@@ -0,0 +1,108 @@
#include "ZPlayerAnimationData.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "ZFile.h"
#include <Globals.h>
REGISTER_ZFILENODE(PlayerAnimationData, ZPlayerAnimationData);
ZPlayerAnimationData::ZPlayerAnimationData(ZFile* nParent) : ZResource(nParent)
{
RegisterRequiredAttribute("FrameCount");
}
void ZPlayerAnimationData::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
std::string& frameCountXml = registeredAttributes.at("FrameCount").value;
frameCount = StringHelper::StrToL(frameCountXml);
}
void ZPlayerAnimationData::ParseRawData()
{
ZResource::ParseRawData();
const auto& rawData = parent->GetRawData();
size_t totalSize = GetRawDataSize();
// Divided by 2 because each value is an s16
limbRotData.reserve(totalSize * frameCount / 2);
for (size_t i = 0; i < totalSize; i += 2)
{
limbRotData.push_back(BitConverter::ToInt16BE(rawData, rawDataIndex + i));
}
}
Declaration* ZPlayerAnimationData::DeclareVar(const std::string& prefix, const std::string& bodyStr)
{
std::string auxName = name;
if (auxName == "")
auxName = GetDefaultName(prefix);
Declaration* decl =
parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(),
GetSourceTypeName(), name, limbRotData.size(), bodyStr);
decl->staticConf = staticConf;
return decl;
}
std::string ZPlayerAnimationData::GetBodySourceCode() const
{
std::string declaration = "";
if (Globals::Instance->otrMode)
return "";
size_t index = 0;
for (const auto entry : limbRotData)
{
if (index % 8 == 0)
{
declaration += "\t";
}
if (entry < 0)
{
declaration += StringHelper::Sprintf("-0x%04X, ", -entry);
}
else
{
declaration += StringHelper::Sprintf("0x%04X, ", entry);
}
if ((index + 1) % 8 == 0)
{
declaration += "\n";
}
index++;
}
return declaration;
}
std::string ZPlayerAnimationData::GetDefaultName(const std::string& prefix) const
{
return StringHelper::Sprintf("%sPlayerAnimationData_%06X", prefix.c_str(), rawDataIndex);
}
std::string ZPlayerAnimationData::GetSourceTypeName() const
{
return "s16";
}
ZResourceType ZPlayerAnimationData::GetResourceType() const
{
return ZResourceType::PlayerAnimationData;
}
size_t ZPlayerAnimationData::GetRawDataSize() const
{
// (sizeof(Vec3s) * limbCount + 2) * frameCount
return (6 * 22 + 2) * frameCount;
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#include <vector>
#include "ZResource.h"
class ZPlayerAnimationData : public ZResource
{
public:
int16_t frameCount = 0;
std::vector<int16_t> limbRotData;
ZPlayerAnimationData(ZFile* nParent);
void ParseXML(tinyxml2::XMLElement* reader) override;
void ParseRawData() override;
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
std::string GetDefaultName(const std::string& prefix) const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
};

57
ZAPDTR/ZAPD/ZPointer.cpp Normal file
View File

@@ -0,0 +1,57 @@
#include "ZPointer.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Pointer, ZPointer);
ZPointer::ZPointer(ZFile* nParent) : ZResource(nParent)
{
RegisterRequiredAttribute("Type");
}
void ZPointer::ParseXML(tinyxml2::XMLElement* reader)
{
ZResource::ParseXML(reader);
type = registeredAttributes.at("Type").value;
}
void ZPointer::ParseRawData()
{
auto& rawData = parent->GetRawData();
ptr = BitConverter::ToUInt32BE(rawData, rawDataIndex);
}
std::string ZPointer::GetBodySourceCode() const
{
std::string ptrName;
Globals::Instance->GetSegmentedPtrName(ptr, parent, "", ptrName, parent->workerID, false);
return ptrName;
}
bool ZPointer::DoesSupportArray() const
{
return true;
}
std::string ZPointer::GetSourceTypeName() const
{
return type + "*";
}
ZResourceType ZPointer::GetResourceType() const
{
return ZResourceType::Pointer;
}
size_t ZPointer::GetRawDataSize() const
{
return 0x04;
}

22
ZAPDTR/ZAPD/ZPointer.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "ZResource.h"
class ZPointer : public ZResource
{
public:
segptr_t ptr = SEGMENTED_NULL;
std::string type;
ZPointer(ZFile* nParent);
void ParseXML(tinyxml2::XMLElement* reader) override;
void ParseRawData() override;
std::string GetBodySourceCode() const override;
bool DoesSupportArray() const override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
};

450
ZAPDTR/ZAPD/ZResource.cpp Normal file
View File

@@ -0,0 +1,450 @@
#include "ZResource.h"
#include <cassert>
#include <regex>
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "ZFile.h"
#include <Globals.h>
#include <set>
#include <ZDisplayList.h>
#include <ZArray.h>
ZResource::ZResource(ZFile* nParent)
{
// assert(nParent != nullptr);
parent = nParent;
name = "";
outName = "";
sourceOutput = "";
rawDataIndex = 0;
outputDeclaration = true;
hash = 0;
RegisterRequiredAttribute("Name");
RegisterOptionalAttribute("OutName");
RegisterOptionalAttribute("Offset");
RegisterOptionalAttribute("Custom");
RegisterOptionalAttribute("Static", "Global");
}
void ZResource::ExtractWithXML(tinyxml2::XMLElement* reader, offset_t nRawDataIndex)
{
rawDataIndex = nRawDataIndex;
declaredInXml = true;
if (reader != nullptr)
ParseXML(reader);
// Don't parse raw data of external files
if (parent->GetMode() != ZFileMode::ExternalFile)
{
ParseRawData();
CalcHash();
}
if (!isInner)
{
Declaration* decl = DeclareVar(parent->GetName(), "");
if (decl != nullptr)
{
decl->declaredInXml = true;
decl->staticConf = staticConf;
}
}
}
void ZResource::ExtractFromFile(offset_t nRawDataIndex)
{
rawDataIndex = nRawDataIndex;
// Don't parse raw data of external files
if (parent->GetMode() == ZFileMode::ExternalFile)
return;
ParseRawData();
CalcHash();
}
void ZResource::ParseXML(tinyxml2::XMLElement* reader)
{
if (reader != nullptr)
{
// If it is an inner node, then 'Name' isn't required
if (isInner)
{
registeredAttributes.at("Name").isRequired = false;
}
auto attrs = reader->FirstAttribute();
while (attrs != nullptr)
{
std::string attrName = attrs->Name();
bool attrDeclared = false;
if (registeredAttributes.find(attrName) != registeredAttributes.end())
{
registeredAttributes[attrName].value = attrs->Value();
registeredAttributes[attrName].wasSet = true;
attrDeclared = true;
}
if (!attrDeclared)
{
HANDLE_WARNING_RESOURCE(
WarningType::UnknownAttribute, parent, this, rawDataIndex,
StringHelper::Sprintf("unexpected '%s' attribute in resource <%s>",
attrName.c_str(), reader->Name()),
"");
}
attrs = attrs->Next();
}
if (!Globals::Instance->otrMode)
{
if (!canHaveInner && !reader->NoChildren())
{
std::string errorHeader = StringHelper::Sprintf(
"resource '%s' with inner element/child detected", reader->Name());
HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, "");
}
}
for (const auto& attr : registeredAttributes)
{
if (attr.second.isRequired && attr.second.value == "")
{
std::string headerMsg =
StringHelper::Sprintf("missing required attribute '%s' in resource <%s>",
attr.first.c_str(), reader->Name());
HANDLE_ERROR_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex,
headerMsg, "");
}
}
name = registeredAttributes.at("Name").value;
// Disable this check for OTR file generation for now since it takes up a considerable amount of CPU time
if (!Globals::Instance->otrMode)
{
static std::regex r("[a-zA-Z_]+[a-zA-Z0-9_]*",
std::regex::icase | std::regex::optimize);
if (!isInner || (isInner && name != ""))
{
if (!std::regex_match(name, r))
{
HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this,
rawDataIndex, "invalid value found for 'Name' attribute",
"");
}
}
}
outName = registeredAttributes.at("OutName").value;
if (outName == "")
outName = name;
isCustomAsset = registeredAttributes["Custom"].wasSet;
std::string& staticXml = registeredAttributes["Static"].value;
if (staticXml == "Global")
{
staticConf = StaticConfig::Global;
}
else if (staticXml == "On")
{
staticConf = StaticConfig::On;
}
else if (staticXml == "Off")
{
staticConf = StaticConfig::Off;
}
else
{
HANDLE_ERROR_RESOURCE(
WarningType::InvalidAttributeValue, parent, this, rawDataIndex,
StringHelper::Sprintf("invalid value '%s' for 'Static' attribute", staticConf), "");
}
declaredInXml = true;
}
}
void ZResource::ParseRawData()
{
}
void ZResource::DeclareReferences([[maybe_unused]] const std::string& prefix)
{
}
void ZResource::ParseRawDataLate()
{
}
void ZResource::DeclareReferencesLate([[maybe_unused]] const std::string& prefix)
{
}
Declaration* ZResource::DeclareVar(const std::string& prefix, const std::string& bodyStr)
{
std::string auxName = name;
if (name == "")
auxName = GetDefaultName(prefix);
Declaration* decl =
parent->AddDeclaration(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(),
GetSourceTypeName(), auxName, bodyStr);
decl->staticConf = staticConf;
return decl;
}
void ZResource::Save([[maybe_unused]] const fs::path& outFolder)
{
}
const std::string& ZResource::GetName() const
{
return name;
}
const std::string& ZResource::GetOutName() const
{
return outName;
}
void ZResource::SetOutName(const std::string& nName)
{
outName = nName;
}
void ZResource::SetName(const std::string& nName)
{
name = nName;
}
bool ZResource::IsExternalResource() const
{
return false;
}
bool ZResource::DoesSupportArray() const
{
return false;
}
std::string ZResource::GetExternalExtension() const
{
return "";
}
DeclarationAlignment ZResource::GetDeclarationAlignment() const
{
return DeclarationAlignment::Align4;
}
bool ZResource::WasDeclaredInXml() const
{
return declaredInXml;
}
StaticConfig ZResource::GetStaticConf() const
{
return staticConf;
}
offset_t ZResource::GetRawDataIndex() const
{
return rawDataIndex;
}
void ZResource::SetRawDataIndex(offset_t nRawDataIndex)
{
rawDataIndex = nRawDataIndex;
}
std::string ZResource::GetBodySourceCode() const
{
return "ERROR";
}
std::string ZResource::GetDefaultName(const std::string& prefix) const
{
return StringHelper::Sprintf("%s%s_%06X", prefix.c_str(), GetSourceTypeName().c_str(),
rawDataIndex);
}
void ZResource::GetSourceOutputCode([[maybe_unused]] const std::string& prefix)
{
std::string bodyStr = GetBodySourceCode();
if (bodyStr != "ERROR")
{
Declaration* decl = parent->GetDeclaration(rawDataIndex);
if (decl == nullptr || decl->isPlaceholder)
decl = DeclareVar(prefix, bodyStr);
else
decl->declBody = bodyStr;
// OTRTODO: This is a hack and we need something more elegant in the future...
if (GetResourceType() == ZResourceType::Array)
{
ZArray* arr = (ZArray*)this;
if (arr->resList[0]->GetResourceType() == ZResourceType::Vertex)
{
for (int i = 0; i < arr->resList.size(); i++)
{
ZVtx* vtx = (ZVtx*)arr->resList[i];
decl->vertexHack.push_back(vtx);
}
}
}
if (decl != nullptr)
decl->staticConf = staticConf;
}
}
std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix, std::set<std::string> *nameSet)
{
if (Globals::Instance->otrMode && genOTRDef)
{
std::string str = "";
std::string nameStr = StringHelper::Strip(StringHelper::Strip(name, "\n"), "\r");
std::string outName = parent->GetOutName();
std::string prefix = "";
if (GetResourceType() == ZResourceType::DisplayList || GetResourceType() == ZResourceType::Texture)
{
//ZDisplayList* dList = (ZDisplayList*)this;
if (StringHelper::Contains(outName, "_room_"))
{
outName = StringHelper::Split(outName, "_room")[0] + "_scene";
}
}
std::string xmlPath = StringHelper::Replace(parent->GetXmlFilePath().string(), "\\", "/");
if (StringHelper::Contains(outName, "_room_") ||
StringHelper::Contains(outName, "_scene") ||
(StringHelper::Contains(parent->GetXmlFilePath().string(), "/scenes/") ||
StringHelper::Contains(parent->GetXmlFilePath().string(), "\\scenes\\"))) {
prefix = "scenes/shared";
// Regex for xml paths that are dungeons with unique MQ variants (only the main dungeon, not boss rooms)
std::regex dungeonsWithMQ(R"(((ydan)|(ddan)|(bdan)|(Bmori1)|(HIDAN)|(MIZUsin)|(jyasinzou)|(HAKAdan)|(HAKAdanCH)|(ice_doukutu)|(men)|(ganontika))\.xml)");
if (StringHelper::Contains(xmlPath, "dungeons/") && std::regex_search(xmlPath, dungeonsWithMQ)) {
prefix = "scenes/nonmq";
}
}
else if (StringHelper::Contains(xmlPath, "objects/"))
prefix = "objects";
else if (StringHelper::Contains(xmlPath, "textures/"))
prefix = "textures";
else if (StringHelper::Contains(xmlPath, "overlays/"))
prefix = "overlays";
else if (StringHelper::Contains(xmlPath, "misc/"))
prefix = "misc";
else if (StringHelper::Contains(xmlPath, "code/"))
prefix = "code";
else if (StringHelper::Contains(xmlPath, "text/"))
prefix = "text";
if (prefix != "") {
str += StringHelper::Sprintf("#define d%s \"__OTR__%s/%s/%s\"", name.c_str(), prefix.c_str(), outName.c_str(), nameStr.c_str());
}
else
str += StringHelper::Sprintf("#define d%s \"__OTR__%s/%s\"", name.c_str(), outName.c_str(), nameStr.c_str());
if (nameSet && nameSet->find(name) == nameSet->end()) {
str += StringHelper::Sprintf("\n");
str += StringHelper::Sprintf(R"(static const ALIGN_ASSET(2) char %s[] = d%s;)", name.c_str(), name.c_str());
if (nameSet) {
nameSet->insert(name);
}
}
if (name == "gTitleZeldaShieldLogoMQTex")
{
std::string addName = "gTitleZeldaShieldLogoTex";
nameStr = StringHelper::Strip(StringHelper::Strip(addName, "\n"), "\r");
str += StringHelper::Sprintf("\n\n#define d%s \"__OTR__%s/%s/%s\"", addName.c_str(), prefix.c_str(), outName.c_str(), nameStr.c_str());
if (nameSet && nameSet->find(addName) == nameSet->end())
{
str += StringHelper::Sprintf("\n");
str += StringHelper::Sprintf(R"(static const ALIGN_ASSET(2) char %s[] = d%s;)", addName.c_str(), addName.c_str());
if (nameSet)
{
nameSet->insert(addName);
}
}
}
return str;
}
else
return "";
}
ZResourceType ZResource::GetResourceType() const
{
return ZResourceType::Error;
}
void ZResource::CalcHash()
{
hash = 0;
}
void ZResource::SetInnerNode(bool inner)
{
isInner = inner;
}
void ZResource::RegisterRequiredAttribute(const std::string& attr)
{
ResourceAttribute resAtrr;
resAtrr.key = attr;
resAtrr.isRequired = true;
registeredAttributes[attr] = resAtrr;
}
void ZResource::RegisterOptionalAttribute(const std::string& attr, const std::string& defaultValue)
{
ResourceAttribute resAtrr;
resAtrr.key = attr;
resAtrr.value = defaultValue;
registeredAttributes[attr] = resAtrr;
}
offset_t Seg2Filespace(segptr_t segmentedAddress, uint32_t parentBaseAddress)
{
offset_t currentPtr = GETSEGOFFSET(segmentedAddress);
if (GETSEGNUM(segmentedAddress) == 0x80) // Is defined in code?
{
uint32_t parentBaseOffset = GETSEGOFFSET(parentBaseAddress);
if (parentBaseOffset > currentPtr)
{
HANDLE_ERROR(WarningType::Always,
StringHelper::Sprintf(
"resource address 0x%08X is smaller than 'BaseAddress' 0x%08X",
segmentedAddress, parentBaseAddress),
"Maybe your 'BaseAddress' is wrong?");
}
currentPtr -= parentBaseOffset;
}
return currentPtr;
}

268
ZAPDTR/ZAPD/ZResource.h Normal file
View File

@@ -0,0 +1,268 @@
#pragma once
#include <cstdint>
#include <map>
#include <set>
#include <stdexcept>
#include <string>
#include <vector>
#include "Declaration.h"
#include <Utils/BinaryWriter.h>
#include <Utils/Directory.h>
#include "tinyxml2.h"
#define SEGMENT_SCENE 2
#define SEGMENT_ROOM 3
#define SEGMENT_KEEP 4
#define SEGMENT_FIELDDANGEON_KEEP 5
#define SEGMENT_OBJECT 6
#define SEGMENT_LINKANIMETION 7
#define GETSEGOFFSET(x) (x & 0x00FFFFFF)
#define GETSEGNUM(x) ((x >> 24) & 0xFF)
class ZFile;
enum class ZResourceType
{
Error,
Animation,
Array,
AltHeader,
Background,
Blob,
CollisionHeader,
Cutscene,
DisplayList,
Limb,
LimbTable,
Mtx,
Path,
PlayerAnimationData,
Room,
RoomCommand,
Scalar,
Scene,
Skeleton,
String,
Symbol,
Texture,
TextureAnimation,
TextureAnimationParams,
Vector,
Vertex,
Audio,
ActorList,
CollisionPoly,
Pointer,
SurfaceType,
Waterbox,
Text,
TextMM,
KeyFrameFlexLimb,
KeyFrameStandardLimb,
KeyFrameSkel,
KeyFrameAnimation,
};
class ResourceAttribute
{
public:
std::string key;
std::string value;
bool isRequired = false;
bool wasSet = false;
};
class ZResource
{
public:
ZFile* parent;
bool outputDeclaration = true;
uint32_t hash = 0;
bool genOTRDef = false;
/**
* Constructor.
* Child classes should not declare any other constructor besides this one
*/
ZResource(ZFile* nParent);
virtual ~ZResource() = default;
/// <summary>
/// Extracts/Parsees data from binary file using an XML to provide the needed metadata.
/// </summary>
/// <param name="reader">XML Node we wish to parse from.</param>
/// <param name="nRawDataIndex">The offset within the binary file we are going to parse from as
/// indicated by the "Offset" parameter in the XML.</param>
virtual void ExtractWithXML(tinyxml2::XMLElement* reader, offset_t nRawDataIndex);
/// <summary>
/// Extracts/Parses the needed data straight from a binary without the use of an XML.
/// </summary>
/// <param name="nRawDataIndex">The offset within the binary file we wish to parse from.</param>
virtual void ExtractFromFile(offset_t nRawDataIndex);
// Misc
/**
* Parses additional attributes of the XML node.
* Extra attritbutes have to be registered using `RegisterRequiredAttribute` or
* `RegisterOptionalAttribute` in the constructor of the ZResource
*/
virtual void ParseXML(tinyxml2::XMLElement* reader);
/**
* Extracts data from the binary file
*/
virtual void ParseRawData();
/**
* Declares any data pointed by this resource that has not been declared already.
* For example, a Vtx referenced by a Dlist should be declared here if it wasn't
* declared previously by something else
*/
virtual void DeclareReferences(const std::string& prefix);
virtual void ParseRawDataLate();
virtual void DeclareReferencesLate(const std::string& prefix);
/**
* Adds this resource as a Declaration of its parent ZFile
*/
virtual Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr);
/**
* Returns the body of the variable of the extracted resource, without any side-effect
*/
[[nodiscard]] virtual std::string GetBodySourceCode() const;
/**
* Creates an automatically generated variable name for the current resource
*/
[[nodiscard]] virtual std::string GetDefaultName(const std::string& prefix) const;
virtual void GetSourceOutputCode(const std::string& prefix);
virtual std::string GetSourceOutputHeader(const std::string& prefix, std::set<std::string> *nameSet);
virtual void CalcHash();
/**
* Exports the resource to binary format
*/
virtual void Save(const fs::path& outFolder);
// Properties
/**
* Returns true if the resource will be externalized, and included back to the C file using
* `#include`s
*/
virtual bool IsExternalResource() const;
/**
* Can this type be wrapped in an <Array> node?
*/
virtual bool DoesSupportArray() const;
/**
* The type of the resource as a C struct
*/
[[nodiscard]] virtual std::string GetSourceTypeName() const = 0;
/**
* The type in the ZResource enum
*/
[[nodiscard]] virtual ZResourceType GetResourceType() const = 0;
/**
* The filename extension for assets extracted as standalone files
*/
[[nodiscard]] virtual std::string GetExternalExtension() const;
// Getters/Setters
[[nodiscard]] const std::string& GetName() const;
void SetName(const std::string& nName);
[[nodiscard]] const std::string& GetOutName() const;
void SetOutName(const std::string& nName);
[[nodiscard]] offset_t GetRawDataIndex() const;
void SetRawDataIndex(offset_t nRawDataIndex);
/**
* The size of the current struct being extracted, not counting data referenced by it
*/
[[nodiscard]] virtual size_t GetRawDataSize() const = 0;
/**
* The alignment of the extracted struct
*/
[[nodiscard]] virtual DeclarationAlignment GetDeclarationAlignment() const;
void SetInnerNode(bool inner);
/**
* Returns `true` if this ZResource was declared using an XML node,
* `false` otherwise (for example, a Vtx extracted indirectly by a DList)
*/
[[nodiscard]] bool WasDeclaredInXml() const;
[[nodiscard]] StaticConfig GetStaticConf() const;
protected:
std::string name;
std::string outName;
offset_t rawDataIndex;
std::string sourceOutput;
// Inner is used mostly for <Array> nodes
/**
* Is this resource an inner node of another resource?
* (namely inside an <Array>)
*/
bool isInner = false;
/**
* Can this type have an inner node?
*/
bool canHaveInner = false;
/**
* If set to true, create a reference for the asset in the file, but don't
* actually try to extract it from the file
*/
bool isCustomAsset;
bool declaredInXml = false;
StaticConfig staticConf = StaticConfig::Global;
// Reading from this XMLs attributes should be performed in the overrided `ParseXML` method.
std::map<std::string, ResourceAttribute> registeredAttributes;
// XML attributes registers.
// Registering XML attributes should be done in constructors.
// The resource needs this attribute. If it is not provided, then the program will throw an
// exception.
void RegisterRequiredAttribute(const std::string& attr);
// Optional attribute. The resource has to do manual checks and manual warnings. It may or may
// not have a value.
void RegisterOptionalAttribute(const std::string& attr, const std::string& defaultValue = "");
};
class ZResourceExporter
{
public:
ZResourceExporter() = default;
virtual ~ZResourceExporter() = default;
virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) = 0;
};
offset_t Seg2Filespace(segptr_t segmentedAddress, uint32_t parentBaseAddress);
typedef ZResource*(ZResourceFactoryFunc)(ZFile* nParent);
#define REGISTER_ZFILENODE(nodeName, zResClass) \
static ZResource* ZResourceFactory_##zResClass_##nodeName(ZFile* nParent) \
{ \
return static_cast<ZResource*>(new zResClass(nParent)); \
} \
\
class ZRes_##nodeName \
{ \
public: \
ZRes_##nodeName() \
{ \
ZFile::RegisterNode(#nodeName, &ZResourceFactory_##zResClass_##nodeName); \
} \
}; \
static ZRes_##nodeName inst_ZRes_##nodeName
#define REGISTER_EXPORTER(expFunc) \
class ZResExp_##expFunc \
{ \
public: \
ZResExp_##expFunc() { expFunc(); } \
}; \
static ZResExp_##expFunc inst_ZResExp_##expFunc

290
ZAPDTR/ZAPD/ZRom.cpp Normal file
View File

@@ -0,0 +1,290 @@
#include "ZRom.h"
#include "Utils/BitConverter.h"
#include <Utils/DiskFile.h>
#include "Utils/Directory.h"
#include "yaz0/yaz0.h"
#ifdef __linux__
#include <byteswap.h>
#endif
#include <Globals.h>
namespace fs = std::filesystem;
#define DMA_ENTRY_SIZE 16
#if defined(_MSC_VER)
#define __bswap_32 _byteswap_ulong
#define bswap_32 _byteswap_ulong
#endif
#if defined __APPLE__
#define __bswap32 __builtin_bswap32
#define bswap32 __builtin_bswap32
#endif
// ROM DMA Table Start
#define OOT_OFF_NTSC_10_RC 0x7430
#define OOT_OFF_NTSC_10 0x7430
#define OOT_OFF_NTSC_11 0x7430
#define OOT_OFF_PAL_10 0x7950
#define OOT_OFF_NTSC_12 0x7960
#define OOT_OFF_PAL_11 0x7950
#define OOT_OFF_JP_GC 0x7170
#define OOT_OFF_JP_MQ 0x7170
#define OOT_OFF_US_GC 0x7170
#define OOT_OFF_US_MQ 0x7170
#define OOT_OFF_PAL_GC_DBG1 0x12F70
#define OOT_OFF_PAL_MQ_DBG 0x12F70
#define OOT_OFF_PAL_GC_DBG2 0x12F70
#define OOT_OFF_PAL_GC 0x7170
#define OOT_OFF_PAL_MQ 0x7170
#define OOT_OFF_JP_GC_CE 0x7170
#define OOT_OFF_CN_IQUE 0xB7A0
#define OOT_OFF_TW_IQUE 0xB240
#define MM_OFF_US_10 0x1A500
#define MM_OFF_US_GC 0x1AE90
#define MM_OFF_JP_GC 0x1AE90
#define MM_OFF_JP_10 0x1C110
#define MM_OFF_JP_11 0x1C050
#define MM_OFF_DBG 0x24F60
#define OOT_NTSC_10 0xEC7011B7
#define OOT_NTSC_11 0xD43DA81F
#define OOT_NTSC_12 0x693BA2AE
#define OOT_PAL_10 0xB044B569
#define OOT_PAL_11 0xB2055FBD
#define OOT_NTSC_JP_GC_CE 0xF7F52DB8
#define OOT_NTSC_JP_GC 0xF611F4BA
#define OOT_NTSC_US_GC 0xF3DD35BA
#define OOT_PAL_GC 0x09465AC3
#define OOT_NTSC_JP_MQ 0xF43B45BA
#define OOT_NTSC_US_MQ 0xF034001A
#define OOT_PAL_MQ 0x1D4136F3
#define OOT_PAL_GC_DBG1 0x871E1C92 // 03-21-2002 build
#define OOT_PAL_GC_DBG2 0x87121EFE // 03-13-2002 build
#define OOT_PAL_GC_MQ_DBG 0x917D18F6
#define OOT_IQUE_TW 0x3D81FB3E
#define OOT_IQUE_CN 0xB1E1E07B
#define UNKNOWN 0xFFFFFFFF
#define MM_NTSC_10 0x5354631C
#define MM_NTSC_10_UNCOMPRESSED 0xDA6983E7
#define MM_NTSC_GC 0xB443EB08
#define MM_NTSC_JP_GC 0x8473D0C1
bool ZRom::IsMQ() {
int crc = BitConverter::ToInt32BE(romData, 0x10);
switch (crc) {
case OOT_NTSC_10:
case OOT_NTSC_11:
case OOT_NTSC_12:
case OOT_PAL_10:
case OOT_PAL_11:
case OOT_NTSC_JP_GC:
case OOT_NTSC_JP_GC_CE:
case OOT_NTSC_US_GC:
case OOT_PAL_GC:
case OOT_PAL_GC_DBG1:
case OOT_PAL_GC_DBG2:
case OOT_IQUE_CN:
case OOT_IQUE_TW:
// MM - Always not MQ
case MM_NTSC_10:
case MM_NTSC_10_UNCOMPRESSED:
case MM_NTSC_GC:
case MM_NTSC_JP_GC:
default:
return false;
case OOT_NTSC_JP_MQ:
case OOT_NTSC_US_MQ:
case OOT_PAL_MQ:
case OOT_PAL_GC_MQ_DBG:
return true;
}
}
ZRom::ZRom(std::string romPath)
{
RomVersion version;
romData = DiskFile::ReadAllBytes(romPath);
BitConverter::RomToBigEndian(romData.data(), romData.size());
version.crc = BitConverter::ToInt32BE(romData, 0x10);
switch (version.crc)
{
case OOT_NTSC_10:
version.version = "N64 NTSC 1.0";
version.listPath = "ntsc_oot.txt";
version.offset = OOT_OFF_NTSC_10;
break;
case OOT_NTSC_11:
version.version = "N64 NTSC 1.1";
version.listPath = "ntsc_oot.txt";
version.offset = OOT_OFF_NTSC_11;
break;
case OOT_NTSC_12:
version.version = "N64 NTSC 1.2";
version.listPath = "ntsc_12_oot.txt";
version.offset = OOT_OFF_NTSC_12;
break;
case OOT_PAL_10:
version.version = "N64 PAL 1.0";
version.listPath = "pal_oot.txt";
version.offset = OOT_OFF_PAL_10;
break;
case OOT_PAL_11:
version.version = "N64 PAL 1.1";
version.listPath = "pal_oot.txt";
version.offset = OOT_OFF_PAL_11;
break;
case OOT_NTSC_JP_GC:
version.version = "JP GameCube (MQ Disk)";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_GC;
break;
case OOT_NTSC_JP_GC_CE:
version.version = "GameCube (Collectors Edition Disk)";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_GC_CE;
break;
case OOT_NTSC_JP_MQ:
version.version = "JP Master Quest";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_MQ;
break;
case OOT_NTSC_US_MQ:
version.version = "NTSC Master Quest";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_MQ;
break;
case OOT_NTSC_US_GC:
version.version = "NTSC GameCube";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_US_MQ;
break;
case OOT_PAL_GC:
version.version = "PAL GameCube";
version.listPath = "gamecube_pal.txt";
version.offset = OOT_OFF_PAL_GC;
break;
case OOT_PAL_MQ:
version.version = "PAL Master Quest";
version.listPath = "gamecube_pal.txt";
version.offset = OOT_OFF_PAL_MQ;
break;
case OOT_PAL_GC_DBG1:
version.version = "GameCube Debug 1.0";
version.listPath = "dbg.txt";
version.offset = OOT_OFF_PAL_GC_DBG1;
break;
case OOT_PAL_GC_DBG2:
version.version = "GameCube Debug 2.0";
version.listPath = "dbg.txt";
version.offset = OOT_OFF_PAL_GC_DBG2;
break;
case OOT_PAL_GC_MQ_DBG:
version.version = "GameCube MQ-Debug";
version.listPath = "dbg.txt";
version.offset = OOT_OFF_PAL_MQ_DBG;
break;
case OOT_IQUE_CN:
version.version = "OoT IQue";
version.listPath = "ique.txt";
version.offset = OOT_OFF_CN_IQUE;
break;
case OOT_IQUE_TW:
version.version = "TW IQue";
version.listPath = "ique.txt";
version.offset = OOT_OFF_TW_IQUE;
break;
case MM_NTSC_10:
version.version = "MM US 1.0";
version.listPath = "mm.txt";
version.offset = MM_OFF_US_10;
break;
case MM_NTSC_10_UNCOMPRESSED:
version.version = "MM US 1.0";
version.listPath = "mm.txt";
version.offset = MM_OFF_US_10;
break;
case MM_NTSC_GC:
version.version = "MM US GC";
version.listPath = "mm_gc.txt";
version.offset = MM_OFF_US_GC;
break;
case MM_NTSC_JP_GC:
version.version = "MM JP GC";
version.listPath = "mm_gc_jp.txt";
version.offset = MM_OFF_JP_GC;
break;
}
auto path = StringHelper::Sprintf("%s/%s", Globals::Instance->fileListPath.string().c_str(), version.listPath.c_str());
auto txt = DiskFile::ReadAllText(path);
std::vector<std::string> lines = StringHelper::Split(txt, "\n");
std::vector<uint8_t> decompressedData(1);
for (unsigned int i = 0; i < lines.size(); i++)
{
lines[i] = StringHelper::Strip(lines[i], "\r");
bool yarCompressed = false;
const int romOffset = version.offset + (DMA_ENTRY_SIZE * i);
const int virtStart = BitConverter::ToInt32BE(romData, romOffset + 0);
const int virtEnd = BitConverter::ToInt32BE(romData, romOffset + 4);
const int physStart = BitConverter::ToInt32BE(romData, romOffset + 8);
const int physEnd = BitConverter::ToInt32BE(romData, romOffset + 12);
// File Deleted
if (physEnd == 0xFFFFFFFF && physStart == 0xFFFFFFFF)
{
// MM has some other checks that we might need to do
//if (virtEnd - virtStart == 0)
continue;
}
const bool compressed = physEnd != 0;
int size = compressed ? physEnd - physStart : virtEnd - virtStart;
auto outData = std::vector<uint8_t>();
outData.resize(size);
memcpy(outData.data(), romData.data() + physStart, size);
// An ifdef is used here because at this point the XMLs haven't been parsed, and we don't
// know if this is MM or OOT
#ifdef GAME_MM
if ((i >= 15 && i <= 20) || i == 22)
{
yarCompressed = true;
}
#endif
if (compressed)
{
int decSize = virtEnd - virtStart;
decompressedData = std::vector<uint8_t>();
decompressedData.resize(decSize);
yaz0_decode(outData.data(), decompressedData.data(), decSize);
files[lines[i]] = decompressedData;
}
else if (yarCompressed)
{
//int decSize = virtEnd - virtStart;
decompressedData = std::vector<uint8_t>();
decompressedData.resize(1024*1024); //TODO FIX THIS PLEASE
yaz0_decodeYarArchive(outData.data(), decompressedData.data(), size);
files[lines[i]] = decompressedData;
}
else
files[lines[i]] = outData;
//DiskFile::WriteAllBytes(StringHelper::Sprintf("baserom/%s", lines[i].c_str()), files[lines[i]]);
}
}
std::vector<uint8_t> ZRom::GetFile(std::string fileName)
{
return files[fileName];
}

28
ZAPDTR/ZAPD/ZRom.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include <vector>
#include <map>
#include <string>
class ZRom
{
public:
ZRom(std::string romPath);
std::vector<uint8_t> GetFile(std::string fileName);
bool IsMQ();
protected:
std::vector<uint8_t> romData;
std::map<std::string, std::vector<uint8_t>> files;
};
struct RomVersion
{
std::string version = "None";
std::string error = "None";
std::string listPath = "None";
int offset;
uint32_t crc;
};

View File

@@ -0,0 +1,20 @@
#include "EndMarker.h"
EndMarker::EndMarker(ZFile* nParent) : ZRoomCommand(nParent)
{
}
std::string EndMarker::GetBodySourceCode() const
{
return "SCENE_CMD_END()";
}
std::string EndMarker::GetCommandCName() const
{
return "SCmdEndMarker";
}
RoomCommand EndMarker::GetRoomCommand() const
{
return RoomCommand::EndMarker;
}

Some files were not shown because too many files have changed in this diff Show More