Plugins agregados
This commit is contained in:
84
ZAPDTR/.clang-format
Normal file
84
ZAPDTR/.clang-format
Normal 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
83
ZAPDTR/.github/workflows/main.yml
vendored
Normal 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
341
ZAPDTR/.gitignore
vendored
Normal 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
|
||||
76
ZAPDTR/ExporterTest/CollisionExporter.cpp
Normal file
76
ZAPDTR/ExporterTest/CollisionExporter.cpp
Normal 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);
|
||||
}
|
||||
10
ZAPDTR/ExporterTest/CollisionExporter.h
Normal file
10
ZAPDTR/ExporterTest/CollisionExporter.h
Normal 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;
|
||||
};
|
||||
79
ZAPDTR/ExporterTest/Main.cpp
Normal file
79
ZAPDTR/ExporterTest/Main.cpp
Normal 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);
|
||||
372
ZAPDTR/ExporterTest/RoomExporter.cpp
Normal file
372
ZAPDTR/ExporterTest/RoomExporter.cpp
Normal 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());
|
||||
}
|
||||
10
ZAPDTR/ExporterTest/RoomExporter.h
Normal file
10
ZAPDTR/ExporterTest/RoomExporter.h
Normal 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;
|
||||
};
|
||||
14
ZAPDTR/ExporterTest/TextureExporter.cpp
Normal file
14
ZAPDTR/ExporterTest/TextureExporter.cpp
Normal 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]);
|
||||
}
|
||||
11
ZAPDTR/ExporterTest/TextureExporter.h
Normal file
11
ZAPDTR/ExporterTest/TextureExporter.h
Normal 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
21
ZAPDTR/LICENSE
Normal 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
164
ZAPDTR/README.md
Normal 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:
|
||||
|
||||

|
||||
454
ZAPDTR/ZAPD/CMakeLists.txt
Normal file
454
ZAPDTR/ZAPD/CMakeLists.txt
Normal 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
23
ZAPDTR/ZAPD/CRC32.h
Normal 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);
|
||||
}
|
||||
208
ZAPDTR/ZAPD/CrashHandler.cpp
Normal file
208
ZAPDTR/ZAPD/CrashHandler.cpp
Normal 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
|
||||
}
|
||||
6
ZAPDTR/ZAPD/CrashHandler.h
Normal file
6
ZAPDTR/ZAPD/CrashHandler.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef CRASH_HANDLER_H
|
||||
#define CRASH_HANDLER_H
|
||||
|
||||
void CrashHandler_Init();
|
||||
|
||||
#endif
|
||||
248
ZAPDTR/ZAPD/Declaration.cpp
Normal file
248
ZAPDTR/ZAPD/Declaration.cpp
Normal 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
188
ZAPDTR/ZAPD/Declaration.h
Normal 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);
|
||||
};
|
||||
9
ZAPDTR/ZAPD/ExecutableMain.cpp
Normal file
9
ZAPDTR/ZAPD/ExecutableMain.cpp
Normal 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
27
ZAPDTR/ZAPD/ExporterSet.h
Normal 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;
|
||||
};
|
||||
0
ZAPDTR/ZAPD/FileWorker.cpp
Normal file
0
ZAPDTR/ZAPD/FileWorker.cpp
Normal file
16
ZAPDTR/ZAPD/FileWorker.h
Normal file
16
ZAPDTR/ZAPD/FileWorker.h
Normal 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
301
ZAPDTR/ZAPD/GameConfig.cpp
Normal 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
97
ZAPDTR/ZAPD/GameConfig.h
Normal 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
363
ZAPDTR/ZAPD/Globals.cpp
Normal 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
103
ZAPDTR/ZAPD/Globals.h
Normal 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);
|
||||
};
|
||||
507
ZAPDTR/ZAPD/ImageBackend.cpp
Normal file
507
ZAPDTR/ZAPD/ImageBackend.cpp
Normal 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;
|
||||
}
|
||||
72
ZAPDTR/ZAPD/ImageBackend.h
Normal file
72
ZAPDTR/ZAPD/ImageBackend.h
Normal 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
756
ZAPDTR/ZAPD/Main.cpp
Normal 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;
|
||||
}
|
||||
0
ZAPDTR/ZAPD/NuGet/libpng.static.txt
Normal file
0
ZAPDTR/ZAPD/NuGet/libpng.static.txt
Normal file
614
ZAPDTR/ZAPD/OtherStructs/CutsceneMM_Commands.cpp
Normal file
614
ZAPDTR/ZAPD/OtherStructs/CutsceneMM_Commands.cpp
Normal 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);
|
||||
}
|
||||
481
ZAPDTR/ZAPD/OtherStructs/CutsceneMM_Commands.h
Normal file
481
ZAPDTR/ZAPD/OtherStructs/CutsceneMM_Commands.h
Normal 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;
|
||||
};
|
||||
458
ZAPDTR/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp
Normal file
458
ZAPDTR/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp
Normal 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;
|
||||
}
|
||||
314
ZAPDTR/ZAPD/OtherStructs/CutsceneOoT_Commands.h
Normal file
314
ZAPDTR/ZAPD/OtherStructs/CutsceneOoT_Commands.h
Normal 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;
|
||||
};
|
||||
128
ZAPDTR/ZAPD/OtherStructs/Cutscene_Common.cpp
Normal file
128
ZAPDTR/ZAPD/OtherStructs/Cutscene_Common.cpp
Normal 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);
|
||||
}
|
||||
72
ZAPDTR/ZAPD/OtherStructs/Cutscene_Common.h
Normal file
72
ZAPDTR/ZAPD/OtherStructs/Cutscene_Common.h
Normal 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;
|
||||
};
|
||||
354
ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.cpp
Normal file
354
ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.cpp
Normal 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;
|
||||
}
|
||||
111
ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.h
Normal file
111
ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.h
Normal 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;
|
||||
};
|
||||
123
ZAPDTR/ZAPD/OutputFormatter.cpp
Normal file
123
ZAPDTR/ZAPD/OutputFormatter.cpp
Normal 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);
|
||||
}
|
||||
42
ZAPDTR/ZAPD/OutputFormatter.h
Normal file
42
ZAPDTR/ZAPD/OutputFormatter.h
Normal 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();
|
||||
};
|
||||
354
ZAPDTR/ZAPD/Overlays/ZOverlay.cpp
Normal file
354
ZAPDTR/ZAPD/Overlays/ZOverlay.cpp
Normal 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
|
||||
78
ZAPDTR/ZAPD/Overlays/ZOverlay.h
Normal file
78
ZAPDTR/ZAPD/Overlays/ZOverlay.h
Normal 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
|
||||
178
ZAPDTR/ZAPD/Utils/BinaryReader.cpp
Normal file
178
ZAPDTR/ZAPD/Utils/BinaryReader.cpp
Normal 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;
|
||||
}
|
||||
41
ZAPDTR/ZAPD/Utils/BinaryReader.h
Normal file
41
ZAPDTR/ZAPD/Utils/BinaryReader.h
Normal 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;
|
||||
};
|
||||
148
ZAPDTR/ZAPD/Utils/BinaryWriter.cpp
Normal file
148
ZAPDTR/ZAPD/Utils/BinaryWriter.cpp
Normal 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);
|
||||
}
|
||||
41
ZAPDTR/ZAPD/Utils/BinaryWriter.h
Normal file
41
ZAPDTR/ZAPD/Utils/BinaryWriter.h
Normal 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;
|
||||
};
|
||||
209
ZAPDTR/ZAPD/Utils/BitConverter.h
Normal file
209
ZAPDTR/ZAPD/Utils/BitConverter.h
Normal 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
|
||||
}
|
||||
}
|
||||
};
|
||||
60
ZAPDTR/ZAPD/Utils/Directory.h
Normal file
60
ZAPDTR/ZAPD/Utils/Directory.h
Normal 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;
|
||||
}
|
||||
};
|
||||
91
ZAPDTR/ZAPD/Utils/DiskFile.h
Normal file
91
ZAPDTR/ZAPD/Utils/DiskFile.h
Normal 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());
|
||||
}
|
||||
};
|
||||
97
ZAPDTR/ZAPD/Utils/MemoryStream.cpp
Normal file
97
ZAPDTR/ZAPD/Utils/MemoryStream.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
33
ZAPDTR/ZAPD/Utils/MemoryStream.h
Normal file
33
ZAPDTR/ZAPD/Utils/MemoryStream.h
Normal 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
50
ZAPDTR/ZAPD/Utils/Path.h
Normal 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(); };
|
||||
};
|
||||
34
ZAPDTR/ZAPD/Utils/Stream.h
Normal file
34
ZAPDTR/ZAPD/Utils/Stream.h
Normal 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;
|
||||
};
|
||||
191
ZAPDTR/ZAPD/Utils/StringHelper.cpp
Normal file
191
ZAPDTR/ZAPD/Utils/StringHelper.cpp
Normal 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); });
|
||||
}
|
||||
33
ZAPDTR/ZAPD/Utils/StringHelper.h
Normal file
33
ZAPDTR/ZAPD/Utils/StringHelper.h
Normal 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
45
ZAPDTR/ZAPD/Utils/vt.h
Normal 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
|
||||
455
ZAPDTR/ZAPD/WarningHandler.cpp
Normal file
455
ZAPDTR/ZAPD/WarningHandler.cpp
Normal 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");
|
||||
}
|
||||
146
ZAPDTR/ZAPD/WarningHandler.h
Normal file
146
ZAPDTR/ZAPD/WarningHandler.h
Normal 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
194
ZAPDTR/ZAPD/ZActorList.cpp
Normal 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
52
ZAPDTR/ZAPD/ZActorList.h
Normal 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
580
ZAPDTR/ZAPD/ZAnimation.cpp
Normal 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
179
ZAPDTR/ZAPD/ZAnimation.h
Normal 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
154
ZAPDTR/ZAPD/ZArray.cpp
Normal 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
31
ZAPDTR/ZAPD/ZArray.h
Normal 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
416
ZAPDTR/ZAPD/ZAudio.cpp
Normal 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
130
ZAPDTR/ZAPD/ZAudio.h
Normal 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;
|
||||
};
|
||||
670
ZAPDTR/ZAPD/ZAudioDecode.cpp
Normal file
670
ZAPDTR/ZAPD/ZAudioDecode.cpp
Normal 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
200
ZAPDTR/ZAPD/ZBackground.cpp
Normal 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
34
ZAPDTR/ZAPD/ZBackground.h
Normal 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
116
ZAPDTR/ZAPD/ZBlob.cpp
Normal 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
31
ZAPDTR/ZAPD/ZBlob.h
Normal 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
307
ZAPDTR/ZAPD/ZCKeyFrame.cpp
Normal 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
121
ZAPDTR/ZAPD/ZCKeyFrame.h
Normal 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;
|
||||
};
|
||||
221
ZAPDTR/ZAPD/ZCKeyFrameAnim.cpp
Normal file
221
ZAPDTR/ZAPD/ZCKeyFrameAnim.cpp
Normal 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;
|
||||
}
|
||||
52
ZAPDTR/ZAPD/ZCkeyFrameAnim.h
Normal file
52
ZAPDTR/ZAPD/ZCkeyFrameAnim.h
Normal 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
451
ZAPDTR/ZAPD/ZCollision.cpp
Normal 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
75
ZAPDTR/ZAPD/ZCollision.h
Normal 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;
|
||||
};
|
||||
78
ZAPDTR/ZAPD/ZCollisionPoly.cpp
Normal file
78
ZAPDTR/ZAPD/ZCollisionPoly.cpp
Normal 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;
|
||||
}
|
||||
29
ZAPDTR/ZAPD/ZCollisionPoly.h
Normal file
29
ZAPDTR/ZAPD/ZCollisionPoly.h
Normal 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
375
ZAPDTR/ZAPD/ZCutscene.cpp
Normal 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
37
ZAPDTR/ZAPD/ZCutscene.h
Normal 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
2324
ZAPDTR/ZAPD/ZDisplayList.cpp
Normal file
File diff suppressed because it is too large
Load Diff
265
ZAPDTR/ZAPD/ZDisplayList.h
Normal file
265
ZAPDTR/ZAPD/ZDisplayList.h
Normal 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
1505
ZAPDTR/ZAPD/ZFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
150
ZAPDTR/ZAPD/ZFile.h
Normal file
150
ZAPDTR/ZAPD/ZFile.h
Normal 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
420
ZAPDTR/ZAPD/ZLimb.cpp
Normal 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
74
ZAPDTR/ZAPD/ZLimb.h
Normal 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
59
ZAPDTR/ZAPD/ZMtx.cpp
Normal 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
24
ZAPDTR/ZAPD/ZMtx.h
Normal 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
218
ZAPDTR/ZAPD/ZPath.cpp
Normal 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
51
ZAPDTR/ZAPD/ZPath.h
Normal 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;
|
||||
};
|
||||
108
ZAPDTR/ZAPD/ZPlayerAnimationData.cpp
Normal file
108
ZAPDTR/ZAPD/ZPlayerAnimationData.cpp
Normal 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;
|
||||
}
|
||||
28
ZAPDTR/ZAPD/ZPlayerAnimationData.h
Normal file
28
ZAPDTR/ZAPD/ZPlayerAnimationData.h
Normal 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
57
ZAPDTR/ZAPD/ZPointer.cpp
Normal 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
22
ZAPDTR/ZAPD/ZPointer.h
Normal 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
450
ZAPDTR/ZAPD/ZResource.cpp
Normal 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
268
ZAPDTR/ZAPD/ZResource.h
Normal 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
290
ZAPDTR/ZAPD/ZRom.cpp
Normal 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
28
ZAPDTR/ZAPD/ZRom.h
Normal 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;
|
||||
};
|
||||
20
ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.cpp
Normal file
20
ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.cpp
Normal 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
Reference in New Issue
Block a user