diff --git a/ZAPDTR/.clang-format b/ZAPDTR/.clang-format new file mode 100644 index 000000000..784e734e9 --- /dev/null +++ b/ZAPDTR/.clang-format @@ -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: true +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 +... + diff --git a/ZAPDTR/.gitignore b/ZAPDTR/.gitignore new file mode 100644 index 000000000..68c502e36 --- /dev/null +++ b/ZAPDTR/.gitignore @@ -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 diff --git a/ZAPDTR/.gitrepo b/ZAPDTR/.gitrepo new file mode 100644 index 000000000..cd980ceb8 --- /dev/null +++ b/ZAPDTR/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = https://github.com/HarbourMasters/ZAPDTR.git + branch = master + commit = a53a53ea4216b926253dde2c942ae0ca6e2f2ccd + parent = f52a2a6406eb1bbd2b631c65923d879a83983ccb + method = rebase + cmdver = 0.4.1 diff --git a/ZAPDTR/ExporterTest/CollisionExporter.cpp b/ZAPDTR/ExporterTest/CollisionExporter.cpp new file mode 100644 index 000000000..e00f5c1b0 --- /dev/null +++ b/ZAPDTR/ExporterTest/CollisionExporter.cpp @@ -0,0 +1,74 @@ +#include "CollisionExporter.h" + +void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] 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].a); + writer->Write(col->polygons[i].b); + writer->Write(col->polygons[i].c); + writer->Write(col->polygons[i].d); + } + + writer->Seek(col->polyTypeDefSegmentOffset, SeekOffsetType::Start); + + for (uint16_t i = 0; i < col->polygonTypes.size(); i++) + writer->Write(col->polygonTypes[i]); + + 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); +} diff --git a/ZAPDTR/ExporterTest/CollisionExporter.h b/ZAPDTR/ExporterTest/CollisionExporter.h new file mode 100644 index 000000000..5f48e6557 --- /dev/null +++ b/ZAPDTR/ExporterTest/CollisionExporter.h @@ -0,0 +1,10 @@ +#pragma once + +#include "ZCollision.h" +#include "ZResource.h" + +class ExporterExample_Collision : public ZResourceExporter +{ +public: + void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override; +}; \ No newline at end of file diff --git a/ZAPDTR/ExporterTest/ExporterTest.vcxproj b/ZAPDTR/ExporterTest/ExporterTest.vcxproj new file mode 100644 index 000000000..839d45102 --- /dev/null +++ b/ZAPDTR/ExporterTest/ExporterTest.vcxproj @@ -0,0 +1,160 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {65608eb0-1a47-45ad-ab66-192fb64c762c} + ExporterTest + 10.0 + ExporterExample + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + $(ProjectDir)..\ZAPD\;$(ProjectDir)..\ZAPDUtils;$(ProjectDir)..\lib\tinyxml2;$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\lib\elfio;$(ProjectDir)..\lib\stb;$(ProjectDir);$(IncludePath) + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + stdcpp17 + stdc11 + MultiThreadedDebug + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ZAPDTR/ExporterTest/ExporterTest.vcxproj.filters b/ZAPDTR/ExporterTest/ExporterTest.vcxproj.filters new file mode 100644 index 000000000..166f563a1 --- /dev/null +++ b/ZAPDTR/ExporterTest/ExporterTest.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/ZAPDTR/ExporterTest/Main.cpp b/ZAPDTR/ExporterTest/Main.cpp new file mode 100644 index 000000000..07fdbeece --- /dev/null +++ b/ZAPDTR/ExporterTest/Main.cpp @@ -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); diff --git a/ZAPDTR/ExporterTest/Makefile b/ZAPDTR/ExporterTest/Makefile new file mode 100644 index 000000000..42033b7c0 --- /dev/null +++ b/ZAPDTR/ExporterTest/Makefile @@ -0,0 +1,28 @@ +# Only used for standalone compilation, usually inherits these from the main makefile +CXXFLAGS ?= -Wall -Wextra -O2 -g -std=c++17 + +SRC_DIRS := $(shell find . -type d -not -path "*build*") +CPP_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp)) +H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h)) + +O_FILES := $(foreach f,$(CPP_FILES:.cpp=.o),build/$f) +LIB := ExporterTest.a + +# create build directories +$(shell mkdir -p $(foreach dir,$(SRC_DIRS),build/$(dir))) + +all: $(LIB) + +clean: + rm -rf build $(LIB) + +format: + clang-format-11 -i $(CPP_FILES) $(H_FILES) + +.PHONY: all clean format + +build/%.o: %.cpp + $(CXX) $(CXXFLAGS) $(OPTFLAGS) -I ./ -I ../ZAPD -I ../ZAPDUtils -I ../lib/tinyxml2 -c $(OUTPUT_OPTION) $< + +$(LIB): $(O_FILES) + $(AR) rcs $@ $^ diff --git a/ZAPDTR/ExporterTest/RoomExporter.cpp b/ZAPDTR/ExporterTest/RoomExporter.cpp new file mode 100644 index 000000000..6c5552d8f --- /dev/null +++ b/ZAPDTR/ExporterTest/RoomExporter.cpp @@ -0,0 +1,372 @@ +#include "RoomExporter.h" +#include "CollisionExporter.h" +#include "Utils/BinaryWriter.h" +#include "Utils/File.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, fs::path outPath, BinaryWriter* writer) +{ + ZRoom* room = dynamic_cast(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 (EntranceEntry 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.initVar); + } + + 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(); + // File::WriteAllBytes(StringHelper::Sprintf("%s", res->GetName().c_str()), + // memStream->ToVector()); +} diff --git a/ZAPDTR/ExporterTest/RoomExporter.h b/ZAPDTR/ExporterTest/RoomExporter.h new file mode 100644 index 000000000..ee531dc87 --- /dev/null +++ b/ZAPDTR/ExporterTest/RoomExporter.h @@ -0,0 +1,10 @@ +#pragma once + +#include "ZResource.h" +#include "ZRoom/ZRoom.h" + +class ExporterExample_Room : public ZResourceExporter +{ +public: + void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override; +}; \ No newline at end of file diff --git a/ZAPDTR/ExporterTest/TextureExporter.cpp b/ZAPDTR/ExporterTest/TextureExporter.cpp new file mode 100644 index 000000000..6488bed3a --- /dev/null +++ b/ZAPDTR/ExporterTest/TextureExporter.cpp @@ -0,0 +1,14 @@ +#include "TextureExporter.h" +#include "../ZAPD/ZFile.h" + +void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] 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]); +} diff --git a/ZAPDTR/ExporterTest/TextureExporter.h b/ZAPDTR/ExporterTest/TextureExporter.h new file mode 100644 index 000000000..41c4e79be --- /dev/null +++ b/ZAPDTR/ExporterTest/TextureExporter.h @@ -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, fs::path outPath, BinaryWriter* writer) override; +}; \ No newline at end of file diff --git a/ZAPDTR/Jenkinsfile b/ZAPDTR/Jenkinsfile new file mode 100644 index 000000000..ec9b56ac5 --- /dev/null +++ b/ZAPDTR/Jenkinsfile @@ -0,0 +1,97 @@ +pipeline { + agent { + label 'ZAPD' + } + + stages { + // Non-parallel ZAPD stage + stage('Build ZAPD') { + steps { + sh 'make -j WERROR=1' + } + } + + // CHECKOUT THE REPOS + stage('Checkout Repos') { + parallel { + stage('Checkout oot') { + steps { + dir('oot') { + git url: 'https://github.com/zeldaret/oot.git' + } + } + } + + stage('Checkout mm') { + steps{ + dir('mm') { + git url: 'https://github.com/zeldaret/mm.git' + } + } + } + } + } + + // SETUP THE REPOS + stage('Set up repos') { + parallel { + stage('Setup OOT') { + steps { + dir('oot') { + sh 'cp /usr/local/etc/roms/baserom_oot.z64 baserom_original.z64' + + // Identical to `make setup` except for copying our newer ZAPD.out into oot + sh 'git submodule update --init --recursive' + sh 'make -C tools' + sh 'cp ../ZAPD.out tools/ZAPD/' + sh 'python3 fixbaserom.py' + sh 'python3 extract_baserom.py' + sh 'python3 extract_assets.py' + } + } + } + + stage('Setup MM') { + steps { + dir('mm') { + sh 'cp /usr/local/etc/roms/mm.us.rev1.z64 baserom.mm.us.rev1.z64' + + // Identical to `make setup` except for copying our newer ZAPD.out into mm + sh 'make -C tools' + sh 'cp ../ZAPD.out tools/ZAPD/' + sh 'python3 tools/fixbaserom.py' + sh 'python3 tools/extract_baserom.py' + sh 'python3 extract_assets.py -t$(nproc)' + } + } + } + } + } + + // BUILD THE REPOS + stage('Build repos') { + parallel { + stage('Build oot') { + steps { + dir('oot') { + sh 'make -j' + } + } + } + stage('Build mm') { + steps { + dir('mm') { + sh 'make -j disasm' + sh 'make -j all' + } + } + } + } + } + } + post { + always { + cleanWs() + } + } +} diff --git a/ZAPDTR/LICENSE b/ZAPDTR/LICENSE new file mode 100644 index 000000000..90b734bde --- /dev/null +++ b/ZAPDTR/LICENSE @@ -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. diff --git a/ZAPDTR/Makefile b/ZAPDTR/Makefile new file mode 100644 index 000000000..2b47a8039 --- /dev/null +++ b/ZAPDTR/Makefile @@ -0,0 +1,134 @@ +# use variables in submakes +export +OPTIMIZATION_ON ?= 1 +ASAN ?= 0 +DEPRECATION_ON ?= 1 +DEBUG ?= 0 +COPYCHECK_ARGS ?= +LLD ?= 0 +WERROR ?= 0 + +# Use clang++ if available, else use g++ +ifeq ($(shell command -v clang++ >/dev/null 2>&1; echo $$?),0) + CXX := clang++ +else + CXX := g++ +endif + +INC := -I ZAPD -I lib/elfio -I lib/libgfxd -I lib/tinyxml2 -I ZAPDUtils +CXXFLAGS := -fpic -std=c++17 -Wall -Wextra -fno-omit-frame-pointer +OPTFLAGS := + +ifneq ($(DEBUG),0) + OPTIMIZATION_ON = 0 + CXXFLAGS += -g3 -DDEVELOPMENT -D_DEBUG + COPYCHECK_ARGS += --devel + DEPRECATION_ON = 0 +endif + +ifneq ($(WERROR),0) + CXXFLAGS += -Werror +endif + +ifeq ($(OPTIMIZATION_ON),0) + OPTFLAGS := -O0 +else + OPTFLAGS := -O2 +endif + +ifneq ($(ASAN),0) + CXXFLAGS += -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined +endif +ifneq ($(DEPRECATION_ON),0) + CXXFLAGS += -DDEPRECATION_ON +endif +# CXXFLAGS += -DTEXTURE_DEBUG + +LDFLAGS := -lm -ldl -lpng + +# Use LLD if available. Set LLD=0 to not use it +ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0) + LLD := 1 +endif + +ifneq ($(LLD),0) + LDFLAGS += -fuse-ld=lld +endif + +UNAME := $(shell uname) +UNAMEM := $(shell uname -m) +ifneq ($(UNAME), Darwin) + LDFLAGS += -Wl,-export-dynamic -lstdc++fs + EXPORTERS := -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive +else + EXPORTERS := -Wl,-force_load ExporterTest/ExporterTest.a + ifeq ($(UNAMEM),arm64) + ifeq ($(shell brew list libpng > /dev/null 2>&1; echo $$?),0) + LDFLAGS += -L $(shell brew --prefix)/lib + INC += -I $(shell brew --prefix)/include + else + $(error Please install libpng via Homebrew) + endif + endif +endif + + +ZAPD_SRC_DIRS := $(shell find ZAPD -type d) +SRC_DIRS = $(ZAPD_SRC_DIRS) lib/tinyxml2 + +ZAPD_CPP_FILES := $(foreach dir,$(ZAPD_SRC_DIRS),$(wildcard $(dir)/*.cpp)) +ZAPD_H_FILES := $(foreach dir,$(ZAPD_SRC_DIRS),$(wildcard $(dir)/*.h)) + +CPP_FILES += $(ZAPD_CPP_FILES) lib/tinyxml2/tinyxml2.cpp +O_FILES := $(foreach f,$(CPP_FILES:.cpp=.o),build/$f) +O_FILES += build/ZAPD/BuildInfo.o + +# create build directories +$(shell mkdir -p $(foreach dir,$(SRC_DIRS),build/$(dir))) + + +# Main targets +all: ZAPD.out copycheck + +build/ZAPD/BuildInfo.o: + python3 ZAPD/genbuildinfo.py $(COPYCHECK_ARGS) + $(CXX) $(CXXFLAGS) $(OPTFLAGS) $(INC) -c $(OUTPUT_OPTION) build/ZAPD/BuildInfo.cpp + +copycheck: ZAPD.out + python3 copycheck.py + +clean: + rm -rf build ZAPD.out + $(MAKE) -C lib/libgfxd clean + $(MAKE) -C ZAPDUtils clean + $(MAKE) -C ExporterTest clean + +rebuild: clean all + +format: + clang-format-11 -i $(ZAPD_CPP_FILES) $(ZAPD_H_FILES) + $(MAKE) -C ZAPDUtils format + $(MAKE) -C ExporterTest format + +.PHONY: all build/ZAPD/BuildInfo.o copycheck clean rebuild format + +build/%.o: %.cpp + $(CXX) $(CXXFLAGS) $(OPTFLAGS) $(INC) -c $(OUTPUT_OPTION) $< + + +# Submakes +lib/libgfxd/libgfxd.a: + $(MAKE) -C lib/libgfxd + +.PHONY: ExporterTest +ExporterTest: + $(MAKE) -C ExporterTest + +.PHONY: ZAPDUtils +ZAPDUtils: + $(MAKE) -C ZAPDUtils + + +# Linking +ZAPD.out: $(O_FILES) lib/libgfxd/libgfxd.a ExporterTest ZAPDUtils + $(CXX) $(CXXFLAGS) $(O_FILES) lib/libgfxd/libgfxd.a ZAPDUtils/ZAPDUtils.a $(EXPORTERS) $(LDFLAGS) $(OUTPUT_OPTION) diff --git a/ZAPDTR/README.md b/ZAPDTR/README.md new file mode 100644 index 000000000..448aea033 --- /dev/null +++ b/ZAPDTR/README.md @@ -0,0 +1,168 @@ +# 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 clasic `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. +- `bovl`: "Build overlay" mode. + - In this mode, ZAPD expects an overlay C file as input, a filename as ouput and an overlay configuration path (`-cfg`). + - ZAPD will generate a reloc `.s` file. + +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` +- `-cfg PATH`: Set cfg path (for overlays). + - Can be used only in `bovl` mode. +- `-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-pointer` | Warn | ZAPD lacks the info to make a symbol, so must output a hardcoded pointer | +| `-Wintersection` | Warn | Two assets intersect | +| `-Winvalid-attribute-value` | Err | Attribute declared in XML is wrong | +| `-Winvalid-extracted-data` | Err | Extracted data does not have correct form | +| `-Winvalid-jpeg` | Err | JPEG file does not conform to the game's format requirements | +| `-Winvalid-png` | Err | Issues arising when processing PNG data | +| `-Winvalid-xml` | Err | XML has syntax errors | +| `-Wmissing-attribute` | Warn | Required attribute missing in XML tag | +| `-Wmissing-offsets` | Warn | Offset attribute missing in XML tag | +| `-Wmissing-segment` | Warn | Segment not given in File tag in XML | +| `-Wnot-implemented` | Warn | ZAPD does not currently support this feature | +| `-Wunaccounted` | Off | Large blocks of unaccounted | +| `-Wunknown-attribute` | Warn | Unknown attribute in XML entry tag | + +There are also errors that do not have a type, and cannot be disabled. + +For example, here we have invoked ZAPD in the usual way to extract using a (rather badly-written) XML, but escalating `-Wintersection` to an error: + +![ZAPD warnings example](docs/zapd_warning_example.png?raw=true) diff --git a/ZAPDTR/ZAPD/CRC32.h b/ZAPDTR/ZAPD/CRC32.h new file mode 100644 index 000000000..4158a5528 --- /dev/null +++ b/ZAPDTR/ZAPD/CRC32.h @@ -0,0 +1,23 @@ +#pragma once + +static uint32_t CRC32B(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); +} \ No newline at end of file diff --git a/ZAPDTR/ZAPD/Declaration.cpp b/ZAPDTR/ZAPD/Declaration.cpp new file mode 100644 index 000000000..eeb988db7 --- /dev/null +++ b/ZAPDTR/ZAPD/Declaration.cpp @@ -0,0 +1,229 @@ +#include "Declaration.h" + +#include "Globals.h" +#include "Utils/StringHelper.h" + +Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nText) +{ + address = nAddress; + alignment = nAlignment; + size = nSize; + text = nText; +} + +Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + const std::string& nText) + : Declaration(nAddress, nAlignment, nSize, nText) +{ + varType = nVarType; + varName = nVarName; + isArray = nIsArray; +} + +Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + size_t nArrayItemCnt, const std::string& nText) + : Declaration(nAddress, nAlignment, nSize, nText) +{ + varType = nVarType; + varName = nVarName; + isArray = nIsArray; + arrayItemCnt = nArrayItemCnt; +} + +Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + const std::string& nArrayItemCntStr, const std::string& nText) + : Declaration(nAddress, nAlignment, nSize, nText) +{ + varType = nVarType; + varName = nVarName; + isArray = nIsArray; + arrayItemCntStr = nArrayItemCntStr; +} + +Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + size_t nArrayItemCnt, const std::string& nText, bool nIsExternal) + : Declaration(nAddress, nAlignment, nSize, nVarType, nVarName, nIsArray, nArrayItemCnt, nText) +{ + isExternal = nIsExternal; +} + +Declaration::Declaration(offset_t nAddress, const std::string& nIncludePath, size_t nSize, + const std::string& nVarType, const std::string& nVarName) + : Declaration(nAddress, DeclarationAlignment::Align4, nSize, "") +{ + includePath = nIncludePath; + varType = nVarType; + varName = nVarName; +} + +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 (preText != "") + output += preText + "\n"; + + if (IsStatic()) + { + output += "static "; + } + + if (isArray) + { + if (arrayItemCntStr != "" && (IsStatic() || forceArrayCnt)) + { + output += StringHelper::Sprintf("%s %s[%s];\n", varType.c_str(), varName.c_str(), + arrayItemCntStr.c_str()); + } + else if (arrayItemCnt != 0 && (IsStatic() || forceArrayCnt)) + { + output += StringHelper::Sprintf("%s %s[%i] = {\n", varType.c_str(), varName.c_str(), + arrayItemCnt); + } + else + { + output += StringHelper::Sprintf("%s %s[] = {\n", varType.c_str(), varName.c_str()); + } + + output += text + "\n"; + } + else + { + output += StringHelper::Sprintf("%s %s = { ", varType.c_str(), varName.c_str()); + output += text; + } + + if (output.back() == '\n') + output += "};"; + else + output += " };"; + + if (rightText != "") + output += " " + rightText + ""; + + output += "\n"; + + if (postText != "") + output += postText + "\n"; + + output += "\n"; + + return output; +} + +std::string Declaration::GetExternalDeclarationStr() const +{ + std::string output; + + if (preText != "") + output += preText + "\n"; + + if (IsStatic()) + { + output += "static "; + } + + if (arrayItemCntStr != "" && (IsStatic() || forceArrayCnt)) + output += StringHelper::Sprintf("%s %s[%s] = ", varType.c_str(), varName.c_str(), + arrayItemCntStr.c_str()); + else if (arrayItemCnt != 0 && (IsStatic() || forceArrayCnt)) + output += + StringHelper::Sprintf("%s %s[%i] = ", varType.c_str(), varName.c_str(), arrayItemCnt); + else + output += StringHelper::Sprintf("%s %s[] = ", varType.c_str(), varName.c_str()); + + output += StringHelper::Sprintf("{\n#include \"%s\"\n};", includePath.c_str()); + + if (rightText != "") + output += " " + rightText + ""; + + output += "\n"; + + if (postText != "") + output += postText + "\n"; + + output += "\n"; + + return output; +} + +std::string Declaration::GetExternStr() const +{ + if (IsStatic() || varType == "") + { + 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", varType.c_str(), varName.c_str(), + arrayItemCntStr.c_str()); + } + else if (arrayItemCnt != 0 && (IsStatic() || forceArrayCnt)) + { + return StringHelper::Sprintf("extern %s %s[%i];\n", varType.c_str(), varName.c_str(), + arrayItemCnt); + } + else + return StringHelper::Sprintf("extern %s %s[];\n", varType.c_str(), varName.c_str()); + } + + return StringHelper::Sprintf("extern %s %s;\n", varType.c_str(), varName.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", varType.c_str(), varName.c_str(), + arrayItemCntStr.c_str()); + } + else + { + return StringHelper::Sprintf("static %s %s[%i];\n", varType.c_str(), varName.c_str(), + arrayItemCnt); + } + } + + return StringHelper::Sprintf("static %s %s;\n", varType.c_str(), varName.c_str()); +} diff --git a/ZAPDTR/ZAPD/Declaration.h b/ZAPDTR/ZAPD/Declaration.h new file mode 100644 index 000000000..4a743b50f --- /dev/null +++ b/ZAPDTR/ZAPD/Declaration.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include + +// 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 Declaration +{ +public: + offset_t address; + DeclarationAlignment alignment; + size_t size; + std::string preText; + std::string text; + std::string rightText; + std::string postText; + std::string preComment; + std::string postComment; + std::string varType; + std::string varName; + std::string includePath; + + bool isExternal = false; + bool isArray = false; + bool forceArrayCnt = false; + size_t arrayItemCnt = 0; + std::string arrayItemCntStr = ""; + std::vector references; + bool isUnaccounted = false; + bool isPlaceholder = false; + bool declaredInXml = false; + StaticConfig staticConf = StaticConfig::Global; + + Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + const std::string& nText); + Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + size_t nArrayItemCnt, const std::string& nText); + Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + const std::string& nArrayItemCntStr, const std::string& nText); + Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nVarType, const std::string& nVarName, bool nIsArray, + size_t nArrayItemCnt, const std::string& nText, bool nIsExternal); + + Declaration(offset_t nAddress, const std::string& nIncludePath, size_t nSize, + const std::string& nVarType, const std::string& nVarName); + + bool IsStatic() const; + + std::string GetNormalDeclarationStr() const; + std::string GetExternalDeclarationStr() const; + + std::string GetExternStr() const; + + std::string GetStaticForwardDeclarationStr() const; + +protected: + Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize, + const std::string& nText); +}; diff --git a/ZAPDTR/ZAPD/GameConfig.cpp b/ZAPDTR/ZAPD/GameConfig.cpp new file mode 100644 index 000000000..ae29ba28f --- /dev/null +++ b/ZAPDTR/ZAPD/GameConfig.cpp @@ -0,0 +1,184 @@ +#include "GameConfig.h" + +#include +#include + +#include "Utils/Directory.h" +#include "Utils/File.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 = File::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 lines = + File::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 lines = + File::ReadAllLines(Path::GetDirectoryName(configFilePath) / fileName); + + for (auto& line : lines) + objectList.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); +} + +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::ReadConfigFile(const fs::path& argConfigFilePath) +{ + static const std::map ConfigFuncDictionary = { + {"SymbolMap", &GameConfig::ConfigFunc_SymbolMap}, + {"ActorList", &GameConfig::ConfigFunc_ActorList}, + {"ObjectList", &GameConfig::ConfigFunc_ObjectList}, + {"TexturePool", &GameConfig::ConfigFunc_TexturePool}, + {"BGConfig", &GameConfig::ConfigFunc_BGConfig}, + {"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); + } +} diff --git a/ZAPDTR/ZAPD/GameConfig.h b/ZAPDTR/ZAPD/GameConfig.h new file mode 100644 index 000000000..c478d16ce --- /dev/null +++ b/ZAPDTR/ZAPD/GameConfig.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include + +#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); +}; + +class ZFile; + +class GameConfig +{ +public: + std::string configFilePath; + std::map> segmentRefFiles; + std::map symbolMap; + std::vector actorList; + std::vector objectList; + std::map texturePool; // Key = CRC + + // ZBackground + uint32_t bgScreenWidth = 320, bgScreenHeight = 240; + + // ExternalFile + fs::path externalXmlFolder; + std::vector 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_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 ReadConfigFile(const fs::path& configFilePath); +}; diff --git a/ZAPDTR/ZAPD/Globals.cpp b/ZAPDTR/ZAPD/Globals.cpp new file mode 100644 index 000000000..0902b2c9e --- /dev/null +++ b/ZAPDTR/ZAPD/Globals.cpp @@ -0,0 +1,225 @@ +#include "Globals.h" + +#include +#include + +#include "Utils/File.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; + verbosity = VerbosityLevel::VERBOSITY_SILENT; + outputPath = Directory::GetCurrentDirectory(); +} + +Globals::~Globals() +{ + auto& exporters = GetExporterMap(); + + for (auto& it : exporters) + { + delete it.second; + } +} + +void Globals::AddSegment(int32_t segment, ZFile* file) +{ + if (std::find(segments.begin(), segments.end(), segment) == segments.end()) + segments.push_back(segment); + if (cfg.segmentRefFiles.find(segment) == cfg.segmentRefFiles.end()) + cfg.segmentRefFiles[segment] = std::vector(); + + cfg.segmentRefFiles[segment].push_back(file); +} + +bool Globals::HasSegment(int32_t segment) +{ + return std::find(segments.begin(), segments.end(), segment) != segments.end(); +} + +ZFile* Globals::GetSegment(int32_t segment) +{ + if (HasSegment(segment)) + { + int idx = std::find(segments.begin(), segments.end(), segment) - segments.begin(); + return files[idx]; + } + else + return nullptr; +} + +std::map& Globals::GetExporterMap() +{ + static std::map 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; +} + +bool Globals::GetSegmentedPtrName(segptr_t segAddress, ZFile* currentFile, + const std::string& expectedType, std::string& declName) +{ + if (segAddress == 0) + { + 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)) + { + for (auto file : cfg.segmentRefFiles[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); + return false; +} + +bool Globals::GetSegmentedArrayIndexedName(segptr_t segAddress, size_t elementSize, + ZFile* currentFile, const std::string& expectedType, + std::string& declName) +{ + if (segAddress == 0) + { + 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)) + { + for (auto file : cfg.segmentRefFiles[segment]) + { + if (file->IsSegmentedInFilespaceRange(segAddress)) + { + bool addressFound = file->GetDeclarationArrayIndexedName(segAddress, elementSize, + expectedType, declName); + if (addressFound) + return true; + } + } + } + + declName = StringHelper::Sprintf("0x%08X", segAddress); + return false; +} + +ExternalFile::ExternalFile(fs::path nXmlPath, fs::path nOutPath) + : xmlPath{nXmlPath}, outPath{nOutPath} +{ +} + +ExporterSet::~ExporterSet() +{ + for (auto& it : exporters) + { + delete it.second; + } +} diff --git a/ZAPDTR/ZAPD/Globals.h b/ZAPDTR/ZAPD/Globals.h new file mode 100644 index 000000000..140de1f24 --- /dev/null +++ b/ZAPDTR/ZAPD/Globals.h @@ -0,0 +1,95 @@ +#pragma once + +#include +#include +#include +#include "GameConfig.h" +#include "ZFile.h" + +class ZRoom; + +enum class VerbosityLevel +{ + VERBOSITY_SILENT, + VERBOSITY_INFO, + VERBOSITY_DEBUG +}; + +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 (*ExporterSetResSave)(ZResource* res, BinaryWriter& writer); + +class ExporterSet +{ +public: + ~ExporterSet(); + + std::map 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; +}; + +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; + VerbosityLevel verbosity; // ZAPD outputs additional information + ZFileMode fileMode; + fs::path baseRomPath, inputPath, outputPath, sourceOutputPath, cfgPath; + TextureType texType; + ZGame game; + GameConfig cfg; + bool verboseUnaccounted = false; + bool gccCompat = false; + bool forceStatic = false; + bool forceUnaccountedStatic = false; + bool otrMode = true; + + std::vector files; + std::vector externalFiles; + std::vector segments; + + std::string currentExporter; + static std::map& GetExporterMap(); + static void AddExporter(std::string exporterName, ExporterSet* exporterSet); + + Globals(); + ~Globals(); + + void AddSegment(int32_t segment, ZFile* file); + bool HasSegment(int32_t segment); + ZFile* GetSegment(int32_t segment); + + ZResourceExporter* GetExporter(ZResourceType resType); + ExporterSet* GetExporterSet(); + + /** + * 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); + + bool GetSegmentedArrayIndexedName(segptr_t segAddress, size_t elementSize, ZFile* currentFile, + const std::string& expectedType, std::string& declName); +}; diff --git a/ZAPDTR/ZAPD/ImageBackend.cpp b/ZAPDTR/ZAPD/ImageBackend.cpp new file mode 100644 index 000000000..8accb6b4e --- /dev/null +++ b/ZAPDTR/ZAPD/ImageBackend.cpp @@ -0,0 +1,506 @@ +#include "ImageBackend.h" + +#include +#include +#include +#include + +#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.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(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>& 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(malloc(sizeof(uint8_t*) * height)); + for (size_t y = 0; y < height; y++) + { + pixelMatrix[y] = static_cast(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(malloc(sizeof(uint8_t*) * height)); + for (size_t y = 0; y < height; y++) + { + pixelMatrix[y] = static_cast(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(calloc(width * bytePerPixel, sizeof(uint8_t*))); + } + colorPalette = calloc(paletteSize, sizeof(png_color)); + alphaPalette = static_cast(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(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(colorPalette); + pal[index].red = nR; + pal[index].green = nG; + pal[index].blue = nB; + alphaPalette[index] = nA; +} + +void ImageBackend::SetPalette(const ImageBackend& pal) +{ + 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, 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; +} diff --git a/ZAPDTR/ZAPD/ImageBackend.h b/ZAPDTR/ZAPD/ImageBackend.h new file mode 100644 index 000000000..9e05a2eed --- /dev/null +++ b/ZAPDTR/ZAPD/ImageBackend.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#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>& 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 SetPaletteIndex(size_t index, uint8_t nR, uint8_t nG, uint8_t nB, uint8_t nA); + void SetPalette(const ImageBackend& pal); + + 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(); +}; diff --git a/ZAPDTR/ZAPD/Main.cpp b/ZAPDTR/ZAPD/Main.cpp new file mode 100644 index 000000000..440f6d504 --- /dev/null +++ b/ZAPDTR/ZAPD/Main.cpp @@ -0,0 +1,471 @@ +#include "Globals.h" +#include "Overlays/ZOverlay.h" +#include "Utils/Directory.h" +#include "Utils/File.h" +#include "Utils/Path.h" +#include "WarningHandler.h" +#include "ZAnimation.h" +#include "ZBackground.h" +#include "ZBlob.h" +#include "ZFile.h" +#include "ZTexture.h" + +#if !defined(_MSC_VER) && !defined(__CYGWIN__) +#include +#include +#include +#include // for __cxa_demangle +#include // for dladdr +#include +#include +#endif + +#include +#include +#include "tinyxml2.h" + +//extern const char gBuildHash[]; +const char gBuildHash[] = ""; + +bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath, + ZFileMode fileMode); + +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); + +#if !defined(_MSC_VER) && !defined(__CYGWIN__) +#define ARRAY_COUNT(arr) (sizeof(arr) / sizeof(arr[0])) +void ErrorHandler(int sig) +{ + void* array[4096]; + const size_t nMaxFrames = sizeof(array) / sizeof(array[0]); + size_t size = backtrace(array, nMaxFrames); + char** symbols = backtrace_symbols(array, nMaxFrames); + + fprintf(stderr, "\nZAPD crashed. (Signal: %i)\n", sig); + + // Feel free to add more crash messages. + const char* 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.", + }; + + srand(time(nullptr)); + auto easterIndex = rand() % ARRAY_COUNT(crashEasterEgg); + + 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(array[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*)array[i] - (char*)info.dli_saddr); + free(demangled); + } + + fprintf(stderr, "%-3zd %s\n", i, functionName.c_str()); + } + + fprintf(stderr, "\n"); + + free(symbols); + exit(1); +} +#endif + +int main(int argc, char* argv[]) +{ + // Syntax: ZAPD.out [mode (btex/bovl/e)] (Arbritrary Number of Arguments) + + 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; + } + } + + // Parse other "commands" + for (int32_t i = 2; i < argc; i++) + { + std::string arg = argv[i]; + + if (arg == "-o" || arg == "--outputpath") // Set output path + { + Globals::Instance->outputPath = argv[++i]; + + if (Globals::Instance->sourceOutputPath == "") + Globals::Instance->sourceOutputPath = Globals::Instance->outputPath; + } + else if (arg == "-i" || arg == "--inputpath") // Set input path + { + Globals::Instance->inputPath = argv[++i]; + } + else if (arg == "-b" || arg == "--baserompath") // Set baserom path + { + Globals::Instance->baseRomPath = argv[++i]; + } + else if (arg == "-osf") // Set source output path + { + Globals::Instance->sourceOutputPath = argv[++i]; + } + else if (arg == "-gsf") // Generate source file during extraction + { + Globals::Instance->genSourceFile = std::string_view(argv[++i]) == "1"; + } + else if (arg == "-tm") // Test Mode (enables certain experimental features) + { + Globals::Instance->testMode = std::string_view(argv[++i]) == "1"; + } + else if (arg == "-crc" || + arg == "--output-crc") // Outputs a CRC file for each extracted texture. + { + Globals::Instance->testMode = std::string_view(argv[++i]) == "1"; + } + else if (arg == "-ulzdl") // Use Legacy ZDisplay List + { + Globals::Instance->useLegacyZDList = std::string_view(argv[++i]) == "1"; + } + else if (arg == "-profile") // Enable profiling + { + Globals::Instance->profile = std::string_view(argv[++i]) == "1"; + } + else if (arg == + "-uer") // 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"; + } + else if (arg == "-tt") // Set texture type + { + Globals::Instance->texType = ZTexture::GetTextureTypeFromString(argv[++i]); + } + else if (arg == "-cfg") // Set cfg path (for overlays) + // TODO: Change the name of this to something else so it doesn't + // get confused with XML config files. + { + Globals::Instance->cfgPath = argv[++i]; + } + else if (arg == "-rconf") // Read Config File + { + Globals::Instance->cfg.ReadConfigFile(argv[++i]); + } + else if (arg == "-eh") // Enable Error Handler + { +#if !defined(_MSC_VER) && !defined(__CYGWIN__) + signal(SIGSEGV, ErrorHandler); + signal(SIGABRT, ErrorHandler); +#else + HANDLE_WARNING(WarningType::Always, + "tried to set error handler, but this ZAPD build lacks support for one", + ""); +#endif + } + else if (arg == "-v") // Verbose + { + Globals::Instance->verbosity = static_cast(strtol(argv[++i], NULL, 16)); + } + else if (arg == "-vu" || arg == "--verbose-unaccounted") // Verbose unaccounted + { + Globals::Instance->verboseUnaccounted = true; + } + else if (arg == "-se" || arg == "--set-exporter") // Set Current Exporter + { + Globals::Instance->currentExporter = argv[++i]; + } + else if (arg == "--gcc-compat") // GCC compatibility + { + Globals::Instance->gccCompat = true; + } + else if (arg == "-s" || arg == "--static") + { + Globals::Instance->forceStatic = true; + } + else if (arg == "-us" || arg == "--unaccounted-static") + { + Globals::Instance->forceUnaccountedStatic = true; + } + } + + // Parse File Mode + ExporterSet* exporterSet = Globals::Instance->GetExporterSet(); + std::string buildMode = argv[1]; + ZFileMode fileMode = ZFileMode::Invalid; + + if (buildMode == "btex") + fileMode = ZFileMode::BuildTexture; + else if (buildMode == "bren") + fileMode = ZFileMode::BuildBackground; + else if (buildMode == "bovl") + fileMode = ZFileMode::BuildOverlay; + else if (buildMode == "bsf") + fileMode = ZFileMode::BuildSourceFile; + else if (buildMode == "bblb") + fileMode = ZFileMode::BuildBlob; + else if (buildMode == "e") + fileMode = ZFileMode::Extract; + else if (exporterSet != nullptr && exporterSet->parseFileModeFunc != nullptr) + exporterSet->parseFileModeFunc(buildMode, fileMode); + + if (fileMode == ZFileMode::Invalid) + { + printf("Error: Invalid file mode '%s'\n", buildMode.c_str()); + return 1; + } + + // 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->verbosity >= VerbosityLevel::VERBOSITY_INFO) + printf("ZAPD: Zelda Asset Processor For Decomp: %s\n", gBuildHash); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + { + WarningHandler::PrintWarningsDebugInfo(); + } + + // TODO: switch + if (fileMode == ZFileMode::Extract || fileMode == ZFileMode::BuildSourceFile) + { + bool procFileModeSuccess = false; + + if (exporterSet != nullptr && exporterSet->processFileModeFunc != nullptr) + procFileModeSuccess = exporterSet->processFileModeFunc(fileMode); + + if (!procFileModeSuccess) + { + bool parseSuccessful; + + 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); + + if (!parseSuccessful) + return 1; + } + + parseSuccessful = Parse(Globals::Instance->inputPath, Globals::Instance->baseRomPath, + Globals::Instance->outputPath, fileMode); + if (!parseSuccessful) + return 1; + } + } + else if (fileMode == ZFileMode::BuildTexture) + { + TextureType texType = Globals::Instance->texType; + BuildAssetTexture(Globals::Instance->inputPath, 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); + } + else if (fileMode == ZFileMode::BuildOverlay) + { + ZOverlay* overlay = + ZOverlay::FromBuild(Path::GetDirectoryName(Globals::Instance->inputPath), + Path::GetDirectoryName(Globals::Instance->cfgPath)); + + if (overlay != nullptr) + File::WriteAllText(Globals::Instance->outputPath.string(), + overlay->GetSourceOutputCode("")); + } + + delete g; + return 0; +} + +bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath, + ZFileMode fileMode) +{ + 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); + Globals::Instance->files.push_back(file); + if (fileMode == ZFileMode::ExternalFile) + { + Globals::Instance->externalFiles.push_back(file); + 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); + } + 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(); + + for (ZFile* file : Globals::Instance->files) + { + if (fileMode == ZFileMode::BuildSourceFile) + file->BuildSourceFile(); + else + file->ExtractResources(); + } + + if (exporterSet != nullptr && exporterSet->endXMLFunc != nullptr) + exporterSet->endXMLFunc(); + } + + return true; +} + +void 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 (File::Exists(cfgPath)) + name = File::ReadAllText(cfgPath); + + std::string src = tex.GetBodySourceCode(); + + File::WriteAllText(outPath.string(), src); +} + +void BuildAssetBackground(const fs::path& imageFilePath, const fs::path& outPath) +{ + ZBackground background(nullptr); + background.ParseBinaryFile(imageFilePath.string(), false); + + File::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(); + + File::WriteAllText(outPath.string(), src); + + delete blob; +} diff --git a/ZAPDTR/ZAPD/NuGet/libpng.static.txt b/ZAPDTR/ZAPD/NuGet/libpng.static.txt new file mode 100644 index 000000000..e69de29bb diff --git a/ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.cpp b/ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.cpp new file mode 100644 index 000000000..8ce215c97 --- /dev/null +++ b/ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.cpp @@ -0,0 +1,343 @@ +#include "SkinLimbStructs.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZDisplayList.h" +#include "ZFile.h" + +/* Struct_800A57C0 */ + +Struct_800A57C0::Struct_800A57C0(ZFile* nParent) : ZResource(nParent) +{ +} + +void Struct_800A57C0::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + unk_0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x00); + unk_2 = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x02); + unk_4 = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x04); + unk_6 = BitConverter::ToInt8BE(rawData, rawDataIndex + 0x06); + unk_7 = BitConverter::ToInt8BE(rawData, rawDataIndex + 0x07); + unk_8 = BitConverter::ToInt8BE(rawData, rawDataIndex + 0x08); + unk_9 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x09); +} + +std::string Struct_800A57C0::GetBodySourceCode() const +{ + return StringHelper::Sprintf("0x%02X, %i, %i, %i, %i, %i, 0x%02X", unk_0, unk_2, unk_4, unk_6, + unk_7, unk_8, unk_9); +} + +std::string Struct_800A57C0::GetSourceTypeName() const +{ + return "Struct_800A57C0"; +} + +ZResourceType Struct_800A57C0::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +size_t Struct_800A57C0::GetRawDataSize() const +{ + return 0x0A; +} + +/* Struct_800A598C_2 */ + +Struct_800A598C_2::Struct_800A598C_2(ZFile* nParent) : ZResource(nParent) +{ +} + +void Struct_800A598C_2::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + unk_0 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x00); + x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x02); + y = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x04); + z = BitConverter::ToInt16BE(rawData, rawDataIndex + 0x06); + unk_8 = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x08); +} + +std::string Struct_800A598C_2::GetBodySourceCode() const +{ + return StringHelper::Sprintf("0x%02X, %i, %i, %i, 0x%02X", unk_0, x, y, z, unk_8); +} + +std::string Struct_800A598C_2::GetSourceTypeName() const +{ + return "Struct_800A598C_2"; +} + +ZResourceType Struct_800A598C_2::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +size_t Struct_800A598C_2::GetRawDataSize() const +{ + return 0x0A; +} + +/* Struct_800A598C */ + +Struct_800A598C::Struct_800A598C(ZFile* nParent) : ZResource(nParent) +{ +} + +void Struct_800A598C::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + unk_0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x00); + unk_2 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x02); + unk_4 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x04); + unk_8 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x08); + unk_C = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0C); + + if (unk_8 != 0 && GETSEGNUM(unk_8) == parent->segment) + { + uint32_t unk_8_Offset = Seg2Filespace(unk_8, parent->baseAddress); + for (size_t i = 0; i < unk_0; i++) + { + Struct_800A57C0 unk8_data(parent); + unk8_data.ExtractFromFile(unk_8_Offset); + unk_8_arr.push_back(unk8_data); + + unk_8_Offset += unk8_data.GetRawDataSize(); + } + } + + if (unk_C != 0 && GETSEGNUM(unk_8) == parent->segment) + { + uint32_t unk_C_Offset = Seg2Filespace(unk_C, parent->baseAddress); + for (size_t i = 0; i < unk_2; i++) + { + Struct_800A598C_2 unkC_data(parent); + unkC_data.ExtractFromFile(unk_C_Offset); + unk_C_arr.push_back(unkC_data); + + unk_C_Offset += unkC_data.GetRawDataSize(); + } + } +} + +void Struct_800A598C::DeclareReferences(const std::string& prefix) +{ + std::string varPrefix = prefix; + if (name != "") + varPrefix = name; + + if (unk_8 != 0 && GETSEGNUM(unk_8) == parent->segment) + { + const auto& res = unk_8_arr.at(0); + std::string unk_8_Str = res.GetDefaultName(varPrefix); + + size_t arrayItemCnt = unk_8_arr.size(); + std::string entryStr = ""; + + for (size_t i = 0; i < arrayItemCnt; i++) + { + auto& child = unk_8_arr[i]; + child.DeclareReferences(varPrefix); + entryStr += StringHelper::Sprintf("\t{ %s },", child.GetBodySourceCode().c_str()); + + if (i < arrayItemCnt - 1) + entryStr += "\n"; + } + + uint32_t unk_8_Offset = Seg2Filespace(unk_8, parent->baseAddress); + Declaration* decl = parent->GetDeclaration(unk_8_Offset); + if (decl == nullptr) + { + parent->AddDeclarationArray(unk_8_Offset, res.GetDeclarationAlignment(), + arrayItemCnt * res.GetRawDataSize(), + res.GetSourceTypeName(), unk_8_Str, arrayItemCnt, entryStr); + } + else + decl->text = entryStr; + } + + if (unk_C != 0 && GETSEGNUM(unk_C) == parent->segment) + { + const auto& res = unk_C_arr.at(0); + std::string unk_C_Str = res.GetDefaultName(varPrefix); + + size_t arrayItemCnt = unk_C_arr.size(); + std::string entryStr = ""; + + for (size_t i = 0; i < arrayItemCnt; i++) + { + auto& child = unk_C_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(unk_C, 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->text = entryStr; + } +} + +std::string Struct_800A598C::GetBodySourceCode() const +{ + std::string unk_8_Str; + std::string unk_C_Str; + Globals::Instance->GetSegmentedPtrName(unk_8, parent, "Struct_800A57C0", unk_8_Str); + Globals::Instance->GetSegmentedPtrName(unk_C, parent, "Struct_800A598C_2", unk_C_Str); + + std::string entryStr = StringHelper::Sprintf("\n\t\tARRAY_COUNTU(%s), ARRAY_COUNTU(%s),\n", + unk_8_Str.c_str(), unk_C_Str.c_str()); + entryStr += + StringHelper::Sprintf("\t\t%i, %s, %s\n\t", unk_4, unk_8_Str.c_str(), unk_C_Str.c_str()); + + return entryStr; +} + +std::string Struct_800A598C::GetSourceTypeName() const +{ + return "Struct_800A598C"; +} + +ZResourceType Struct_800A598C::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +size_t Struct_800A598C::GetRawDataSize() const +{ + return 0x10; +} + +/* Struct_800A5E28 */ + +Struct_800A5E28::Struct_800A5E28(ZFile* nParent) : ZResource(nParent) +{ +} + +void Struct_800A5E28::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + unk_0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x00); + unk_2 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x02); + unk_4 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x04); + unk_8 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x08); + + if (unk_4 != 0 && GETSEGNUM(unk_4) == parent->segment) + { + uint32_t unk_4_Offset = Seg2Filespace(unk_4, parent->baseAddress); + for (size_t i = 0; i < unk_2; i++) + { + Struct_800A598C unk_4_data(parent); + unk_4_data.ExtractFromFile(unk_4_Offset); + unk_4_arr.push_back(unk_4_data); + + unk_4_Offset += unk_4_data.GetRawDataSize(); + } + } +} + +void Struct_800A5E28::DeclareReferences(const std::string& prefix) +{ + std::string varPrefix = prefix; + if (name != "") + varPrefix = name; + + ZResource::DeclareReferences(varPrefix); + + if (unk_4 != SEGMENTED_NULL && GETSEGNUM(unk_4) == parent->segment) + { + const auto& res = unk_4_arr.at(0); + std::string unk_4_Str = res.GetDefaultName(varPrefix); + + size_t arrayItemCnt = unk_4_arr.size(); + std::string entryStr = ""; + + for (size_t i = 0; i < arrayItemCnt; i++) + { + auto& child = unk_4_arr[i]; + child.DeclareReferences(varPrefix); + entryStr += StringHelper::Sprintf("\t{ %s },", child.GetBodySourceCode().c_str()); + + if (i < arrayItemCnt - 1) + entryStr += "\n"; + } + + uint32_t unk_4_Offset = Seg2Filespace(unk_4, parent->baseAddress); + Declaration* decl = parent->GetDeclaration(unk_4_Offset); + if (decl == nullptr) + { + parent->AddDeclarationArray(unk_4_Offset, res.GetDeclarationAlignment(), + arrayItemCnt * res.GetRawDataSize(), + res.GetSourceTypeName(), unk_4_Str, arrayItemCnt, entryStr); + } + else + decl->text = entryStr; + } + + if (unk_8 != SEGMENTED_NULL && GETSEGNUM(unk_8) == parent->segment) + { + uint32_t unk_8_Offset = Seg2Filespace(unk_8, parent->baseAddress); + + int32_t dlistLength = ZDisplayList::GetDListLength( + parent->GetRawData(), unk_8_Offset, + Globals::Instance->game == ZGame::OOT_SW97 ? DListType::F3DEX : DListType::F3DZEX); + unk_8_dlist = new ZDisplayList(parent); + unk_8_dlist->ExtractFromBinary(unk_8_Offset, dlistLength); + + std::string dListStr = + StringHelper::Sprintf("%sSkinLimbDL_%06X", varPrefix.c_str(), unk_8_Offset); + unk_8_dlist->SetName(dListStr); + unk_8_dlist->DeclareVar(varPrefix, ""); + unk_8_dlist->DeclareReferences(varPrefix); + parent->AddResource(unk_8_dlist); + } +} + +std::string Struct_800A5E28::GetBodySourceCode() const +{ + std::string unk_4_Str; + std::string unk_8_Str; + Globals::Instance->GetSegmentedPtrName(unk_4, parent, "Struct_800A598C", unk_4_Str); + Globals::Instance->GetSegmentedPtrName(unk_8, parent, "Gfx", unk_8_Str); + + std::string entryStr = "\n"; + entryStr += StringHelper::Sprintf("\t%i, ARRAY_COUNTU(%s),\n", unk_0, unk_4_Str.c_str()); + entryStr += StringHelper::Sprintf("\t%s, %s\n", unk_4_Str.c_str(), unk_8_Str.c_str()); + + return entryStr; +} + +std::string Struct_800A5E28::GetSourceTypeName() const +{ + return "Struct_800A5E28"; +} + +ZResourceType Struct_800A5E28::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +size_t Struct_800A5E28::GetRawDataSize() const +{ + return 0x0C; +} diff --git a/ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.h b/ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.h new file mode 100644 index 000000000..ce842aee3 --- /dev/null +++ b/ZAPDTR/ZAPD/OtherStructs/SkinLimbStructs.h @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include + +#include "ZResource.h" +#include "ZDisplayList.h" + +// TODO: check if more types exists +enum class ZLimbSkinType +{ + SkinType_0, // Segment = 0 + SkinType_4 = 4, // Segment = segmented address // Struct_800A5E28 + SkinType_5 = 5, // Segment = 0 + SkinType_DList = 11, // Segment = DList address +}; + +class Struct_800A57C0 : public ZResource +{ +public: + Struct_800A57C0(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 unk_0; + int16_t unk_2; + int16_t unk_4; + int8_t unk_6; + int8_t unk_7; + int8_t unk_8; + uint8_t unk_9; +}; + +class Struct_800A598C_2 : public ZResource +{ +public: + Struct_800A598C_2(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 unk_0; + int16_t x; + int16_t y; + int16_t z; + uint8_t unk_8; +}; + +class Struct_800A598C : public ZResource +{ +public: + Struct_800A598C(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 unk_0; // Length of unk_8 + uint16_t unk_2; // Length of unk_C + uint16_t unk_4; // 0 or 1 // Used as an index for unk_C + segptr_t unk_8; // Struct_800A57C0* + segptr_t unk_C; // Struct_800A598C_2* + + std::vector unk_8_arr; + std::vector unk_C_arr; +}; + +class Struct_800A5E28 : public ZResource +{ +public: + Struct_800A5E28(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 unk_0; // Vtx count + uint16_t unk_2; // Length of unk_4 + segptr_t unk_4; // Struct_800A598C* + segptr_t unk_8; // Gfx* + + std::vector unk_4_arr; + ZDisplayList* unk_8_dlist = nullptr; +}; diff --git a/ZAPDTR/ZAPD/OutputFormatter.cpp b/ZAPDTR/ZAPD/OutputFormatter.cpp new file mode 100644 index 000000000..dbb8692c0 --- /dev/null +++ b/ZAPDTR/ZAPD/OutputFormatter.cpp @@ -0,0 +1,119 @@ +#include "OutputFormatter.h" +#include + +void OutputFormatter::Flush() +{ + //if (!Globals::Instance->otrMode) + { + 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) +{ + 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()); +} + +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); +} diff --git a/ZAPDTR/ZAPD/OutputFormatter.h b/ZAPDTR/ZAPD/OutputFormatter.h new file mode 100644 index 000000000..28955b1cd --- /dev/null +++ b/ZAPDTR/ZAPD/OutputFormatter.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +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 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(); +}; diff --git a/ZAPDTR/ZAPD/Overlays/ZOverlay.cpp b/ZAPDTR/ZAPD/Overlays/ZOverlay.cpp new file mode 100644 index 000000000..113c4ef33 --- /dev/null +++ b/ZAPDTR/ZAPD/Overlays/ZOverlay.cpp @@ -0,0 +1,352 @@ +#include "ZOverlay.h" + +#include +#include +#include "Globals.h" +#include "Utils/Directory.h" +#include "Utils/File.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(); +} + +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 sRelSections = { + ".rel.text", + ".rel.data", + ".rel.rodata", +}; +static const std::unordered_set sSections = { + ".text", ".data", ".symtab", ".rodata", ".rodata.str1.4", ".rodata.cst4", ".rodata.cst8", +}; + +ZOverlay* ZOverlay::FromBuild(fs::path buildPath, fs::path cfgFolderPath) +{ + std::string cfgText = File::ReadAllText(cfgFolderPath / "overlay.cfg"); + std::vector cfgLines = StringHelper::Split(cfgText, "\n"); + + ZOverlay* ovl = new ZOverlay(StringHelper::Strip(cfgLines[0], "\r")); + ovl->cfgLines = cfgLines; + + int32_t sectionOffs[5] = {0}; + std::vector textRelocs; + std::vector dataRelocs; + std::vector rodataRelocs; + + // get the elf files + std::vector 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(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(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; +} diff --git a/ZAPDTR/ZAPD/Overlays/ZOverlay.h b/ZAPDTR/ZAPD/Overlays/ZOverlay.h new file mode 100644 index 000000000..98ead9013 --- /dev/null +++ b/ZAPDTR/ZAPD/Overlays/ZOverlay.h @@ -0,0 +1,75 @@ +#pragma once + +#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(sectionType) << 30; + relocationWord |= static_cast(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 entries; + std::vector 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); +}; diff --git a/ZAPDTR/ZAPD/WarningHandler.cpp b/ZAPDTR/ZAPD/WarningHandler.cpp new file mode 100644 index 000000000..29f8352a7 --- /dev/null +++ b/ZAPDTR/ZAPD/WarningHandler.cpp @@ -0,0 +1,443 @@ +/** + * 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 +#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 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-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 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(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(warnType) >= 0 && warnType < WarningType::Max); + + return warningTypeToInfoMap.at(warnType).level != WarningLevel::Off; +} + +bool WarningHandler::WasElevatedToError(WarningType warnType) { + assert(static_cast(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) { + if (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()); + } + fprintf(stderr, "offset 0x%06X: \n\t", offset); +} + +/** + * 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 + +/** + * Print each warning name, default status, and description using the init map + */ +void WarningHandler::PrintHelp() { + std::set 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"); +} diff --git a/ZAPDTR/ZAPD/WarningHandler.h b/ZAPDTR/ZAPD/WarningHandler.h new file mode 100644 index 000000000..bb0360a81 --- /dev/null +++ b/ZAPDTR/ZAPD/WarningHandler.h @@ -0,0 +1,145 @@ +#pragma once + +#include +#include +#include +#include + +#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, + 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(); +}; diff --git a/ZAPDTR/ZAPD/ZAPD.vcxproj b/ZAPDTR/ZAPD/ZAPD.vcxproj new file mode 100644 index 000000000..95e89d8ff --- /dev/null +++ b/ZAPDTR/ZAPD/ZAPD.vcxproj @@ -0,0 +1,356 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36} + ZAPD + 10.0 + ZAPD + + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(OutDir);$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\..\OTRExporter\packages\libpng-v142.1.6.37.2\build\native\lib\x64\v142\Debug\;$(ProjectDir)..\..\libultraship\libultraship\;$(LibraryPath) + $(ProjectDir)..\ZAPDUtils;$(ProjectDir)..\lib\tinyxml2;$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\lib\elfio;$(ProjectDir)..\lib\stb;$(ProjectDir);$(IncludePath) + + + $(ProjectDir)..\ZAPDUtils;$(ProjectDir)..\lib\tinyxml2;$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\lib\elfio;$(ProjectDir)..\lib\stb;$(ProjectDir);$(IncludePath) + $(OutDir);$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\..\OTRExporter\packages\libpng-v142.1.6.37.2\build\native\lib\x64\v142\Debug\;$(ProjectDir)..\..\libultraship\libultraship\;$(LibraryPath) + false + + + $(SolutionDir)ZAPD\lib\tinyxml2;$(SolutionDir)ZAPD\lib\libgfxd;$(SolutionDir)ZAPD\lib\elfio;$(SolutionDir)ZAPD\lib\stb;$(ProjectDir);$(IncludePath) + $(SolutionDir)ZAPD\lib\libgfxd;$(SolutionDir)x64\Debug;$(SolutionDir)packages\libpng.1.6.28.1\build\native\lib\x64\v140\dynamic\Debug;$(LibraryPath) + + + + Level3 + Disabled + true + true + stdcpp17 + stdc11 + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + + + + + Level3 + Disabled + true + true + stdcpp17 + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + stdc11 + MultiThreadedDebug + + + true + ZAPDUtils.lib;/WHOLEARCHIVE:OTRExporter.lib;libultraship.lib;%(AdditionalDependencies) + false + + + + + + + + + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + Level3 + true + true + true + true + stdcpp17 + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + stdc11 + + + true + true + ZAPDUtils.lib;/WHOLEARCHIVE:OTRExporter.lib;libultraship.lib;%(AdditionalDependencies) + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + \ No newline at end of file diff --git a/ZAPDTR/ZAPD/ZAPD.vcxproj.filters b/ZAPDTR/ZAPD/ZAPD.vcxproj.filters new file mode 100644 index 000000000..2a004bf9d --- /dev/null +++ b/ZAPDTR/ZAPD/ZAPD.vcxproj.filters @@ -0,0 +1,557 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {02148456-5068-4613-8478-f10addc58e70} + + + {bcab3136-95ba-4839-833c-43d78ad6e335} + + + {dc06ed84-f6fe-4277-80f3-d62bd5cdbb98} + + + {6049c045-bc38-4221-b29e-ca6d4d8af4aa} + + + {490e3a08-047b-48d3-ab53-3a860a3b92aa} + + + {26c06845-8e8e-4b79-ad18-07c4f9c0f801} + + + {d45c420d-2378-47ac-92c5-80db9475c195} + + + {03cc56a2-e0e8-4167-80a0-98fb900a959a} + + + {73db0879-6df8-4f6a-8cc2-a1f836e9e796} + + + {be9a5be0-ec6a-4200-8e39-bb58c7da7aa8} + + + {7ee79d97-c6a8-4e82-93ef-37981f4d7838} + + + {85600275-99fe-491d-8189-bcc3dc1a8903} + + + {ba9990b0-1082-48bb-874c-6108534b5455} + + + {ce9d91b0-ba20-4296-bc2d-8630965bb392} + + + {730beb67-6d59-4849-9d9b-702c4a565fc0} + + + + + Source Files + + + Source Files\Z64\ZRoom + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files + + + Source Files\Z64 + + + Source Files\Libraries\libgfxd + + + Source Files\Libraries\libgfxd + + + Source Files\Libraries\libgfxd + + + Source Files\Libraries\libgfxd + + + Source Files\Libraries\libgfxd + + + Source Files\Libraries\libgfxd + + + Source Files\Libraries\libgfxd + + + Source Files\Z64 + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64\ZRoom\Commands + + + Source Files\Z64 + + + Source Files + + + Source Files + + + Source Files\Z64 + + + Source Files + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files\Z64 + + + Source Files + + + Source Files\Z64 + + + + + Header Files\Z64\ZRoom + + + Header Files\Z64\ZRoom + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files\Libraries\elfio + + + Header Files + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Libraries + + + Header Files\Libraries + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files + + + Header Files\Z64 + + + Header Files + + + Header Files\Z64 + + + Header Files\Libraries\libgfxd + + + Header Files\Libraries\libgfxd + + + Header Files\Libraries\libgfxd + + + Header Files\Z64 + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64\ZRoom\Commands + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64\ZRoom\Commands + + + Header Files + + + Header Files\Z64 + + + Header Files + + + Header Files\Z64 + + + Header Files + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files\Z64 + + + Header Files + + + Header Files\Z64 + + + + + Resource Files + + + any\any + + + NuGet + + + + + + \ No newline at end of file diff --git a/ZAPDTR/ZAPD/ZAnimation.cpp b/ZAPDTR/ZAPD/ZAnimation.cpp new file mode 100644 index 000000000..dced31aff --- /dev/null +++ b/ZAPDTR/ZAPD/ZAnimation.cpp @@ -0,0 +1,569 @@ +#include "ZAnimation.h" + +#include + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/File.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(); + + const uint8_t* data = parent->GetRawData().data(); + + 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; + + 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); + + 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); + std::string jointIndicesName; + Globals::Instance->GetSegmentedPtrName(rotationIndicesSeg, parent, "JointIndex", + jointIndicesName); + + 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 +{ + 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); + + return StringHelper::Sprintf("\n\t{ %i }, %s\n", frameCount, segSymbol.c_str()); +} + +/* ZCurveAnimation */ + +TransformData::TransformData(ZFile* parent, const std::vector& 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); +} + +TransformData::TransformData(ZFile* parent, const std::vector& rawData, + uint32_t fileOffset, size_t index) + : TransformData(parent, rawData, fileOffset + index * GetRawDataSize()) +{ +} + +std::string TransformData::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 TransformData::GetRawDataSize() const +{ + return 0x0C; +} + +std::string TransformData::GetSourceTypeName() +{ + return "TransformData"; +} + +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 ", + "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->text = 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->text = 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->text = entryStr; + } + } +} + +std::string ZCurveAnimation::GetBodySourceCode() const +{ + std::string refIndexStr; + Globals::Instance->GetSegmentedPtrName(refIndex, parent, "u8", refIndexStr); + std::string transformDataStr; + Globals::Instance->GetSegmentedPtrName(transformData, parent, "TransformData", + transformDataStr); + std::string copyValuesStr; + Globals::Instance->GetSegmentedPtrName(copyValues, parent, "s16", copyValuesStr); + + 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 "TransformUpdateIndex"; +} + +/* 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++) + { + JointKey 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); + Globals::Instance->GetSegmentedPtrName(jointKey, parent, "JointKey", jointKeyName); + + 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; +} + +JointKey::JointKey(ZFile* nParent) : ZResource(nParent) +{ +} + +void JointKey::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 JointKey::GetBodySourceCode() const +{ + return StringHelper::Sprintf("%6i, %6i, %6i, %6i, %6i, %6i", xMax, x, yMax, y, zMax, z); +} + +std::string JointKey::GetSourceTypeName() const +{ + return "JointKey"; +} + +ZResourceType JointKey::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +size_t JointKey::GetRawDataSize() const +{ + return 0x0C; +} diff --git a/ZAPDTR/ZAPD/ZAnimation.h b/ZAPDTR/ZAPD/ZAnimation.h new file mode 100644 index 000000000..956e7faee --- /dev/null +++ b/ZAPDTR/ZAPD/ZAnimation.h @@ -0,0 +1,180 @@ +#pragma once + +#include +#include +#include +#include "Vec3s.h" +#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 rotationValues; + std::vector 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 TransformData +{ +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: + TransformData() = default; + TransformData(ZFile* parent, const std::vector& rawData, uint32_t fileOffset); + TransformData(ZFile* parent, const std::vector& 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 */ TransformData* 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 refIndexArr; + std::vector transformDataArr; + std::vector 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; +}; +// TransformUpdateIndex + +/* ZLegacyAnimation */ + +class JointKey : public ZResource +{ +public: + JointKey(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; // JointKey* + + std::vector frameDataArray; + std::vector jointKeyArray; +}; diff --git a/ZAPDTR/ZAPD/ZArray.cpp b/ZAPDTR/ZAPD/ZArray.cpp new file mode 100644 index 000000000..341ade1cf --- /dev/null +++ b/ZAPDTR/ZAPD/ZArray.cpp @@ -0,0 +1,143 @@ +#include "ZArray.h" + +#include + +#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, + " needs one sub-element", ""); + } + + childName = child->Name(); + + auto nodeMap = ZFile::GetNodeMap(); + size_t childIndex = rawDataIndex; + 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 ", childName.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, errorHeader, + ""); + } + res->parent = parent; + res->SetInnerNode(true); + res->ExtractFromXML(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.c_str(), + res->GetExternalExtension().c_str()); + decl = parent->AddDeclarationIncludeArray(rawDataIndex, includePath, GetRawDataSize(), + GetSourceTypeName(), name, arrayCnt); + decl->text = 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"; + + if (res->GetResourceType() == ZResourceType::Scalar || + res->GetResourceType() == ZResourceType::Vertex) + output += resList.at(i)->GetBodySourceCode(); + else + output += StringHelper::Sprintf("{ %s }", resList.at(i)->GetBodySourceCode().c_str()); + + if (i < arrayCnt - 1 || res->IsExternalResource()) + output += ",\n"; + } + + return output; +} + +size_t ZArray::GetRawDataSize() const +{ + size_t size = 0; + for (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(); +} diff --git a/ZAPDTR/ZAPD/ZArray.h b/ZAPDTR/ZAPD/ZArray.h new file mode 100644 index 000000000..e6594fadc --- /dev/null +++ b/ZAPDTR/ZAPD/ZArray.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#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 resList; +protected: + std::string childName; +}; diff --git a/ZAPDTR/ZAPD/ZBackground.cpp b/ZAPDTR/ZAPD/ZBackground.cpp new file mode 100644 index 000000000..0ed1eb747 --- /dev/null +++ b/ZAPDTR/ZAPD/ZBackground.cpp @@ -0,0 +1,192 @@ +#include "ZBackground.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/File.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 = File::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); + 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) +{ + fs::path filepath = outFolder / (outName + "." + GetExternalExtension()); + File::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; +} diff --git a/ZAPDTR/ZAPD/ZBackground.h b/ZAPDTR/ZAPD/ZBackground.h new file mode 100644 index 000000000..e3728bd98 --- /dev/null +++ b/ZAPDTR/ZAPD/ZBackground.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "ZResource.h" + +class ZBackground : public ZResource +{ +protected: + std::vector 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); +}; diff --git a/ZAPDTR/ZAPD/ZBlob.cpp b/ZAPDTR/ZAPD/ZBlob.cpp new file mode 100644 index 000000000..759dbbc62 --- /dev/null +++ b/ZAPDTR/ZAPD/ZBlob.cpp @@ -0,0 +1,116 @@ +#include "ZBlob.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/File.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 = File::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) + File::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; +} diff --git a/ZAPDTR/ZAPD/ZBlob.h b/ZAPDTR/ZAPD/ZBlob.h new file mode 100644 index 000000000..d7a7feff1 --- /dev/null +++ b/ZAPDTR/ZAPD/ZBlob.h @@ -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 blobData; + size_t blobSize = 0; +}; diff --git a/ZAPDTR/ZAPD/ZCollision.cpp b/ZAPDTR/ZAPD/ZCollision.cpp new file mode 100644 index 000000000..11efd47e8 --- /dev/null +++ b/ZAPDTR/ZAPD/ZCollision.cpp @@ -0,0 +1,364 @@ +#include "ZCollision.h" + +#include +#include + +#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); + + uint32_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++) + polygons.push_back(PolygonEntry(rawData, polySegmentOffset + (i * 16))); + + uint16_t highestPolyType = 0; + + for (PolygonEntry poly : polygons) + { + if (poly.type > highestPolyType) + highestPolyType = poly.type; + } + + for (uint16_t i = 0; i < highestPolyType + 1; i++) + polygonTypes.push_back( + BitConverter::ToUInt64BE(rawData, polyTypeDefSegmentOffset + (i * 8))); + + if (camDataAddress != 0) + camData = new CameraDataList(parent, name, rawData, camDataSegmentOffset, + polyTypeDefSegmentOffset, polygonTypes.size()); + + for (uint16_t i = 0; i < numWaterBoxes; i++) + waterBoxes.push_back(WaterBoxHeader( + rawData, + waterBoxSegmentOffset + (i * (Globals::Instance->game == ZGame::OOT_SW97 ? 12 : 16)))); +} + +void ZCollisionHeader::DeclareReferences(const std::string& prefix) +{ + std::string declaration = ""; + std::string auxName = name; + + if (name == "") + auxName = GetDefaultName(prefix); + + if (waterBoxes.size() > 0) + { + 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, 16 * waterBoxes.size(), "WaterBox", + StringHelper::Sprintf("%s_waterBoxes_%06X", auxName.c_str(), waterBoxSegmentOffset), + waterBoxes.size(), declaration); + } + + if (polygons.size() > 0) + { + declaration.clear(); + + for (size_t i = 0; i < polygons.size(); i++) + { + declaration += StringHelper::Sprintf( + "\t{ 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X },", + polygons[i].type, polygons[i].vtxA, polygons[i].vtxB, polygons[i].vtxC, + polygons[i].a, polygons[i].b, polygons[i].c, polygons[i].d); + if (i + 1 < polygons.size()) + declaration += "\n"; + } + + parent->AddDeclarationArray( + polySegmentOffset, DeclarationAlignment::Align4, polygons.size() * 16, "CollisionPoly", + StringHelper::Sprintf("%s_polygons_%08X", auxName.c_str(), polySegmentOffset), + polygons.size(), declaration); + } + + declaration.clear(); + for (size_t i = 0; i < polygonTypes.size(); i++) + { + declaration += StringHelper::Sprintf("\t{ 0x%08lX, 0x%08lX },", polygonTypes[i] >> 32, + polygonTypes[i] & 0xFFFFFFFF); + + if (i < polygonTypes.size() - 1) + declaration += "\n"; + } + + if (polyTypeDefAddress != 0) + parent->AddDeclarationArray( + polyTypeDefSegmentOffset, DeclarationAlignment::Align4, polygonTypes.size() * 8, + "SurfaceType", + StringHelper::Sprintf("%s_surfaceType_%08X", auxName.c_str(), polyTypeDefSegmentOffset), + polygonTypes.size(), declaration); + + declaration.clear(); + + if (vertices.size() > 0) + { + declaration.clear(); + + 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("%s_vtx_%08X", auxName.c_str(), vtxSegmentOffset), + vertices.size(), declaration); + } +} + +std::string ZCollisionHeader::GetBodySourceCode() const +{ + std::string 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); + declaration += StringHelper::Sprintf("\t%i,\n\t%s,\n", numVerts, vtxName.c_str()); + + std::string polyName; + Globals::Instance->GetSegmentedPtrName(polyAddress, parent, "CollisionPoly", polyName); + declaration += StringHelper::Sprintf("\t%i,\n\t%s,\n", numPolygons, polyName.c_str()); + + std::string surfaceName; + Globals::Instance->GetSegmentedPtrName(polyTypeDefAddress, parent, "SurfaceType", surfaceName); + declaration += StringHelper::Sprintf("\t%s,\n", surfaceName.c_str()); + + std::string camName; + Globals::Instance->GetSegmentedPtrName(camDataAddress, parent, "CamData", camName); + declaration += StringHelper::Sprintf("\t%s,\n", camName.c_str()); + + std::string waterBoxName; + Globals::Instance->GetSegmentedPtrName(waterBoxAddress, parent, "WaterBox", waterBoxName); + declaration += StringHelper::Sprintf("\t%i,\n\t%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; +} + +PolygonEntry::PolygonEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + const uint8_t* data = rawData.data(); + + type = BitConverter::ToUInt16BE(data, rawDataIndex + 0); + vtxA = BitConverter::ToUInt16BE(data, rawDataIndex + 2); + vtxB = BitConverter::ToUInt16BE(data, rawDataIndex + 4); + vtxC = BitConverter::ToUInt16BE(data, rawDataIndex + 6); + a = BitConverter::ToUInt16BE(data, rawDataIndex + 8); + b = BitConverter::ToUInt16BE(data, rawDataIndex + 10); + c = BitConverter::ToUInt16BE(data, rawDataIndex + 12); + d = BitConverter::ToUInt16BE(data, rawDataIndex + 14); +} + +WaterBoxHeader::WaterBoxHeader(const std::vector& rawData, uint32_t rawDataIndex) +{ + const uint8_t* data = rawData.data(); + + xMin = BitConverter::ToInt16BE(data, rawDataIndex + 0); + ySurface = BitConverter::ToInt16BE(data, rawDataIndex + 2); + zMin = BitConverter::ToInt16BE(data, rawDataIndex + 4); + xLength = BitConverter::ToInt16BE(data, rawDataIndex + 6); + zLength = BitConverter::ToInt16BE(data, rawDataIndex + 8); + + if (Globals::Instance->game == ZGame::OOT_SW97) + properties = BitConverter::ToInt16BE(data, rawDataIndex + 10); + else + properties = BitConverter::ToInt32BE(data, rawDataIndex + 12); +} + +std::string WaterBoxHeader::GetBodySourceCode() const +{ + return StringHelper::Sprintf("%i, %i, %i, %i, %i, 0x%08X", xMin, ySurface, zMin, xLength, + zLength, properties); +} + +CameraDataList::CameraDataList(ZFile* parent, const std::string& prefix, + const std::vector& rawData, uint32_t rawDataIndex, + uint32_t polyTypeDefSegmentOffset, + [[maybe_unused]] uint32_t polygonTypesCnt) +{ + std::string declaration; + + // Parse CameraDataEntries + int32_t numElements = (polyTypeDefSegmentOffset - rawDataIndex) / 8; + uint32_t cameraPosDataSeg = rawDataIndex; + for (int32_t i = 0; i < numElements; i++) + { + CameraDataEntry* entry = new CameraDataEntry(); + + 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 (entry->cameraPosDataSeg != 0 && cameraPosDataSeg > (entry->cameraPosDataSeg & 0xFFFFFF)) + cameraPosDataSeg = (entry->cameraPosDataSeg & 0xFFFFFF); + + entries.push_back(entry); + } + + // Setting cameraPosDataAddr to rawDataIndex give a pos list length of 0 + uint32_t cameraPosDataOffset = cameraPosDataSeg & 0xFFFFFF; + for (size_t i = 0; i < entries.size(); i++) + { + char camSegLine[2048]; + + if (entries[i]->cameraPosDataSeg != 0) + { + int32_t index = + ((entries[i]->cameraPosDataSeg & 0x00FFFFFF) - cameraPosDataOffset) / 0x6; + sprintf(camSegLine, "&%s_camPosData_%08X[%i]", prefix.c_str(), cameraPosDataOffset, + index); + } + else + sprintf(camSegLine, "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, "CamData", + StringHelper::Sprintf("%s_camDataList_%08X", prefix.c_str(), rawDataIndex), entries.size(), + declaration); + + uint32_t numDataTotal = (rawDataIndex - cameraPosDataOffset) / 0x6; + + if (numDataTotal > 0) + { + declaration.clear(); + for (uint32_t i = 0; i < numDataTotal; i++) + { + CameraPositionData* data = + new CameraPositionData(rawData, cameraPosDataOffset + (i * 6)); + cameraPositionData.push_back(data); + + declaration += StringHelper::Sprintf("\t{ %6i, %6i, %6i },", data->x, data->y, data->z); + if (i + 1 < numDataTotal) + declaration += "\n"; + } + + int32_t cameraPosDataIndex = GETSEGOFFSET(cameraPosDataSeg); + uint32_t entrySize = numDataTotal * 0x6; + parent->AddDeclarationArray( + cameraPosDataIndex, DeclarationAlignment::Align4, entrySize, "Vec3s", + StringHelper::Sprintf("%s_camPosData_%08X", prefix.c_str(), cameraPosDataIndex), + numDataTotal, declaration); + } +} + +CameraDataList::~CameraDataList() +{ + for (auto entry : entries) + delete entry; + + for (auto camPosData : cameraPositionData) + delete camPosData; +} + +CameraPositionData::CameraPositionData(const std::vector& rawData, uint32_t rawDataIndex) +{ + x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + y = BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + z = BitConverter::ToInt16BE(rawData, rawDataIndex + 4); +} diff --git a/ZAPDTR/ZAPD/ZCollision.h b/ZAPDTR/ZAPD/ZCollision.h new file mode 100644 index 000000000..4bce7c944 --- /dev/null +++ b/ZAPDTR/ZAPD/ZCollision.h @@ -0,0 +1,99 @@ +#pragma once + +#include "ZFile.h" +#include "ZResource.h" +#include "ZRoom/ZRoom.h" +#include "ZVector.h" + +class PolygonEntry +{ +public: + uint16_t type; + uint16_t vtxA, vtxB, vtxC; + uint16_t a, b, c, d; + + PolygonEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class WaterBoxHeader +{ +public: + int16_t xMin; + int16_t ySurface; + int16_t zMin; + int16_t xLength; + int16_t zLength; + int16_t pad; + int32_t properties; + + WaterBoxHeader(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; +}; + +class CameraPositionData +{ +public: + int16_t x, y, z; + + CameraPositionData(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CameraDataEntry +{ +public: + uint16_t cameraSType; + int16_t numData; + int32_t cameraPosDataSeg; +}; + +class CameraDataList +{ +public: + std::vector entries; + std::vector cameraPositionData; + + CameraDataList(ZFile* parent, const std::string& prefix, const std::vector& rawData, + uint32_t rawDataIndex, uint32_t polyTypeDefSegmentOffset, + uint32_t polygonTypesCnt); + ~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 vertices; + std::vector polygons; + std::vector polygonTypes; + std::vector 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; +}; diff --git a/ZAPDTR/ZAPD/ZCutscene.cpp b/ZAPDTR/ZAPD/ZCutscene.cpp new file mode 100644 index 000000000..69fbd9e48 --- /dev/null +++ b/ZAPDTR/ZAPD/ZCutscene.cpp @@ -0,0 +1,1260 @@ +#include "ZCutscene.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZResource.h" + +REGISTER_ZFILENODE(Cutscene, ZCutscene); + +ZCutscene::ZCutscene(ZFile* nParent) : ZCutsceneBase(nParent) +{ + genOTRDef = true; +} + +ZCutscene::~ZCutscene() +{ + for (CutsceneCommand* cmd : commands) + delete cmd; +} +CutsceneCommandSetCameraPos::~CutsceneCommandSetCameraPos() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandSpecialAction::~CutsceneCommandSpecialAction() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandFadeBGM::~CutsceneCommandFadeBGM() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandPlayBGM::~CutsceneCommandPlayBGM() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandStopBGM::~CutsceneCommandStopBGM() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandEnvLighting::~CutsceneCommandEnvLighting() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandUnknown9::~CutsceneCommandUnknown9() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandUnknown::~CutsceneCommandUnknown() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandDayTime::~CutsceneCommandDayTime() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandTextbox::~CutsceneCommandTextbox() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandActorAction::~CutsceneCommandActorAction() +{ + for (auto e : entries) + delete e; +} + +CutsceneCommandSceneTransFX::~CutsceneCommandSceneTransFX() +{ +} + +std::string ZCutscene::GetBodySourceCode() const +{ + std::string output = ""; + uint32_t curPtr = 0; + + 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(curPtr); + curPtr += cmd->GetCommandSize(); + } + + output += StringHelper::Sprintf(" CS_END(),\n", 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(); + size += 4; + } + + // End + size += 8; + + return size; +} + +void ZCutscene::ParseRawData() +{ + ZResource::ParseRawData(); + + const auto& rawData = parent->GetRawData(); + + numCommands = BitConverter::ToInt32BE(rawData, rawDataIndex + 0); + commands = std::vector(); + + endFrame = BitConverter::ToInt32BE(rawData, rawDataIndex + 4); + uint32_t currentPtr = rawDataIndex + 8; + + for (int32_t i = 0; i < numCommands; i++) + { + int32_t id = BitConverter::ToInt32BE(rawData, currentPtr); + + if (id == -1) + break; + + CutsceneCommands cmdID = (CutsceneCommands)GetCommandFromID(id); + currentPtr += 4; + + int32_t numEntries = 1; + + for (int32_t j = 0; j < numEntries; j++) + { + CutsceneCommand* cmd = nullptr; + + switch (cmdID) + { + case CutsceneCommands::Cmd00: + break; + case CutsceneCommands::SetCameraPos: + cmd = new CutsceneCommandSetCameraPos(rawData, currentPtr); + break; + case CutsceneCommands::SetCameraFocus: + cmd = new CutsceneCommandSetCameraPos(rawData, currentPtr); + break; + case CutsceneCommands::SpecialAction: + cmd = new CutsceneCommandSpecialAction(rawData, currentPtr); + break; + case CutsceneCommands::SetLighting: + cmd = new CutsceneCommandEnvLighting(rawData, currentPtr); + break; + case CutsceneCommands::SetCameraPosLink: + cmd = new CutsceneCommandSetCameraPos(rawData, currentPtr); + break; + case CutsceneCommands::SetCameraFocusLink: + cmd = new CutsceneCommandSetCameraPos(rawData, currentPtr); + break; + case CutsceneCommands::Cmd07: + break; + case CutsceneCommands::Cmd08: + break; + case CutsceneCommands::Cmd09: + cmd = new CutsceneCommandUnknown9(rawData, currentPtr); + break; + case CutsceneCommands::Textbox: + cmd = new CutsceneCommandTextbox(rawData, currentPtr); + break; + case CutsceneCommands::Unknown: + cmd = new CutsceneCommandUnknown(rawData, currentPtr); + break; + case CutsceneCommands::SetActorAction0: + case CutsceneCommands::SetActorAction1: + case CutsceneCommands::SetActorAction2: + case CutsceneCommands::SetActorAction3: + case CutsceneCommands::SetActorAction4: + case CutsceneCommands::SetActorAction5: + case CutsceneCommands::SetActorAction6: + case CutsceneCommands::SetActorAction7: + case CutsceneCommands::SetActorAction8: + case CutsceneCommands::SetActorAction9: + case CutsceneCommands::SetActorAction10: + cmd = new CutsceneCommandActorAction(rawData, currentPtr); + break; + case CutsceneCommands::SetSceneTransFX: + cmd = new CutsceneCommandSceneTransFX(rawData, currentPtr); + break; + case CutsceneCommands::Nop: + cmd = new CutsceneCommandNop(rawData, currentPtr); + break; + case CutsceneCommands::PlayBGM: + cmd = new CutsceneCommandPlayBGM(rawData, currentPtr); + break; + case CutsceneCommands::StopBGM: + cmd = new CutsceneCommandStopBGM(rawData, currentPtr); + break; + case CutsceneCommands::FadeBGM: + cmd = new CutsceneCommandFadeBGM(rawData, currentPtr); + break; + case CutsceneCommands::SetTime: + cmd = new CutsceneCommandDayTime(rawData, currentPtr); + break; + case CutsceneCommands::Terminator: + cmd = new CutsceneCommandTerminator(rawData, currentPtr); + break; + case CutsceneCommands::End: + cmd = new CutsceneCommandEnd(rawData, currentPtr); + break; + case CutsceneCommands::Error: + HANDLE_WARNING_RESOURCE(WarningType::NotImplemented, parent, this, rawDataIndex, + StringHelper::Sprintf("cutscene command error %d", cmdID), + ""); + break; + } + + cmd->commandIndex = i; + cmd->commandID = (uint32_t)id; + currentPtr += (uint32_t)cmd->GetCommandSize(); + + commands.push_back(cmd); + } + } +} + +CutsceneCommands ZCutscene::GetCommandFromID(int32_t id) +{ + switch (id) + { + case 0x0003: + return CutsceneCommands::SpecialAction; + case 0x0004: + return CutsceneCommands::SetLighting; + case 0x0056: + return CutsceneCommands::PlayBGM; + case 0x0057: + return CutsceneCommands::StopBGM; + case 0x007C: + return CutsceneCommands::FadeBGM; + case 0x0009: + return CutsceneCommands::Cmd09; + case 0x0013: + return CutsceneCommands::Textbox; + case 0x008C: + return CutsceneCommands::SetTime; + case 0x0001: + return CutsceneCommands::SetCameraPos; + case 0x0002: + return CutsceneCommands::SetCameraFocus; + case 0x0005: + return CutsceneCommands::SetCameraPosLink; + case 0x0006: + return CutsceneCommands::SetCameraFocusLink; + case 0x0007: + return CutsceneCommands::Cmd07; + case 0x0008: + return CutsceneCommands::Cmd08; + case 0x03E8: + return CutsceneCommands::Terminator; + case 0xFFFF: + return CutsceneCommands::End; + case 0x002D: + return CutsceneCommands::SetSceneTransFX; + case 10: + return CutsceneCommands::SetActorAction0; + case 15: + case 17: + case 18: + case 23: + case 34: + case 39: + case 46: + case 76: + case 85: + case 93: + case 105: + case 107: + case 110: + case 119: + case 123: + case 138: + case 139: + case 144: + return CutsceneCommands::SetActorAction1; + case 14: + case 16: + case 24: + case 35: + case 40: + case 48: + case 64: + case 68: + case 70: + case 78: + case 80: + case 94: + case 116: + case 118: + case 120: + case 125: + case 131: + case 141: + return CutsceneCommands::SetActorAction2; + case 25: + case 36: + case 41: + case 50: + case 67: + case 69: + case 72: + case 81: + case 106: + case 117: + case 121: + case 126: + case 132: + return CutsceneCommands::SetActorAction3; + case 29: + case 37: + case 42: + case 51: + case 53: + case 63: + case 65: + case 66: + case 75: + case 82: + case 108: + case 127: + case 133: + return CutsceneCommands::SetActorAction4; + case 30: + case 38: + case 43: + case 47: + case 54: + case 79: + case 83: + case 128: + case 135: + return CutsceneCommands::SetActorAction5; + case 44: + case 55: + case 77: + case 84: + case 90: + case 129: + case 136: + return CutsceneCommands::SetActorAction6; + case 31: + case 52: + case 57: + case 58: + case 88: + case 115: + case 130: + case 137: + return CutsceneCommands::SetActorAction7; + case 49: + case 60: + case 89: + case 111: + case 114: + case 134: + case 142: + return CutsceneCommands::SetActorAction8; + case 62: + return CutsceneCommands::SetActorAction9; + case 143: + return CutsceneCommands::SetActorAction10; + case 0x0B: + case 0x0D: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x20: + case 0x21: + case 0x3B: + case 0x3D: + case 0x47: + case 0x49: + case 0x6D: + case 0x15: + case 0x16: + case 0x70: + case 0x71: + case 0x4A: + return CutsceneCommands::Unknown; + } + + HANDLE_WARNING_RESOURCE( + WarningType::NotImplemented, parent, this, rawDataIndex, + StringHelper::Sprintf("could not identify cutscene command. ID 0x%04X", id), ""); + + return CutsceneCommands::Error; +} + +ZResourceType ZCutscene::GetResourceType() const +{ + return ZResourceType::Cutscene; +} + +CutsceneCommand::CutsceneCommand([[maybe_unused]] const std::vector& rawData, + [[maybe_unused]] uint32_t rawDataIndex) +{ +} + +CutsceneCommand::~CutsceneCommand() +{ +} + +std::string CutsceneCommand::GetCName() +{ + return "SCmdCutsceneData"; +} + +std::string CutsceneCommand::GenerateSourceCode(uint32_t baseAddress) +{ + return StringHelper::Sprintf("%s CutsceneData%04XCmd%02X = { 0x%02X,", GetCName().c_str(), + baseAddress, commandIndex, commandID); +} + +size_t CutsceneCommand::GetCommandSize() +{ + return 4; +} + +CutsceneCameraPoint::CutsceneCameraPoint(const std::vector& rawData, uint32_t rawDataIndex) +{ + const uint8_t* data = rawData.data(); + + continueFlag = data[rawDataIndex + 0]; + cameraRoll = data[rawDataIndex + 1]; + nextPointFrame = BitConverter::ToInt16BE(data, rawDataIndex + 2); + viewAngle = BitConverter::ToFloatBE(data, rawDataIndex + 4); + + posX = BitConverter::ToInt16BE(data, rawDataIndex + 8); + posY = BitConverter::ToInt16BE(data, rawDataIndex + 10); + posZ = BitConverter::ToInt16BE(data, rawDataIndex + 12); + + unused = BitConverter::ToInt16BE(data, rawDataIndex + 14); +} + +CutsceneCommandSetCameraPos::CutsceneCommandSetCameraPos(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + const uint8_t* data = rawData.data(); + + base = BitConverter::ToUInt16BE(data, rawDataIndex + 0); + startFrame = BitConverter::ToUInt16BE(data, rawDataIndex + 2); + endFrame = BitConverter::ToUInt16BE(data, rawDataIndex + 4); + unused = BitConverter::ToUInt16BE(data, rawDataIndex + 6); + + entries = std::vector(); + + bool shouldContinue = true; + + uint32_t currentPtr = rawDataIndex + 8; + + while (shouldContinue) + { + CutsceneCameraPoint* camPoint = new CutsceneCameraPoint(rawData, currentPtr); + entries.push_back(camPoint); + + if (camPoint->continueFlag == -1) + shouldContinue = false; + + currentPtr += 16; + } +} + +// TODO +std::string CutsceneCommandSetCameraPos::GetCName() +{ + return ""; +} + +std::string CutsceneCommandSetCameraPos::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + std::string listStr; + std::string posStr; + + if (commandID == (int32_t)CutsceneCommands::SetCameraFocus) + { + listStr = "CS_CAM_FOCUS_POINT_LIST"; + posStr = "CS_CAM_FOCUS_POINT"; + } + else if (commandID == (int32_t)CutsceneCommands::SetCameraFocusLink) + { + listStr = "CS_CAM_FOCUS_POINT_PLAYER_LIST"; + posStr = "CS_CAM_FOCUS_POINT_PLAYER"; + } + else if (commandID == (int32_t)CutsceneCommands::SetCameraPosLink) + { + listStr = "CS_CAM_POS_PLAYER_LIST"; + posStr = "CS_CAM_POS_PLAYER"; + } + else + { + listStr = "CS_CAM_POS_LIST"; + posStr = "CS_CAM_POS"; + } + + result += StringHelper::Sprintf("%s(%i, %i),\n", listStr.c_str(), startFrame, endFrame); + + for (size_t i = 0; i < entries.size(); i++) + { + std::string continueMacro = "CS_CMD_CONTINUE"; + if (entries[i]->continueFlag != 0) + continueMacro = "CS_CMD_STOP"; + result += StringHelper::Sprintf(" %s(%s, 0x%02X, %i, %ff, %i, %i, %i, 0x%04X),\n", + posStr.c_str(), continueMacro.c_str(), + entries[i]->cameraRoll, entries[i]->nextPointFrame, + entries[i]->viewAngle, entries[i]->posX, entries[i]->posY, + entries[i]->posZ, entries[i]->unused); + } + + return result; +} + +size_t CutsceneCommandSetCameraPos::GetCommandSize() +{ + return 8 + (entries.size() * 16); +} + +MusicFadeEntry::MusicFadeEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + base = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0); + startFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2); + endFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4); + unknown0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6); + unknown1 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8); + unknown2 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 12); + unknown3 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 16); + unknown4 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 20); + unknown5 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 24); + unknown6 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 28); + unknown7 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 32); + unknown8 = BitConverter::ToUInt32BE(rawData, + rawDataIndex + 36); // Macro hardcodes it as zero + unknown9 = BitConverter::ToUInt32BE(rawData, + rawDataIndex + 40); // Macro hardcodes it as zero + unknown10 = BitConverter::ToUInt32BE(rawData, + rawDataIndex + 44); // Macro hardcodes it as zero +} + +CutsceneCommandFadeBGM::CutsceneCommandFadeBGM(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + uint32_t numEntries = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0); + + rawDataIndex += 4; + + for (uint32_t i = 0; i < numEntries; i++) + { + entries.push_back(new MusicFadeEntry(rawData, rawDataIndex)); + rawDataIndex += 0x30; + } +} + +std::string CutsceneCommandFadeBGM::GetCName() +{ + return "CsCmdMusicFade"; +} + +std::string CutsceneCommandFadeBGM::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_FADE_BGM_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + " CS_FADE_BGM(%i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i),\n", entries[i]->base, + entries[i]->startFrame, entries[i]->endFrame, entries[i]->unknown0, + entries[i]->unknown1, entries[i]->unknown2, entries[i]->unknown3, entries[i]->unknown4, + entries[i]->unknown5, entries[i]->unknown6, entries[i]->unknown7); + } + + return result; +} + +size_t CutsceneCommandFadeBGM::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + 0x30 * entries.size(); +} + +MusicChangeEntry::MusicChangeEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + sequence = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0); + startFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2); + endFrame = BitConverter::ToUInt16BE(rawData, rawDataIndex + 4); + unknown0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 6); + unknown1 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8); + unknown2 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 12); + unknown3 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 16); + unknown4 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 20); + unknown5 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 24); + unknown6 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 28); + unknown7 = BitConverter::ToUInt32BE(rawData, rawDataIndex + 32); +} + +CutsceneCommandPlayBGM::CutsceneCommandPlayBGM(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + uint32_t numEntries = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0); + + rawDataIndex += 4; + + for (uint32_t i = 0; i < numEntries; i++) + { + entries.push_back(new MusicChangeEntry(rawData, rawDataIndex)); + rawDataIndex += 0x30; + } +} + +std::string CutsceneCommandPlayBGM::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_PLAY_BGM_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + " CS_PLAY_BGM(%i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i),\n", + entries[i]->sequence, entries[i]->startFrame, entries[i]->endFrame, + entries[i]->unknown0, entries[i]->unknown1, entries[i]->unknown2, entries[i]->unknown3, + entries[i]->unknown4, entries[i]->unknown5, entries[i]->unknown6, entries[i]->unknown7); + } + + return result; +} + +std::string CutsceneCommandPlayBGM::GetCName() +{ + return "CsCmdMusicChange"; +} + +size_t CutsceneCommandPlayBGM::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + 0x30; +} + +CutsceneCommandStopBGM::CutsceneCommandStopBGM(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + uint32_t numEntries = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0); + + rawDataIndex += 4; + + for (uint32_t i = 0; i < numEntries; i++) + { + entries.push_back(new MusicChangeEntry(rawData, rawDataIndex)); + rawDataIndex += 0x30; + } +} + +std::string CutsceneCommandStopBGM::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_STOP_BGM_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + "\t\tCS_STOP_BGM(%i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i),\n", entries[i]->sequence, + entries[i]->startFrame, entries[i]->endFrame, entries[i]->unknown0, + entries[i]->unknown1, entries[i]->unknown2, entries[i]->unknown3, entries[i]->unknown4, + entries[i]->unknown5, entries[i]->unknown6, entries[i]->unknown7); + } + + return result; +} + +std::string CutsceneCommandStopBGM::GetCName() +{ + return "CsCmdMusicChange"; +} + +size_t CutsceneCommandStopBGM::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + 0x30; +} + +EnvLightingEntry::EnvLightingEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + setting = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + unused0 = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 6); + unused1 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 8); + unused2 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 12); + unused3 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 16); + unused4 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 20); + unused5 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 24); + unused6 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 28); + unused7 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 32); +} + +CutsceneCommandEnvLighting::CutsceneCommandEnvLighting(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + int32_t numEntries = BitConverter::ToInt32BE(rawData, rawDataIndex + 0); + + rawDataIndex += 4; + + for (int32_t i = 0; i < numEntries; i++) + { + entries.push_back(new EnvLightingEntry(rawData, rawDataIndex)); + rawDataIndex += 0x30; + } +} + +std::string CutsceneCommandEnvLighting::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_LIGHTING_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + "\t\tCS_LIGHTING(%i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i),\n", entries[i]->setting, + entries[i]->startFrame, entries[i]->endFrame, entries[i]->unused0, entries[i]->unused1, + entries[i]->unused2, entries[i]->unused3, entries[i]->unused4, entries[i]->unused5, + entries[i]->unused6, entries[i]->unused7); + } + + return result; +} + +std::string CutsceneCommandEnvLighting::GetCName() +{ + return "CsCmdEnvLighting"; +} + +size_t CutsceneCommandEnvLighting::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + (0x30 * entries.size()); +} + +Unknown9Entry::Unknown9Entry(const std::vector& rawData, uint32_t rawDataIndex) +{ + base = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + unk2 = rawData[rawDataIndex + 6]; + unk3 = rawData[rawDataIndex + 7]; + unk4 = rawData[rawDataIndex + 8]; + unused0 = rawData[rawDataIndex + 10]; + unused1 = rawData[rawDataIndex + 11]; + ; +} + +CutsceneCommandUnknown9::CutsceneCommandUnknown9(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + int32_t numEntries = BitConverter::ToInt32BE(rawData, rawDataIndex); + + rawDataIndex += 4; + + for (int32_t i = 0; i < numEntries; i++) + { + entries.push_back(new Unknown9Entry(rawData, rawDataIndex)); + rawDataIndex += 0x0C; + } +} + +std::string CutsceneCommandUnknown9::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_CMD_09_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf("\t\tCS_CMD_09(%i, %i, %i, %i, %i, %i, %i, %i),\n", + entries[i]->base, entries[i]->startFrame, + entries[i]->endFrame, entries[i]->unk2, entries[i]->unk3, + entries[i]->unk4, entries[i]->unused0, entries[i]->unused1); + } + + return result; +} + +std::string CutsceneCommandUnknown9::GetCName() +{ + return "CsCmdUnknown9"; +} + +size_t CutsceneCommandUnknown9::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + (entries.size() * 12); +} + +UnkEntry::UnkEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + unused0 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 0); + unused1 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 4); + unused2 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 8); + unused3 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 12); + unused4 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 16); + unused5 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 20); + unused6 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 24); + unused7 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 28); + unused8 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 32); + unused9 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 36); + unused10 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 40); + unused11 = (uint32_t)BitConverter::ToInt32BE(rawData, rawDataIndex + 44); +} + +CutsceneCommandUnknown::CutsceneCommandUnknown(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + int32_t numEntries = BitConverter::ToInt32BE(rawData, rawDataIndex); + + rawDataIndex += 4; + + for (int32_t i = 0; i < numEntries; i++) + { + entries.push_back(new UnkEntry(rawData, rawDataIndex)); + rawDataIndex += 0x30; + } +} + +std::string CutsceneCommandUnknown::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_UNK_DATA_LIST(0x%02X, %i),\n", commandID, entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + " CS_UNK_DATA(%i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i),\n", + entries[i]->unused0, entries[i]->unused1, entries[i]->unused2, entries[i]->unused3, + entries[i]->unused4, entries[i]->unused5, entries[i]->unused6, entries[i]->unused7, + entries[i]->unused8, entries[i]->unused9, entries[i]->unused10, entries[i]->unused11); + } + + return result; +} + +std::string CutsceneCommandUnknown::GetCName() +{ + return "CsCmdUnknown1A"; +} + +size_t CutsceneCommandUnknown::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + (entries.size() * 0x30); +} + +DayTimeEntry::DayTimeEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + base = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + hour = rawData[rawDataIndex + 6]; + minute = rawData[rawDataIndex + 7]; + unused = rawData[rawDataIndex + 8]; +} + +CutsceneCommandDayTime::CutsceneCommandDayTime(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + int32_t numEntries = BitConverter::ToInt32BE(rawData, rawDataIndex); + + rawDataIndex += 4; + + for (int32_t i = 0; i < numEntries; i++) + { + entries.push_back(new DayTimeEntry(rawData, rawDataIndex)); + rawDataIndex += 12; + } +} + +std::string CutsceneCommandDayTime::GetCName() +{ + return "CsCmdDayTime"; +} + +std::string CutsceneCommandDayTime::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_TIME_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + " CS_TIME(%i, %i, %i, %i, %i, %i),\n", entries[i]->base, entries[i]->startFrame, + entries[i]->endFrame, entries[i]->hour, entries[i]->minute, entries[i]->unused); + } + + return result; +} + +size_t CutsceneCommandDayTime::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + (entries.size() * 12); +} + +TextboxEntry::TextboxEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + base = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + type = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 6); + textID1 = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 8); + textID2 = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 10); +} + +CutsceneCommandTextbox::CutsceneCommandTextbox(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + int32_t numEntries = BitConverter::ToInt32BE(rawData, rawDataIndex); + + rawDataIndex += 4; + + for (int32_t i = 0; i < numEntries; i++) + { + entries.push_back(new TextboxEntry(rawData, rawDataIndex)); + rawDataIndex += 12; + } +} + +std::string CutsceneCommandTextbox::GetCName() +{ + return "CsCmdTextbox"; +} + +std::string CutsceneCommandTextbox::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_TEXT_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + if (entries[i]->base == 0xFFFF) + { + result += StringHelper::Sprintf(" CS_TEXT_NONE(%i, %i),\n", + entries[i]->startFrame, entries[i]->endFrame); + } + else + { + result += StringHelper::Sprintf( + " CS_TEXT_DISPLAY_TEXTBOX(%i, %i, %i, %i, %i, %i),\n", entries[i]->base, + entries[i]->startFrame, entries[i]->endFrame, entries[i]->type, entries[i]->textID1, + entries[i]->textID2); + } + } + + return result; +} + +size_t CutsceneCommandTextbox::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + (entries.size() * 12); +} + +ActorAction::ActorAction(const std::vector& rawData, uint32_t rawDataIndex) +{ + const uint8_t* data = rawData.data(); + + action = (uint16_t)BitConverter::ToInt16BE(data, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(data, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(data, rawDataIndex + 4); + rotX = (uint16_t)BitConverter::ToInt16BE(data, rawDataIndex + 6); + rotY = (uint16_t)BitConverter::ToInt16BE(data, rawDataIndex + 8); + rotZ = (uint16_t)BitConverter::ToInt16BE(data, rawDataIndex + 10); + startPosX = BitConverter::ToInt32BE(data, rawDataIndex + 12); + startPosY = BitConverter::ToInt32BE(data, rawDataIndex + 16); + startPosZ = BitConverter::ToInt32BE(data, rawDataIndex + 20); + endPosX = BitConverter::ToInt32BE(data, rawDataIndex + 24); + endPosY = BitConverter::ToInt32BE(data, rawDataIndex + 28); + endPosZ = BitConverter::ToInt32BE(data, rawDataIndex + 32); + normalX = BitConverter::ToFloatBE(data, rawDataIndex + 36); + normalY = BitConverter::ToFloatBE(data, rawDataIndex + 40); + normalZ = BitConverter::ToFloatBE(data, rawDataIndex + 44); +} + +CutsceneCommandActorAction::CutsceneCommandActorAction(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + int32_t numEntries = BitConverter::ToInt32BE(rawData, rawDataIndex); + + rawDataIndex += 4; + + for (int32_t i = 0; i < numEntries; i++) + { + entries.push_back(new ActorAction(rawData, rawDataIndex)); + rawDataIndex += 0x30; + } +} + +std::string CutsceneCommandActorAction::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + std::string subCommand; + + if (commandID == 10) + { + result += StringHelper::Sprintf("CS_PLAYER_ACTION_LIST(%i),\n", entries.size()); + subCommand = "CS_PLAYER_ACTION"; + } + else + { + result += StringHelper::Sprintf("CS_NPC_ACTION_LIST(%i, %i),\n", commandID, entries.size()); + subCommand = "CS_NPC_ACTION"; + } + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + "\t\t%s(0x%04X, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, %i, %i, %i, %i, %.11ef, " + "%.11ef, %.11ef),\n", + subCommand.c_str(), entries[i]->action, entries[i]->startFrame, entries[i]->endFrame, + entries[i]->rotX, entries[i]->rotY, entries[i]->rotZ, entries[i]->startPosX, + entries[i]->startPosY, entries[i]->startPosZ, entries[i]->endPosX, entries[i]->endPosY, + entries[i]->endPosZ, entries[i]->normalX, entries[i]->normalY, entries[i]->normalZ); + } + + return result; +} + +std::string CutsceneCommandActorAction::GetCName() +{ + return "CsCmdBase"; +} + +size_t CutsceneCommandActorAction::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + (entries.size() * 0x30); +} + +CutsceneCommandTerminator::CutsceneCommandTerminator(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + rawDataIndex += 4; + + base = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + unknown = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 6); // endFrame duplicate +} + +std::string CutsceneCommandTerminator::GetCName() +{ + return "CsCmdBase"; +} + +std::string CutsceneCommandTerminator::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_TERMINATOR(0x%04X, %i, %i),\n", base, startFrame, endFrame); + + return result; +} + +size_t CutsceneCommandTerminator::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + 8; +} + +CutsceneCommandEnd::CutsceneCommandEnd(const std::vector& rawData, uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + base = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); +} + +std::string CutsceneCommandEnd::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_END(),\n"); + + return result; +} + +std::string CutsceneCommandEnd::GetCName() +{ + return "CsCmdBase"; +} + +size_t CutsceneCommandEnd::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + 6; +} + +SpecialActionEntry::SpecialActionEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + const uint8_t* data = rawData.data(); + + base = BitConverter::ToUInt16BE(data, rawDataIndex + 0); + startFrame = BitConverter::ToUInt16BE(data, rawDataIndex + 2); + endFrame = BitConverter::ToUInt16BE(data, rawDataIndex + 4); + unused0 = BitConverter::ToUInt16BE(data, rawDataIndex + 6); + unused1 = BitConverter::ToUInt32BE(data, rawDataIndex + 8); + unused2 = BitConverter::ToUInt32BE(data, rawDataIndex + 12); + unused3 = BitConverter::ToUInt32BE(data, rawDataIndex + 16); + unused4 = BitConverter::ToUInt32BE(data, rawDataIndex + 20); + unused5 = BitConverter::ToUInt32BE(data, rawDataIndex + 24); + unused6 = BitConverter::ToUInt32BE(data, rawDataIndex + 28); + unused7 = BitConverter::ToUInt32BE(data, rawDataIndex + 32); + unused8 = BitConverter::ToUInt32BE(data, rawDataIndex + 36); + unused9 = BitConverter::ToUInt32BE(data, rawDataIndex + 40); + unused10 = BitConverter::ToUInt32BE(data, rawDataIndex + 44); +} + +CutsceneCommandSpecialAction::CutsceneCommandSpecialAction(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + int32_t numEntries = BitConverter::ToInt32BE(rawData, rawDataIndex + 0); + + rawDataIndex += 4; + + for (int32_t i = 0; i < numEntries; i++) + { + entries.push_back(new SpecialActionEntry(rawData, rawDataIndex)); + rawDataIndex += 0x30; + } +} + +std::string CutsceneCommandSpecialAction::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + std::string result; + + result += StringHelper::Sprintf("CS_MISC_LIST(%i),\n", entries.size()); + + for (size_t i = 0; i < entries.size(); i++) + { + result += StringHelper::Sprintf( + "\t\tCS_MISC(0x%04X, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, %i, %i, %i, %i, %i, " + "%i),\n", + entries[i]->base, entries[i]->startFrame, entries[i]->endFrame, entries[i]->unused0, + entries[i]->unused1, entries[i]->unused2, entries[i]->unused3, entries[i]->unused4, + entries[i]->unused5, entries[i]->unused6, entries[i]->unused7, entries[i]->unused8, + entries[i]->unused9, entries[i]->unused10); + } + + return result; +} + +std::string CutsceneCommandSpecialAction::GetCName() +{ + return "CsCmdBase"; +} + +size_t CutsceneCommandSpecialAction::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + (0x30 * entries.size()); +} + +CutsceneCommandNop::CutsceneCommandNop(const std::vector& rawData, uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + base = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); +} + +std::string CutsceneCommandNop::GetCName() +{ + return "CsCmdBase"; +} + +size_t CutsceneCommandNop::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + 6; +} + +CutsceneCommandSceneTransFX::CutsceneCommandSceneTransFX(const std::vector& rawData, + uint32_t rawDataIndex) + : CutsceneCommand(rawData, rawDataIndex) +{ + rawDataIndex += 4; + + base = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + startFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + endFrame = (uint16_t)BitConverter::ToInt16BE(rawData, rawDataIndex + 4); +} + +std::string CutsceneCommandSceneTransFX::GenerateSourceCode([[maybe_unused]] uint32_t baseAddress) +{ + return StringHelper::Sprintf("CS_SCENE_TRANS_FX(%i, %i, %i),\n", base, startFrame, endFrame); +} + +std::string CutsceneCommandSceneTransFX::GetCName() +{ + return "CsCmdBase"; +} + +size_t CutsceneCommandSceneTransFX::GetCommandSize() +{ + return CutsceneCommand::GetCommandSize() + 8; +} + +ZCutsceneBase::ZCutsceneBase(ZFile* nParent) : ZResource(nParent) +{ +} + +Declaration* ZCutsceneBase::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 ZCutsceneBase::GetSourceTypeName() const +{ + return "CutsceneData"; +} diff --git a/ZAPDTR/ZAPD/ZCutscene.h b/ZAPDTR/ZAPD/ZCutscene.h new file mode 100644 index 000000000..8e901e307 --- /dev/null +++ b/ZAPDTR/ZAPD/ZCutscene.h @@ -0,0 +1,440 @@ +#pragma once + +#include +#include +#include +#include "ZFile.h" +#include "ZResource.h" +#include "tinyxml2.h" + +enum class CutsceneCommands +{ + Cmd00 = 0x0000, + SetCameraPos = 0x0001, + SetCameraFocus = 0x0002, + SpecialAction = 0x0003, + SetLighting = 0x0004, + SetCameraPosLink = 0x0005, + SetCameraFocusLink = 0x0006, + Cmd07 = 0x0007, + Cmd08 = 0x0008, + Cmd09 = 0x0009, + Unknown = 0x001A, + Textbox = 0x0013, + SetActorAction0 = 0x000A, + SetActorAction1 = 0x000F, + SetActorAction2 = 0x000E, + SetActorAction3 = 0x0019, + SetActorAction4 = 0x001D, + SetActorAction5 = 0x001E, + SetActorAction6 = 0x002C, + SetActorAction7 = 0x001F, + SetActorAction8 = 0x0031, + SetActorAction9 = 0x003E, + SetActorAction10 = 0x008F, + SetSceneTransFX = 0x002D, + Nop = 0x000B, + PlayBGM = 0x0056, + StopBGM = 0x0057, + FadeBGM = 0x007C, + SetTime = 0x008C, + Terminator = 0x03E8, + End = 0xFFFF, + Error = 0xFEAF, +}; + +class CutsceneCameraPoint +{ +public: + int8_t continueFlag; + int8_t cameraRoll; + int16_t nextPointFrame; + float viewAngle; + int16_t posX, posY, posZ; + int16_t unused; + + CutsceneCameraPoint(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommand +{ +public: + uint32_t commandID; + uint32_t commandIndex; + virtual ~CutsceneCommand(); + CutsceneCommand(const std::vector& rawData, uint32_t rawDataIndex); + virtual std::string GetCName(); + virtual std::string GenerateSourceCode(uint32_t baseAddress); + virtual size_t GetCommandSize(); +}; + +class CutsceneCommandSetCameraPos : public CutsceneCommand +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + uint16_t unused; + + std::vector entries; + ~CutsceneCommandSetCameraPos(); + CutsceneCommandSetCameraPos(const std::vector& rawData, uint32_t rawDataIndex); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class SpecialActionEntry +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + uint16_t unused0; + uint32_t unused1; + uint32_t unused2; + uint32_t unused3; + uint32_t unused4; + uint32_t unused5; + uint32_t unused6; + uint32_t unused7; + uint32_t unused8; + uint32_t unused9; + uint32_t unused10; + + SpecialActionEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandSpecialAction : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandSpecialAction(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandSpecialAction(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class MusicFadeEntry +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + uint16_t unknown0; + uint32_t unknown1; + uint32_t unknown2; + uint32_t unknown3; + uint32_t unknown4; + uint32_t unknown5; + uint32_t unknown6; + uint32_t unknown7; + uint32_t unknown8; + uint32_t unknown9; + uint32_t unknown10; + + MusicFadeEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandFadeBGM : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandFadeBGM(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandFadeBGM(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class MusicChangeEntry +{ +public: + uint16_t sequence; + uint16_t startFrame; + uint16_t endFrame; + uint16_t unknown0; + uint32_t unknown1; + uint32_t unknown2; + uint32_t unknown3; + uint32_t unknown4; + uint32_t unknown5; + uint32_t unknown6; + uint32_t unknown7; + + MusicChangeEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandPlayBGM : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandPlayBGM(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandPlayBGM(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class CutsceneCommandStopBGM : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandStopBGM(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandStopBGM(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class EnvLightingEntry +{ +public: + uint16_t setting; + uint16_t startFrame; + uint16_t endFrame; + uint16_t unused0; + uint32_t unused1; + uint32_t unused2; + uint32_t unused3; + uint32_t unused4; + uint32_t unused5; + uint32_t unused6; + uint32_t unused7; + + EnvLightingEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandEnvLighting : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandEnvLighting(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandEnvLighting(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class CutsceneCommandSceneTransFX : public CutsceneCommand +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + ~CutsceneCommandSceneTransFX(); + CutsceneCommandSceneTransFX(const std::vector& rawData, uint32_t rawDataIndex); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class Unknown9Entry +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + uint16_t unk2; + uint16_t unk3; + uint16_t unk4; + uint8_t unused0; + uint8_t unused1; + + Unknown9Entry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandUnknown9 : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandUnknown9(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandUnknown9(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class UnkEntry +{ +public: + uint32_t unused0; + uint32_t unused1; + uint32_t unused2; + uint32_t unused3; + uint32_t unused4; + uint32_t unused5; + uint32_t unused6; + uint32_t unused7; + uint32_t unused8; + uint32_t unused9; + uint32_t unused10; + uint32_t unused11; + + UnkEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandUnknown : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandUnknown(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandUnknown(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class DayTimeEntry +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + uint8_t hour; + uint8_t minute; + uint8_t unused; + + DayTimeEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandDayTime : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandDayTime(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandDayTime(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class TextboxEntry +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + uint16_t type; + uint16_t textID1; + uint16_t textID2; + + TextboxEntry(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandTextbox : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandTextbox(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandTextbox(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class ActorAction +{ +public: + uint16_t action; + uint16_t startFrame; + uint16_t endFrame; + int16_t rotX, rotY, rotZ; + int32_t startPosX, startPosY, startPosZ; + int32_t endPosX, endPosY, endPosZ; + float normalX, normalY, normalZ; + + ActorAction(const std::vector& rawData, uint32_t rawDataIndex); +}; + +class CutsceneCommandActorAction : public CutsceneCommand +{ +public: + std::vector entries; + + CutsceneCommandActorAction(const std::vector& rawData, uint32_t rawDataIndex); + ~CutsceneCommandActorAction(); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class CutsceneCommandTerminator : public CutsceneCommand +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + uint16_t unknown; + + CutsceneCommandTerminator(const std::vector& rawData, uint32_t rawDataIndex); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class CutsceneCommandEnd : public CutsceneCommand +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + + CutsceneCommandEnd(const std::vector& rawData, uint32_t rawDataIndex); + std::string GetCName(); + std::string GenerateSourceCode(uint32_t baseAddress); + size_t GetCommandSize(); +}; + +class CutsceneCommandNop : public CutsceneCommand +{ +public: + uint16_t base; + uint16_t startFrame; + uint16_t endFrame; + + CutsceneCommandNop(const std::vector& rawData, uint32_t rawDataIndex); + std::string GetCName(); + size_t GetCommandSize(); +}; + +class ZCutsceneBase : public ZResource +{ +public: + ZCutsceneBase(ZFile* nParent); + + Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override; + + std::string GetSourceTypeName() const override; +}; + +class ZCutscene : public ZCutsceneBase +{ +public: + ZCutscene(ZFile* nParent); + ~ZCutscene(); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + size_t GetRawDataSize() const override; + + ZResourceType GetResourceType() const override; + + CutsceneCommands GetCommandFromID(int32_t id); + + int32_t numCommands; + int32_t endFrame; + std::vector commands; +}; diff --git a/ZAPDTR/ZAPD/ZCutsceneMM.cpp b/ZAPDTR/ZAPD/ZCutsceneMM.cpp new file mode 100644 index 000000000..d0208bc07 --- /dev/null +++ b/ZAPDTR/ZAPD/ZCutsceneMM.cpp @@ -0,0 +1,61 @@ +#include "ZCutsceneMM.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" + +ZCutsceneMM::ZCutsceneMM(ZFile* nParent) : ZCutsceneBase(nParent) +{ +} + +ZCutsceneMM::~ZCutsceneMM() +{ + for (CutsceneCommand* cmd : commands) + delete cmd; +} + +std::string ZCutsceneMM::GetBodySourceCode() const +{ + std::string output; + + output += StringHelper::Sprintf(" CS_BEGIN_CUTSCENE(%i, %i),", numCommands, endFrame); + + for (size_t i = 0; i < data.size(); i++) + { + if ((i % 4) == 0) + output += "\n "; + output += StringHelper::Sprintf("0x%08X, ", data[i]); + } + + return output; +} + +size_t ZCutsceneMM::GetRawDataSize() const +{ + return 8 + data.size() * 4; +} + +void ZCutsceneMM::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + numCommands = BitConverter::ToInt32BE(rawData, rawDataIndex + 0); + commands = std::vector(); + + endFrame = BitConverter::ToInt32BE(rawData, rawDataIndex + 4); + uint32_t currentPtr = rawDataIndex + 8; + uint32_t lastData = 0; + + // TODO currently cutscenes aren't being parsed, so just consume words until we see an end + // marker. + do + { + lastData = BitConverter::ToInt32BE(rawData, currentPtr); + data.push_back(lastData); + currentPtr += 4; + } while (lastData != 0xFFFFFFFF); +} + +ZResourceType ZCutsceneMM::GetResourceType() const +{ + return ZResourceType::Cutscene; +} diff --git a/ZAPDTR/ZAPD/ZCutsceneMM.h b/ZAPDTR/ZAPD/ZCutsceneMM.h new file mode 100644 index 000000000..44b108d6c --- /dev/null +++ b/ZAPDTR/ZAPD/ZCutsceneMM.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include "ZCutscene.h" +#include "ZFile.h" +#include "tinyxml2.h" + +class ZCutsceneMM : public ZCutsceneBase +{ +public: + ZCutsceneMM(ZFile* nParent); + virtual ~ZCutsceneMM(); + + std::string GetBodySourceCode() const override; + + size_t GetRawDataSize() const override; + + void ParseRawData() override; + ZResourceType GetResourceType() const override; + +protected: + int32_t numCommands; + int32_t endFrame; + std::vector commands; + + std::vector data; +}; diff --git a/ZAPDTR/ZAPD/ZDisplayList.cpp b/ZAPDTR/ZAPD/ZDisplayList.cpp new file mode 100644 index 000000000..4c7dd7c17 --- /dev/null +++ b/ZAPDTR/ZAPD/ZDisplayList.cpp @@ -0,0 +1,2121 @@ +#include "ZDisplayList.h" + +#include +#include +#include +#include +#include + +#include "Globals.h" +#include "OutputFormatter.h" +#include "Utils/BitConverter.h" +#include "Utils/File.h" +#include "Utils/Path.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "gfxd.h" + +REGISTER_ZFILENODE(DList, ZDisplayList); + +ZDisplayList::ZDisplayList(ZFile* nParent) : ZResource(nParent) +{ + lastTexWidth = 0; + lastTexHeight = 0; + lastTexAddr = 0; + lastTexFmt = F3DZEXTexFormats::G_IM_FMT_RGBA; + lastTexSiz = F3DZEXTexSizes::G_IM_SIZ_16b; + lastTexSizTest = F3DZEXTexSizes::G_IM_SIZ_16b; + lastTexLoaded = false; + lastTexIsPalette = false; + dListType = Globals::Instance->game == ZGame::OOT_SW97 ? DListType::F3DEX : DListType::F3DZEX; + genOTRDef = true; + RegisterOptionalAttribute("Ucode"); +} + +ZDisplayList::~ZDisplayList() +{ + for (auto o : otherDLists) + { + delete o; + } +} + +// EXTRACT MODE +void ZDisplayList::ExtractFromXML(tinyxml2::XMLElement* reader, uint32_t nRawDataIndex) +{ + rawDataIndex = nRawDataIndex; + ParseXML(reader); + // TODO add error handling here + bool ucodeSet = registeredAttributes.at("Ucode").wasSet; + std::string ucodeValue = registeredAttributes.at("Ucode").value; + if ((Globals::Instance->game == ZGame::OOT_SW97) || (ucodeValue == "f3dex")) + { + dListType = DListType::F3DEX; + } + else if (!ucodeSet || ucodeValue == "f3dex2") + { + dListType = DListType::F3DZEX; + } + else + { + HANDLE_ERROR_RESOURCE( + WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("Invalid ucode type in node: %s\n", reader->Name()), ""); + } + + // Don't parse raw data of external files + if (parent->GetMode() != ZFileMode::ExternalFile) + { + int32_t rawDataSize = + ZDisplayList::GetDListLength(parent->GetRawData(), rawDataIndex, dListType); + numInstructions = rawDataSize / 8; + ParseRawData(); + } + + Declaration* decl = DeclareVar("", ""); + decl->declaredInXml = true; +} + +void ZDisplayList::ExtractFromBinary(uint32_t nRawDataIndex, int32_t rawDataSize) +{ + rawDataIndex = nRawDataIndex; + name = GetDefaultName(parent->GetName()); + numInstructions = rawDataSize / 8; + + // Don't parse raw data of external files + if (parent->GetMode() == ZFileMode::ExternalFile) + return; + + ParseRawData(); +} + +void ZDisplayList::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + instructions.reserve(numInstructions); + uint32_t ptr = rawDataIndex; + + for (size_t i = 0; i < numInstructions; i++) + { + instructions.push_back(BitConverter::ToUInt64BE(rawData, ptr)); + ptr += 8; + } +} + +Declaration* ZDisplayList::DeclareVar([[maybe_unused]] const std::string& prefix, + const std::string& bodyStr) +{ + Declaration* decl = + parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(), + GetSourceTypeName(), name, numInstructions, bodyStr); + decl->isExternal = true; + decl->staticConf = staticConf; + return decl; +} + +std::string ZDisplayList::GetDefaultName(const std::string& prefix) const +{ + return StringHelper::Sprintf("%sDL_%06X", prefix.c_str(), rawDataIndex); +} + +void ZDisplayList::ParseF3DZEX(F3DZEXOpcode opcode, uint64_t data, int32_t i, + const std::string& prefix, char* line) +{ + switch (opcode) + { + case F3DZEXOpcode::G_NOOP: + sprintf(line, "gsDPNoOpTag(0x%08" PRIX64 "),", data & 0xFFFFFFFF); + break; + case F3DZEXOpcode::G_DL: + Opcode_G_DL(data, prefix, line); + break; + case F3DZEXOpcode::G_MODIFYVTX: + Opcode_G_MODIFYVTX(data, line); + break; + case F3DZEXOpcode::G_CULLDL: + Opcode_G_CULLDL(data, line); + break; + case F3DZEXOpcode::G_TRI1: + Opcode_G_TRI1(data, line); + break; + case F3DZEXOpcode::G_TRI2: + Opcode_G_TRI2(data, line); + break; + case F3DZEXOpcode::G_QUAD: + { + int32_t aa = ((data & 0x00FF000000000000ULL) >> 48) / 2; + int32_t bb = ((data & 0x0000FF0000000000ULL) >> 40) / 2; + int32_t cc = ((data & 0x000000FF00000000ULL) >> 32) / 2; + int32_t dd = ((data & 0x000000000000FFULL)) / 2; + sprintf(line, "gsSP1Quadrangle(%i, %i, %i, %i, 0),", aa, bb, cc, dd); + } + break; + case F3DZEXOpcode::G_VTX: + Opcode_G_VTX(data, line); + break; + case F3DZEXOpcode::G_SETTIMG: // HOTSPOT + Opcode_G_SETTIMG(data, prefix, line); + break; + case F3DZEXOpcode::G_GEOMETRYMODE: + { + int32_t cccccc = (data & 0x00FFFFFF00000000) >> 32; + int32_t ssssssss = (data & 0xFFFFFFFF); + std::string geoModeStr = "G_TEXTURE_ENABLE"; + + int32_t geoModeParam = ~cccccc; + + if (ssssssss != 0) + geoModeParam = ssssssss; + + if (geoModeParam & 0x00000001) + geoModeStr += " | G_ZBUFFER"; + + if (geoModeParam & 0x00000004) + geoModeStr += " | G_SHADE"; + + if (geoModeParam & 0x00000200) + geoModeStr += " | G_CULL_FRONT"; + + if (geoModeParam & 0x00000400) + geoModeStr += " | G_CULL_BACK"; + + if (geoModeParam & 0x00010000) + geoModeStr += " | G_FOG"; + + if (geoModeParam & 0x00020000) + geoModeStr += " | G_LIGHTING"; + + if (geoModeParam & 0x00040000) + geoModeStr += " | G_TEXTURE_GEN"; + + if (geoModeParam & 0x00080000) + geoModeStr += " | G_TEXTURE_GEN_LINEAR"; + + if (geoModeParam & 0x00200000) + geoModeStr += " | G_SHADING_SMOOTH"; + + if (geoModeParam & 0x00800000) + geoModeStr += " | G_CLIPPING"; + + if (ssssssss != 0) + { + if ((~cccccc & 0xFF000000) != 0) + sprintf(line, "gsSPSetGeometryMode(%s),", geoModeStr.c_str()); + else + sprintf(line, "gsSPLoadGeometryMode(%s),", geoModeStr.c_str()); + } + else + sprintf(line, "gsSPClearGeometryMode(%s),", geoModeStr.c_str()); + } + break; + case F3DZEXOpcode::G_SETPRIMCOLOR: + Opcode_G_SETPRIMCOLOR(data, line); + break; + case F3DZEXOpcode::G_SETOTHERMODE_L: + Opcode_G_SETOTHERMODE_L(data, line); + break; + case F3DZEXOpcode::G_SETOTHERMODE_H: + Opcode_G_SETOTHERMODE_H(data, line); + break; + case F3DZEXOpcode::G_SETTILE: + Opcode_G_SETTILE(data, line); + break; + case F3DZEXOpcode::G_SETTILESIZE: + Opcode_G_SETTILESIZE(data, prefix, line); + break; + case F3DZEXOpcode::G_LOADBLOCK: + Opcode_G_LOADBLOCK(data, line); + break; + case F3DZEXOpcode::G_TEXTURE: + Opcode_G_TEXTURE(data, line); + break; + case F3DZEXOpcode::G_RDPSETOTHERMODE: + { + int32_t hhhhhh = (data & 0x00FFFFFF00000000) >> 32; + int32_t llllllll = (data & 0x00000000FFFFFFFF); + + sprintf(line, "gsDPSetOtherMode(%i, %i),", hhhhhh, llllllll); + } + break; + case F3DZEXOpcode::G_POPMTX: + { + sprintf(line, "gsSPPopMatrix(%" PRIi64 "),", data); + } + break; + case F3DZEXOpcode::G_LOADTLUT: + Opcode_G_LOADTLUT(data, prefix, line); + break; + case F3DZEXOpcode::G_SETENVCOLOR: + { + uint8_t r = (uint8_t)((data & 0xFF000000) >> 24); + uint8_t g = (uint8_t)((data & 0x00FF0000) >> 16); + uint8_t b = (uint8_t)((data & 0xFF00FF00) >> 8); + uint8_t a = (uint8_t)((data & 0x000000FF) >> 0); + + sprintf(line, "gsDPSetEnvColor(%i, %i, %i, %i),", r, g, b, a); + } + break; + case F3DZEXOpcode::G_SETCOMBINE: + { + Opcode_G_SETCOMBINE(data, line); + } + break; + case F3DZEXOpcode::G_RDPLOADSYNC: + sprintf(line, "gsDPLoadSync(),"); + break; + case F3DZEXOpcode::G_RDPPIPESYNC: + sprintf(line, "gsDPPipeSync(),"); + break; + case F3DZEXOpcode::G_RDPTILESYNC: + sprintf(line, "gsDPTileSync(),"); + break; + case F3DZEXOpcode::G_RDPFULLSYNC: + sprintf(line, "gsDPFullSync(),"); + break; + case F3DZEXOpcode::G_ENDDL: + Opcode_G_ENDDL(prefix, line); + break; + case F3DZEXOpcode::G_RDPHALF_1: + { + uint64_t data2 = instructions[i + 1]; + uint32_t h = (data & 0xFFFFFFFF); + F3DZEXOpcode opcode2 = (F3DZEXOpcode)(instructions[i + 1] >> 56); + + if (opcode2 == F3DZEXOpcode::G_BRANCH_Z) + { + uint32_t a = (data2 & 0x00FFF00000000000) >> 44; + uint32_t b = (data2 & 0x00000FFF00000000) >> 32; + uint32_t z = (data2 & 0x00000000FFFFFFFF) >> 0; + + // sprintf(line, "gsDPWord(%i, 0),", h); + sprintf(line, "gsSPBranchLessZraw(%sDlist0x%06X, 0x%02X, 0x%02X),", prefix.c_str(), + h & 0x00FFFFFF, (a / 5) | (b / 2), z); + + ZDisplayList* nList = new ZDisplayList(parent); + nList->ExtractFromBinary( + h & 0x00FFFFFF, GetDListLength(parent->GetRawData(), h & 0x00FFFFFF, dListType)); + nList->SetName(nList->GetDefaultName(prefix)); + otherDLists.push_back(nList); + + i++; + } + } + break; + case F3DZEXOpcode::G_MTX: + Opcode_G_MTX(data, line); + break; + default: + sprintf(line, "// Opcode 0x%02X unimplemented!", (uint32_t)opcode); + break; + } +} + +void ZDisplayList::ParseF3DEX(F3DEXOpcode opcode, uint64_t data, const std::string& prefix, + char* line) +{ + switch (opcode) + { + case F3DEXOpcode::G_NOOP: + sprintf(line, "gsDPNoOpTag(0x%08" PRIX64 "),", data & 0xFFFFFFFF); + break; + case F3DEXOpcode::G_VTX: + Opcode_G_VTX(data, line); + break; + case F3DEXOpcode::G_DL: + Opcode_G_DL(data, prefix, line); + break; + case F3DEXOpcode::G_CULLDL: + Opcode_G_CULLDL(data, line); + break; + case F3DEXOpcode::G_MODIFYVTX: + Opcode_G_MODIFYVTX(data, line); + break; + case F3DEXOpcode::G_MTX: + Opcode_G_MTX(data, line); + break; + case F3DEXOpcode::G_TRI1: + Opcode_G_TRI1(data, line); + break; + case F3DEXOpcode::G_TRI2: + Opcode_G_TRI2(data, line); + break; + case F3DEXOpcode::G_ENDDL: + Opcode_G_ENDDL(prefix, line); + break; + case F3DEXOpcode::G_RDPLOADSYNC: + sprintf(line, "gsDPLoadSync(),"); + break; + case F3DEXOpcode::G_RDPPIPESYNC: + sprintf(line, "gsDPPipeSync(),"); + break; + case F3DEXOpcode::G_RDPTILESYNC: + sprintf(line, "gsDPTileSync(),"); + break; + case F3DEXOpcode::G_RDPFULLSYNC: + sprintf(line, "gsDPFullSync(),"); + break; + case F3DEXOpcode::G_TEXTURE: + Opcode_G_TEXTURE(data, line); + break; + case F3DEXOpcode::G_SETTIMG: + Opcode_G_SETTIMG(data, prefix, line); + break; + case F3DEXOpcode::G_SETTILE: + Opcode_G_SETTILE(data, line); + break; + case F3DEXOpcode::G_SETTILESIZE: + Opcode_G_SETTILESIZE(data, prefix, line); + break; + case F3DEXOpcode::G_LOADBLOCK: + Opcode_G_LOADBLOCK(data, line); + break; + case F3DEXOpcode::G_SETCOMBINE: + Opcode_G_SETCOMBINE(data, line); + break; + case F3DEXOpcode::G_SETPRIMCOLOR: + Opcode_G_SETPRIMCOLOR(data, line); + break; + case F3DEXOpcode::G_SETOTHERMODE_L: + Opcode_G_SETOTHERMODE_L(data, line); + break; + case F3DEXOpcode::G_SETOTHERMODE_H: + Opcode_G_SETOTHERMODE_H(data, line); + break; + case F3DEXOpcode::G_LOADTLUT: + Opcode_G_LOADTLUT(data, prefix, line); + break; + case F3DEXOpcode::G_CLEARGEOMETRYMODE: + case F3DEXOpcode::G_SETGEOMETRYMODE: + { + int32_t cccccc = (data & 0x00FFFFFF00000000) >> 32; + int32_t ssssssss = (data & 0xFFFFFFFF); + std::string geoModeStr = "G_TEXTURE_ENABLE"; + + int32_t geoModeParam = ~cccccc; + + if (ssssssss != 0) + geoModeParam = ssssssss; + + if (geoModeParam & 0x00000002) + geoModeStr += " | G_TEXTURE_ENABLE"; + + if (geoModeParam & 0x00000200) + geoModeStr += " | G_SHADING_SMOOTH"; + + if (geoModeParam & 0x00001000) + geoModeStr += " | G_CULL_FRONT"; + + if (geoModeParam & 0x00002000) + geoModeStr += " | G_CULL_BACK"; + + if (geoModeParam & 0x00000001) + geoModeStr += " | G_ZBUFFER"; + + if (geoModeParam & 0x00000004) + geoModeStr += " | G_SHADE"; + + if (geoModeParam & 0x00010000) + geoModeStr += " | G_FOG"; + + if (geoModeParam & 0x00020000) + geoModeStr += " | G_LIGHTING"; + + if (geoModeParam & 0x00040000) + geoModeStr += " | G_TEXTURE_GEN"; + + if (geoModeParam & 0x00080000) + geoModeStr += " | G_TEXTURE_GEN_LINEAR"; + + if (geoModeParam & 0x00800000) + geoModeStr += " | G_CLIPPING"; + + if (opcode == F3DEXOpcode::G_SETGEOMETRYMODE) + sprintf(line, "gsSPSetGeometryMode(%s),", geoModeStr.c_str()); + else + sprintf(line, "gsSPClearGeometryMode(%s),", geoModeStr.c_str()); + } + break; + default: + sprintf(line, "// Opcode 0x%02X unimplemented!", (uint32_t)opcode); + break; + } +} + +int32_t ZDisplayList::GetDListLength(const std::vector& rawData, uint32_t rawDataIndex, + DListType dListType) +{ + uint8_t endDLOpcode; + uint8_t branchListOpcode; + + if (dListType == DListType::F3DZEX) + { + endDLOpcode = static_cast(F3DZEXOpcode::G_ENDDL); + branchListOpcode = static_cast(F3DZEXOpcode::G_DL); + } + else + { + endDLOpcode = static_cast(F3DEXOpcode::G_ENDDL); + branchListOpcode = static_cast(F3DEXOpcode::G_DL); + } + + uint32_t ptr = rawDataIndex; + size_t rawDataSize = rawData.size(); + while (true) + { + if (ptr >= rawDataSize) + { + std::string errorHeader = + StringHelper::Sprintf("reached end of file when trying to find the end of the " + "DisplayList starting at offset 0x%X", + rawDataIndex); + std::string errorBody = StringHelper::Sprintf("Raw data size: 0x%zX.", rawDataSize); + HANDLE_ERROR_PROCESS(WarningType::Always, errorHeader, errorBody); + } + + uint8_t opcode = rawData.at(ptr); + bool dlNoPush = rawData.at(ptr + 1) == 1; + ptr += 8; + + if (opcode == endDLOpcode || (opcode == branchListOpcode && dlNoPush)) + { + return ptr - rawDataIndex; + } + } +} + +bool ZDisplayList::SequenceCheck(std::vector sequence, int32_t startIndex) +{ + bool success = true; + + for (size_t j = 0; j < sequence.size(); j++) + { + F3DZEXOpcode opcode = (F3DZEXOpcode)(instructions[startIndex + j] >> 56); + + if (sequence[j] != opcode) + { + success = false; + break; + } + } + + if (success) + return true; + + return false; +} + +int32_t ZDisplayList::OptimizationChecks(int32_t startIndex, std::string& output, + const std::string& prefix) +{ + int32_t result = -1; + + result = OptimizationCheck_LoadTextureBlock(startIndex, output, prefix); + + if (result != -1) + return result; + + return -1; +} + +int32_t ZDisplayList::OptimizationCheck_LoadTextureBlock(int32_t startIndex, std::string& output, + [[maybe_unused]] const std::string& prefix) +{ + std::vector sequence = {F3DZEXOpcode::G_SETTIMG, F3DZEXOpcode::G_SETTILE, + F3DZEXOpcode::G_RDPLOADSYNC, F3DZEXOpcode::G_LOADBLOCK, + F3DZEXOpcode::G_RDPPIPESYNC, F3DZEXOpcode::G_SETTILE, + F3DZEXOpcode::G_SETTILESIZE}; + + bool seqRes = SequenceCheck(sequence, startIndex); + + if (seqRes) + { + // gsDPLoadTextureBlock(texAddr, fmt, siz, width, height, pal, cms, cmt, masks, maskt, + // shifts, shiftt) gsDPLoadMultiBlock(texAddr, tmem, rtile, fmt, siz, width, height, pal, + // cms, cmt, masks, maskt, shifts, shiftt) gsDPLoadTextureBlock_4b(texAddr, fmt, width, + // height, pal, cms, cmt, masks, maskt, shifts, shiftt) gsDPLoadMultiBlock_4b(texAddr, tmem, + // rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) + + uint32_t texAddr, tmem, rtile, fmt, siz, sizB, width, height, width2, height2, pal, cms, + cmt, masks, maskt, shifts, shiftt; + std::string texStr; + + // gsDPSetTextureImage + { + uint64_t data = instructions[startIndex + 0]; + + int32_t __ = (data & 0x00FF000000000000) >> 48; + // int32_t www = (data & 0x00000FFF00000000) >> 32; + + fmt = (__ & 0xE0) >> 5; + siz = (__ & 0x18) >> 3; + texAddr = Seg2Filespace(data, parent->baseAddress); + uint32_t segmentNumber = GETSEGNUM(data); + + lastTexSeg = segmentNumber; + + Globals::Instance->GetSegmentedPtrName(data & 0xFFFFFFFF, parent, "", texStr); + } + + // gsDPSetTile + { + uint64_t data = instructions[startIndex + 1]; + + tmem = + (data & 0b0000000000000000111111111111111100000000000000000000000000000000) >> 32; + + cmt = (data & 0b0000000000000000000000000000000000000000000011000000000000000000) >> 18; + maskt = + (data & 0b0000000000000000000000000000000000000000000000111100000000000000) >> 14; + shiftt = + (data & 0b0000000000000000000000000000000000000000000000000011110000000000) >> 10; + cms = (data & 0b0000000000000000000000000000000000000000000000000000001100000000) >> 8; + masks = + (data & 0b0000000000000000000000000000000000000000000000000000000011110000) >> 4; + shifts = (data & 0b0000000000000000000000000000000000000000000000000000000000001111); + + // sprintf(line, "gsDPSetTile(%s, %s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i),", + // fmtTbl[fff].c_str(), sizTbl[ii].c_str(), nnnnnnnnn, mmmmmmmmm, ttt, pppp, cc, aaaa, + // ssss, dd, bbbb, uuuu); + } + + // gsDPLoadSync + + // gsDPLoadBlock + + // gsDPPipeSync + + // gsDPSetTile + { + uint64_t data = instructions[startIndex + 5]; + int32_t __ = (data & 0x00FF000000000000) >> 48; + pal = (data & 0b0000000000000000000000000000000000000000111100000000000000000000) >> 20; + // siz = (__ & 0x18) >> 3; + rtile = + (data & 0b0000000000000000000000000000000011111111000000000000000000000000) >> 24; + sizB = (__ & 0x18) >> 3; + } + + // gsDPSetTileSize + { + uint64_t data = instructions[startIndex + 6]; + int32_t uuu = (data & 0x0000000000FFF000) >> 12; + int32_t vvv = (data & 0x0000000000000FFF); + + int32_t shiftAmtW = 2; + int32_t shiftAmtH = 2; + + if (sizB == (int32_t)F3DZEXTexSizes::G_IM_SIZ_8b && + fmt == (int32_t)F3DZEXTexFormats::G_IM_FMT_IA) + shiftAmtW = 3; + + if (sizB == (int32_t)F3DZEXTexSizes::G_IM_SIZ_4b) + shiftAmtW = 3; + + if (sizB == (int32_t)F3DZEXTexSizes::G_IM_SIZ_4b && + fmt == (int32_t)F3DZEXTexFormats::G_IM_FMT_IA) + shiftAmtH = 3; + + width = (uuu >> shiftAmtW) + 1; + height = (vvv >> shiftAmtH) + 1; + + width2 = (uuu >> 2) + 1; + height2 = (vvv >> 2) + 1; + } + + const char* fmtTbl[] = {"G_IM_FMT_RGBA", "G_IM_FMT_YUV", "G_IM_FMT_CI", "G_IM_FMT_IA", + "G_IM_FMT_I"}; + const char* sizTbl[] = {"G_IM_SIZ_4b", "G_IM_SIZ_8b", "G_IM_SIZ_16b", "G_IM_SIZ_32b"}; + + // output += StringHelper::Sprintf("gsDPLoadTextureBlock(%s, %s, %s, %i, %i, %i, %i, %i, %i, + // %i, %i, %i),", texStr.c_str(), fmtTbl[fmt], sizTbl[siz].c_str(), width, height, + // pal, cms, cmt, masks, maskt, shifts, shiftt); + + if (siz == 2 && sizB == 0) + { + if (tmem != 0) + output += StringHelper::Sprintf( + "gsDPLoadMultiBlock_4b(%s, %i, %i, %s, %i, %i, %i, %i, %i, %i, %i, %i, %i),", + texStr.c_str(), tmem, rtile, fmtTbl[fmt], width2, height2, pal, cms, cmt, masks, + maskt, shifts, shiftt); + else + output += StringHelper::Sprintf( + "gsDPLoadTextureBlock_4b(%s, %s, %i, %i, %i, %i, %i, %i, %i, %i, %i),", + texStr.c_str(), fmtTbl[fmt], width2, height2, pal, cms, cmt, masks, maskt, + shifts, shiftt); + } + else if (siz == 2 && sizB != 0) + { + if (tmem != 0) + output += StringHelper::Sprintf( + "gsDPLoadMultiBlock(%s, %i, %i, %s, %s, %i, %i, %i, %i, %i, %i, %i, %i, %i),", + texStr.c_str(), tmem, rtile, fmtTbl[fmt], sizTbl[sizB], width2, height2, pal, + cms, cmt, masks, maskt, shifts, shiftt); + else + output += StringHelper::Sprintf( + "gsDPLoadTextureBlock(%s, %s, %s, %i, %i, %i, %i, %i, %i, %i, %i, %i),", + texStr.c_str(), fmtTbl[fmt], sizTbl[sizB], width2, height2, pal, cms, cmt, + masks, maskt, shifts, shiftt); + } + else + { + if (siz != sizB) + { + lastTexAddr = texAddr; + lastTexFmt = (F3DZEXTexFormats)fmt; + lastTexWidth = width; + lastTexHeight = height; + lastTexSiz = (F3DZEXTexSizes)siz; + lastTexLoaded = true; + + TextureGenCheck(); + + return -1; + } + + output += StringHelper::Sprintf( + "gsDPLoadMultiBlock(%s, %i, %i, %s, %s, %i, %i, %i, %i, %i, %i, %i, %i, %i),", + texStr.c_str(), tmem, rtile, fmtTbl[fmt], sizTbl[siz], width, height, pal, cms, cmt, + masks, maskt, shifts, shiftt); + } + + lastTexAddr = texAddr; + lastTexFmt = (F3DZEXTexFormats)fmt; + lastTexWidth = width; + lastTexHeight = height; + lastTexSiz = (F3DZEXTexSizes)siz; + lastTexLoaded = true; + + TextureGenCheck(); + + return (int32_t)sequence.size(); + } + + return -1; +} + +void ZDisplayList::Opcode_G_DL(uint64_t data, const std::string& prefix, char* line) +{ + int32_t pp = (data & 0x00FF000000000000) >> 56; + int32_t segNum = GETSEGNUM(data); + + Declaration* dListDecl = nullptr; + + if (parent != nullptr) + dListDecl = parent->GetDeclaration(GETSEGOFFSET(data)); + + if (pp != 0) + { + if (!Globals::Instance->HasSegment(segNum)) + sprintf(line, "gsSPBranchList(0x%08" PRIX64 "),", data & 0xFFFFFFFF); + else if (dListDecl != nullptr) + sprintf(line, "gsSPBranchList(%s),", dListDecl->varName.c_str()); + else + sprintf(line, "gsSPBranchList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), + GETSEGOFFSET(data)); + } + else + { + if (!Globals::Instance->HasSegment(segNum)) + sprintf(line, "gsSPDisplayList(0x%08" PRIX64 "),", data & 0xFFFFFFFF); + else if (dListDecl != nullptr) + sprintf(line, "gsSPDisplayList(%s),", dListDecl->varName.c_str()); + else + sprintf(line, "gsSPDisplayList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), + GETSEGOFFSET(data)); + } + + // if (segNum == 8 || segNum == 9 || segNum == 10 || segNum == 11 || segNum == 12 || segNum == + // 13) // Used for runtime-generated display lists + if (!Globals::Instance->HasSegment(segNum)) + { + if (pp != 0) + sprintf(line, "gsSPBranchList(0x%08" PRIX64 "),", data & 0xFFFFFFFF); + else + sprintf(line, "gsSPDisplayList(0x%08" PRIX64 "),", data & 0xFFFFFFFF); + } + else + { + ZDisplayList* nList = new ZDisplayList(parent); + nList->ExtractFromBinary(GETSEGOFFSET(data), GetDListLength(parent->GetRawData(), + GETSEGOFFSET(data), dListType)); + nList->SetName(nList->GetDefaultName(prefix)); + + otherDLists.push_back(nList); + } +} + +void ZDisplayList::Opcode_G_MODIFYVTX(uint64_t data, char* line) +{ + int32_t ww = (data & 0x00FF000000000000ULL) >> 48; + int32_t nnnn = (data & 0x0000FFFF00000000ULL) >> 32; + int32_t vvvvvvvv = (data & 0x00000000FFFFFFFFULL); + + sprintf(line, "gsSPModifyVertex(%i, %i, %i),", nnnn / 2, ww, vvvvvvvv); +} + +void ZDisplayList::Opcode_G_CULLDL(uint64_t data, char* line) +{ + int32_t vvvv = (data & 0xFFFF00000000) >> 32; + int32_t wwww = (data & 0x0000FFFF); + + sprintf(line, "gsSPCullDisplayList(%i, %i),", vvvv / 2, wwww / 2); +} + +void ZDisplayList::Opcode_G_TRI1(uint64_t data, char* line) +{ + if (dListType == DListType::F3DZEX) + { + int32_t aa = ((data & 0x00FF000000000000ULL) >> 48) / 2; + int32_t bb = ((data & 0x0000FF0000000000ULL) >> 40) / 2; + int32_t cc = ((data & 0x000000FF00000000ULL) >> 32) / 2; + sprintf(line, "gsSP1Triangle(%i, %i, %i, 0),", aa, bb, cc); + } + else + { + int32_t aa = ((data & 0x0000000000FF0000ULL) >> 16) / 2; + int32_t bb = ((data & 0x000000000000FF00ULL) >> 8) / 2; + int32_t cc = ((data & 0x00000000000000FFULL) >> 0) / 2; + sprintf(line, "gsSP1Triangle(%i, %i, %i, 0),", aa, bb, cc); + } +} + +void ZDisplayList::Opcode_G_TRI2(uint64_t data, char* line) +{ + int32_t aa = ((data & 0x00FF000000000000ULL) >> 48) / 2; + int32_t bb = ((data & 0x0000FF0000000000ULL) >> 40) / 2; + int32_t cc = ((data & 0x000000FF00000000ULL) >> 32) / 2; + int32_t dd = ((data & 0x00000000FF0000ULL) >> 16) / 2; + int32_t ee = ((data & 0x0000000000FF00ULL) >> 8) / 2; + int32_t ff = ((data & 0x000000000000FFULL) >> 0) / 2; + sprintf(line, "gsSP2Triangles(%i, %i, %i, 0, %i, %i, %i, 0),", aa, bb, cc, dd, ee, ff); +} + +void ZDisplayList::Opcode_G_MTX(uint64_t data, char* line) +{ + uint32_t pp = 0; + uint32_t mm = (data & 0x00000000FFFFFFFF); + bool push = false; + bool load = false; + bool projection = false; + + if (dListType == DListType::F3DEX) + pp = (data & 0x00FF000000000000) >> 48; + else + pp = (data & 0x000000FF00000000) >> 32; + + std::string matrixRef; + + if (Globals::Instance->cfg.symbolMap.find(mm) != Globals::Instance->cfg.symbolMap.end()) + matrixRef = StringHelper::Sprintf("&%s", Globals::Instance->cfg.symbolMap[mm].c_str()); + else + matrixRef = StringHelper::Sprintf("0x%08X", mm); + + pp ^= 0x01; + + if (pp & 0x01) + push = true; + + if (pp & 0x02) + load = true; + + if (pp & 0x04) + projection = true; + + sprintf(line, "gsSPMatrix(%s, %s | %s | %s),", matrixRef.c_str(), + projection ? "G_MTX_PROJECTION" : "G_MTX_MODELVIEW", + push ? "G_MTX_PUSH" : "G_MTX_NOPUSH", load ? "G_MTX_LOAD" : "G_MTX_MUL"); +} + +void ZDisplayList::Opcode_G_VTX(uint64_t data, char* line) +{ + int32_t nn = (data & 0x000FF00000000000ULL) >> 44; + int32_t aa = (data & 0x000000FF00000000ULL) >> 32; + + uint32_t vtxAddr = Seg2Filespace(data, parent->baseAddress); + + if (dListType == DListType::F3DZEX) + sprintf(line, "gsSPVertex(@r, %i, %i),", nn, ((aa >> 1) - nn)); + else + { + uint32_t hi = data >> 32; + +#define _SHIFTR(v, s, w) (((uint32_t)v >> s) & ((0x01 << w) - 1)) + + nn = _SHIFTR(hi, 10, 6); + + sprintf(line, "gsSPVertex(@r, %i, %i),", nn, _SHIFTR(hi, 17, 7)); + } + + // Hack: Don't extract vertices from a unknown segment. + if (!Globals::Instance->HasSegment(GETSEGNUM(data))) + { + segptr_t segmented = data & 0xFFFFFFFF; + references.push_back(segmented); + parent->AddDeclaration(segmented, DeclarationAlignment::Align8, 16, "Vtx", + StringHelper::Sprintf("0x%08X", segmented), ""); + return; + } + references.push_back(data); + + { + uint32_t currentPtr = Seg2Filespace(data, parent->baseAddress); + Declaration* decl; + + // Check for vertex intersections from other display lists + // TODO: These two could probably be condenced to one... + decl = parent->GetDeclarationRanged(vtxAddr + (nn * 16)); + if (decl != nullptr) + { + int32_t diff = decl->address - vtxAddr; + if (diff > 0) + nn = diff / 16; + else + nn = 0; + } + + decl = parent->GetDeclarationRanged(vtxAddr); + if (decl != nullptr) + { + int32_t diff = decl->address - vtxAddr; + if (diff > 0) + nn = diff / 16; + else + nn = 0; + } + + if (nn > 0) + { + std::vector vtxList; + vtxList.reserve(nn); + + for (int32_t i = 0; i < nn; i++) + { + ZVtx vtx(parent); + vtx.ExtractFromFile(currentPtr); + vtxList.push_back(vtx); + + currentPtr += 16; + } + + vertices[vtxAddr] = vtxList; + } + } +} + +void ZDisplayList::Opcode_G_TEXTURE(uint64_t data, char* line) +{ + int32_t ____ = (data & 0x0000FFFF00000000) >> 32; + int32_t ssss = (data & 0x00000000FFFF0000) >> 16; + int32_t tttt = (data & 0x000000000000FFFF); + int32_t lll = (____ & 0x3800) >> 11; + int32_t ddd = (____ & 0x700) >> 8; + int32_t nnnnnnn = 0; + + if (dListType == DListType::F3DEX) + nnnnnnn = (____ & 0xFF); + else + nnnnnnn = (____ & 0xFE) >> 1; + + sprintf(line, "gsSPTexture(%i, %i, %i, %i, %s),", ssss, tttt, lll, ddd, + nnnnnnn == 1 ? "G_ON" : "G_OFF"); +} + +void ZDisplayList::Opcode_G_SETTIMG(uint64_t data, const std::string& prefix, char* line) +{ + int32_t __ = (data & 0x00FF000000000000) >> 48; + int32_t www = (data & 0x00000FFF00000000) >> 32; + const char* fmtTbl[] = {"G_IM_FMT_RGBA", "G_IM_FMT_YUV", "G_IM_FMT_CI", "G_IM_FMT_IA", + "G_IM_FMT_I"}; + const char* sizTbl[] = {"G_IM_SIZ_4b", "G_IM_SIZ_8b", "G_IM_SIZ_16b", "G_IM_SIZ_32b"}; + + uint32_t fmt = (__ & 0xE0) >> 5; + uint32_t siz = (__ & 0x18) >> 3; + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + printf("TextureGenCheck G_SETTIMG\n"); + + TextureGenCheck(); // HOTSPOT + + lastTexFmt = (F3DZEXTexFormats)fmt; + lastTexSiz = (F3DZEXTexSizes)siz; + lastTexSeg = data; + lastTexAddr = Seg2Filespace(data, parent->baseAddress); + + int32_t segmentNumber = GETSEGNUM(data); + + if (segmentNumber != 2) + { + char texStr[2048]; + int32_t texAddress = Seg2Filespace(data, parent->baseAddress); + Declaration* texDecl = nullptr; + + if (parent != nullptr) + { + if (Globals::Instance->HasSegment(segmentNumber)) + texDecl = parent->GetDeclaration(texAddress); + else + texDecl = parent->GetDeclaration(data); + } + + if (texDecl != nullptr) + sprintf(texStr, "%s", texDecl->varName.c_str()); + else if (data != 0 && Globals::Instance->HasSegment(segmentNumber)) + sprintf(texStr, "%sTex_%06X", prefix.c_str(), texAddress); + else + { + sprintf(texStr, "0x%08" PRIX64, data & 0xFFFFFFFF); + } + + sprintf(line, "gsDPSetTextureImage(%s, %s, %i, %s),", fmtTbl[fmt], sizTbl[siz], www + 1, + texStr); + } + else + { + std::string texName; + Globals::Instance->GetSegmentedPtrName(data, parent, "", texName); + sprintf(line, "gsDPSetTextureImage(%s, %s, %i, %s),", fmtTbl[fmt], sizTbl[siz], www + 1, + texName.c_str()); + } +} + +void ZDisplayList::Opcode_G_SETTILE(uint64_t data, char* line) +{ + int32_t fff = (data & 0b0000000011100000000000000000000000000000000000000000000000000000) >> 53; + int32_t ii = (data & 0b0000000000011000000000000000000000000000000000000000000000000000) >> 51; + int32_t nnnnnnnnn = + (data & 0b0000000000000011111111100000000000000000000000000000000000000000) >> 41; + int32_t mmmmmmmmm = + (data & 0b0000000000000000000000011111111100000000000000000000000000000000) >> 32; + int32_t ttt = (data & 0b0000000000000000000000000000000000000111000000000000000000000000) >> 24; + int32_t pppp = + (data & 0b0000000000000000000000000000000000000000111100000000000000000000) >> 20; + int32_t cc = (data & 0b0000000000000000000000000000000000000000000011000000000000000000) >> 18; + int32_t aaaa = + (data & 0b0000000000000000000000000000000000000000000000111100000000000000) >> 14; + int32_t ssss = + (data & 0b0000000000000000000000000000000000000000000000000011110000000000) >> 10; + int32_t dd = (data & 0b0000000000000000000000000000000000000000000000000000001100000000) >> 8; + int32_t bbbb = (data & 0b0000000000000000000000000000000000000000000000000000000011110000) >> 4; + int32_t uuuu = (data & 0b0000000000000000000000000000000000000000000000000000000000001111); + + const char* fmtTbl[] = {"G_IM_FMT_RGBA", "G_IM_FMT_YUV", "G_IM_FMT_CI", "G_IM_FMT_IA", + "G_IM_FMT_I"}; + const char* sizTbl[] = {"G_IM_SIZ_4b", "G_IM_SIZ_8b", "G_IM_SIZ_16b", "G_IM_SIZ_32b"}; + + if (fff == (int32_t)F3DZEXTexFormats::G_IM_FMT_CI) + lastCISiz = (F3DZEXTexSizes)ii; + + lastTexSizTest = (F3DZEXTexSizes)ii; + + sprintf(line, "gsDPSetTile(%s, %s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i),", fmtTbl[fff], + sizTbl[ii], nnnnnnnnn, mmmmmmmmm, ttt, pppp, cc, aaaa, ssss, dd, bbbb, uuuu); +} + +void ZDisplayList::Opcode_G_SETTILESIZE(uint64_t data, [[maybe_unused]] const std::string& prefix, + char* line) +{ + int32_t sss = (data & 0x00FFF00000000000) >> 44; + int32_t ttt = (data & 0x00000FFF00000000) >> 32; + int32_t uuu = (data & 0x0000000000FFF000) >> 12; + int32_t vvv = (data & 0x0000000000000FFF); + int32_t i = (data & 0x000000000F000000) >> 24; + + int32_t shiftAmtW = 2; + int32_t shiftAmtH = 2; + + if (lastTexSizTest == F3DZEXTexSizes::G_IM_SIZ_8b && + lastTexFmt == F3DZEXTexFormats::G_IM_FMT_IA) + shiftAmtW = 3; + + // if (lastTexFmt == F3DZEXTexFormats::G_IM_FMT_I || lastTexFmt == + // F3DZEXTexFormats::G_IM_FMT_CI) + if (lastTexSizTest == F3DZEXTexSizes::G_IM_SIZ_4b) + shiftAmtW = 3; + + if (lastTexSizTest == F3DZEXTexSizes::G_IM_SIZ_4b && + lastTexFmt == F3DZEXTexFormats::G_IM_FMT_IA) + shiftAmtH = 3; + + lastTexWidth = (uuu >> shiftAmtW) + 1; + lastTexHeight = (vvv >> shiftAmtH) + 1; + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + printf("lastTexWidth: %i lastTexHeight: %i, lastTexSizTest: 0x%x, lastTexFmt: 0x%x\n", + lastTexWidth, lastTexHeight, (uint32_t)lastTexSizTest, (uint32_t)lastTexFmt); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + printf("TextureGenCheck G_SETTILESIZE\n"); + + TextureGenCheck(); + + sprintf(line, "gsDPSetTileSize(%i, %i, %i, %i, %i),", i, sss, ttt, uuu, vvv); +} + +void ZDisplayList::Opcode_G_LOADBLOCK(uint64_t data, char* line) +{ + int32_t sss = (data & 0x00FFF00000000000) >> 48; + int32_t ttt = (data & 0x00000FFF00000000) >> 36; + int32_t i = (data & 0x000000000F000000) >> 24; + int32_t xxx = (data & 0x0000000000FFF000) >> 12; + int32_t ddd = (data & 0x0000000000000FFF); + + lastTexLoaded = true; + + sprintf(line, "gsDPLoadBlock(%i, %i, %i, %i, %i),", i, sss, ttt, xxx, ddd); +} + +void ZDisplayList::Opcode_G_SETCOMBINE(uint64_t data, char* line) +{ + int32_t a0 = (data & 0b000000011110000000000000000000000000000000000000000000000000000) >> 52; + int32_t c0 = (data & 0b000000000001111100000000000000000000000000000000000000000000000) >> 47; + int32_t aa0 = (data & 0b00000000000000011100000000000000000000000000000000000000000000) >> 44; + int32_t ac0 = (data & 0b00000000000000000011100000000000000000000000000000000000000000) >> 41; + int32_t a1 = (data & 0b000000000000000000000011110000000000000000000000000000000000000) >> 37; + int32_t c1 = (data & 0b000000000000000000000000001111100000000000000000000000000000000) >> 32; + int32_t b0 = (data & 0b000000000000000000000000000000011110000000000000000000000000000) >> 28; + int32_t b1 = (data & 0b000000000000000000000000000000000001111000000000000000000000000) >> 24; + int32_t aa1 = (data & 0b00000000000000000000000000000000000000111000000000000000000000) >> 21; + int32_t ac1 = (data & 0b00000000000000000000000000000000000000000111000000000000000000) >> 18; + int32_t d0 = (data & 0b000000000000000000000000000000000000000000000111000000000000000) >> 15; + int32_t ab0 = (data & 0b00000000000000000000000000000000000000000000000111000000000000) >> 12; + int32_t ad0 = (data & 0b00000000000000000000000000000000000000000000000000111000000000) >> 9; + int32_t d1 = (data & 0b000000000000000000000000000000000000000000000000000000111000000) >> 6; + int32_t ab1 = (data & 0b00000000000000000000000000000000000000000000000000000000111000) >> 3; + int32_t ad1 = (data & 0b00000000000000000000000000000000000000000000000000000000000111) >> 0; + + const char* modesA[] = {"COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", + "1", "NOISE", "0", "9", "10", "11", + "12", "13", "14", "0"}; + const char* modesB[] = {"COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", + "CENTER", "K4", "8", "9", "10", "11", + "12", "13", "14", "0"}; + const char* modesC[] = {"COMBINED", + "TEXEL0", + "TEXEL1", + "PRIMITIVE", + "SHADE", + "ENVIRONMENT", + "1", + "COMBINED_ALPHA", + "TEXEL0_ALPHA", + "TEXEL1_ALPHA", + "PRIMITIVE_ALPHA", + "SHADE_ALPHA", + "ENV_ALPHA", + "LOD_FRACTION", + "PRIM_LOD_FRAC", + "K5", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "0"}; + const char* modesD[] = {"COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIRONMENT", "1", "0"}; + + const char* modes2[] = {"COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIRONMENT", "1", "0"}; + const char* modes2C[] = {"LOD_FRACTION", "TEXEL0", "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIRONMENT", "PRIM_LOD_FRAC", "0"}; + + sprintf(line, + "gsDPSetCombineLERP(%s, %s, %s, %s, %s, %s, %s, %s,\n %s, %s, " + "%s, %s, %s, %s, %s, %s),", + modesA[a0], modesB[b0], modesC[c0], modesD[d0], modes2[aa0], modes2[ab0], modes2C[ac0], + modes2[ad0], modesA[a1], modesB[b1], modesC[c1], modesD[d1], modes2[aa1], modes2[ab1], + modes2C[ac1], modes2[ad1]); +} + +void ZDisplayList::Opcode_G_SETPRIMCOLOR(uint64_t data, char* line) +{ + int32_t mm = (data & 0x0000FF0000000000) >> 40; + int32_t ff = (data & 0x000000FF00000000) >> 32; + int32_t rr = (data & 0x00000000FF000000) >> 24; + int32_t gg = (data & 0x0000000000FF0000) >> 16; + int32_t bb = (data & 0x000000000000FF00) >> 8; + int32_t aa = (data & 0x00000000000000FF) >> 0; + sprintf(line, "gsDPSetPrimColor(%i, %i, %i, %i, %i, %i),", mm, ff, rr, gg, bb, aa); +} + +void ZDisplayList::Opcode_F3DEX_G_SETOTHERMODE_L(uint64_t data, char* line) +{ + int32_t sft = (data & 0x0000FF0000000000) >> 40; + int32_t len = (data & 0x000000FF00000000) >> 32; + int32_t dat = (data & 0xFFFFFFFF); + + // TODO: Output the correct render modes in data + + sprintf(line, "gsSPSetOtherMode(0xE2, %i, %i, 0x%08X),", sft, len, dat); +} + +void ZDisplayList::Opcode_G_SETOTHERMODE_L(uint64_t data, char* line) +{ + int32_t dd = (data & 0xFFFFFFFF); + int32_t sft = 0; + int32_t len = 0; + + if (dListType == DListType::F3DEX) + { + sft = (data & 0x0000FF0000000000) >> 40; + len = (data & 0x000000FF00000000) >> 32; + } + else + { + int32_t ss = (data & 0x0000FF0000000000) >> 40; + len = ((data & 0x000000FF00000000) >> 32) + 1; + sft = 32 - (len)-ss; + } + + if (sft == G_MDSFT_RENDERMODE) + { + uint32_t mode1 = (dd & 0xCCCC0000) >> 0; + uint32_t mode2 = (dd & 0x3333FFFF); + + // TODO: Jesus Christ This is Messy + + uint32_t tblA[] = {G_RM_FOG_SHADE_A, + G_RM_FOG_PRIM_A, + G_RM_PASS, + G_RM_AA_ZB_OPA_SURF, + G_RM_AA_ZB_XLU_SURF, + G_RM_AA_ZB_OPA_DECAL, + G_RM_AA_ZB_XLU_DECAL, + G_RM_AA_ZB_OPA_INTER, + G_RM_AA_ZB_XLU_INTER, + G_RM_AA_ZB_XLU_LINE, + G_RM_AA_ZB_DEC_LINE, + G_RM_AA_ZB_TEX_EDGE, + G_RM_AA_ZB_TEX_INTER, + G_RM_AA_ZB_SUB_SURF, + G_RM_AA_ZB_PCL_SURF, + G_RM_AA_ZB_OPA_TERR, + G_RM_AA_ZB_TEX_TERR, + G_RM_AA_ZB_SUB_TERR, + G_RM_RA_ZB_OPA_SURF, + G_RM_RA_ZB_OPA_DECAL, + G_RM_RA_ZB_OPA_INTER, + G_RM_AA_OPA_SURF, + G_RM_AA_XLU_SURF, + G_RM_AA_XLU_LINE, + G_RM_AA_DEC_LINE, + G_RM_AA_TEX_EDGE, + G_RM_AA_SUB_SURF, + G_RM_AA_PCL_SURF, + G_RM_AA_OPA_TERR, + G_RM_AA_TEX_TERR, + G_RM_AA_SUB_TERR, + G_RM_RA_OPA_SURF, + G_RM_ZB_OPA_SURF, + G_RM_ZB_XLU_SURF, + G_RM_ZB_OPA_DECAL, + G_RM_ZB_XLU_DECAL, + G_RM_ZB_CLD_SURF, + G_RM_ZB_OVL_SURF, + G_RM_ZB_PCL_SURF, + G_RM_OPA_SURF, + G_RM_XLU_SURF, + G_RM_CLD_SURF, + G_RM_TEX_EDGE, + G_RM_PCL_SURF, + G_RM_ADD, + G_RM_NOOP, + G_RM_VISCVG, + G_RM_OPA_CI}; + + uint32_t tblB[] = {G_RM_AA_ZB_OPA_SURF2, + G_RM_AA_ZB_XLU_SURF2, + G_RM_AA_ZB_OPA_DECAL2, + G_RM_AA_ZB_XLU_DECAL2, + G_RM_AA_ZB_OPA_INTER2, + G_RM_AA_ZB_XLU_INTER2, + G_RM_AA_ZB_XLU_LINE2, + G_RM_AA_ZB_DEC_LINE2, + G_RM_AA_ZB_TEX_EDGE2, + G_RM_AA_ZB_TEX_INTER2, + G_RM_AA_ZB_SUB_SURF2, + G_RM_AA_ZB_PCL_SURF2, + G_RM_AA_ZB_OPA_TERR2, + G_RM_AA_ZB_TEX_TERR2, + G_RM_AA_ZB_SUB_TERR2, + G_RM_RA_ZB_OPA_SURF2, + G_RM_RA_ZB_OPA_DECAL2, + G_RM_RA_ZB_OPA_INTER2, + G_RM_AA_OPA_SURF2, + G_RM_AA_XLU_SURF2, + G_RM_AA_XLU_LINE2, + G_RM_AA_DEC_LINE2, + G_RM_AA_TEX_EDGE2, + G_RM_AA_SUB_SURF2, + G_RM_AA_PCL_SURF2, + G_RM_AA_OPA_TERR2, + G_RM_AA_TEX_TERR2, + G_RM_AA_SUB_TERR2, + G_RM_RA_OPA_SURF2, + G_RM_ZB_OPA_SURF2, + G_RM_ZB_XLU_SURF2, + G_RM_ZB_OPA_DECAL2, + G_RM_ZB_XLU_DECAL2, + G_RM_ZB_CLD_SURF2, + G_RM_ZB_OVL_SURF2, + G_RM_ZB_PCL_SURF2, + G_RM_OPA_SURF2, + G_RM_XLU_SURF2, + G_RM_CLD_SURF2, + G_RM_TEX_EDGE2, + G_RM_PCL_SURF2, + G_RM_ADD2, + G_RM_NOOP2, + G_RM_VISCVG2, + G_RM_OPA_CI2}; + + std::map str = { + {G_RM_FOG_SHADE_A, "G_RM_FOG_SHADE_A"}, + {G_RM_FOG_PRIM_A, "G_RM_FOG_PRIM_A"}, + {G_RM_PASS, "G_RM_PASS"}, + {G_RM_AA_ZB_OPA_SURF, "G_RM_AA_ZB_OPA_SURF"}, + {G_RM_AA_ZB_OPA_SURF2, "G_RM_AA_ZB_OPA_SURF2"}, + {G_RM_AA_ZB_XLU_SURF, "G_RM_AA_ZB_XLU_SURF"}, + {G_RM_AA_ZB_XLU_SURF2, "G_RM_AA_ZB_XLU_SURF2"}, + {G_RM_AA_ZB_OPA_DECAL, "G_RM_AA_ZB_OPA_DECAL"}, + {G_RM_AA_ZB_OPA_DECAL2, "G_RM_AA_ZB_OPA_DECAL2"}, + {G_RM_AA_ZB_XLU_DECAL, "G_RM_AA_ZB_XLU_DECAL"}, + {G_RM_AA_ZB_XLU_DECAL2, "G_RM_AA_ZB_XLU_DECAL2"}, + {G_RM_AA_ZB_OPA_INTER, "G_RM_AA_ZB_OPA_INTER"}, + {G_RM_AA_ZB_OPA_INTER2, "G_RM_AA_ZB_OPA_INTER2"}, + {G_RM_AA_ZB_XLU_INTER, "G_RM_AA_ZB_XLU_INTER"}, + {G_RM_AA_ZB_XLU_INTER2, "G_RM_AA_ZB_XLU_INTER2"}, + {G_RM_AA_ZB_XLU_LINE, "G_RM_AA_ZB_XLU_LINE"}, + {G_RM_AA_ZB_XLU_LINE2, "G_RM_AA_ZB_XLU_LINE2"}, + {G_RM_AA_ZB_DEC_LINE, "G_RM_AA_ZB_DEC_LINE"}, + {G_RM_AA_ZB_DEC_LINE2, "G_RM_AA_ZB_DEC_LINE2"}, + {G_RM_AA_ZB_TEX_EDGE, "G_RM_AA_ZB_TEX_EDGE"}, + {G_RM_AA_ZB_TEX_EDGE2, "G_RM_AA_ZB_TEX_EDGE2"}, + {G_RM_AA_ZB_TEX_INTER, "G_RM_AA_ZB_TEX_INTER"}, + {G_RM_AA_ZB_TEX_INTER2, "G_RM_AA_ZB_TEX_INTER2"}, + {G_RM_AA_ZB_SUB_SURF, "G_RM_AA_ZB_SUB_SURF"}, + {G_RM_AA_ZB_SUB_SURF2, "G_RM_AA_ZB_SUB_SURF2"}, + {G_RM_AA_ZB_PCL_SURF, "G_RM_AA_ZB_PCL_SURF"}, + {G_RM_AA_ZB_PCL_SURF2, "G_RM_AA_ZB_PCL_SURF2"}, + {G_RM_AA_ZB_OPA_TERR, "G_RM_AA_ZB_OPA_TERR"}, + {G_RM_AA_ZB_OPA_TERR2, "G_RM_AA_ZB_OPA_TERR2"}, + {G_RM_AA_ZB_TEX_TERR, "G_RM_AA_ZB_TEX_TERR"}, + {G_RM_AA_ZB_TEX_TERR2, "G_RM_AA_ZB_TEX_TERR2"}, + {G_RM_AA_ZB_SUB_TERR, "G_RM_AA_ZB_SUB_TERR"}, + {G_RM_AA_ZB_SUB_TERR2, "G_RM_AA_ZB_SUB_TERR2"}, + {G_RM_RA_ZB_OPA_SURF, "G_RM_RA_ZB_OPA_SURF"}, + {G_RM_RA_ZB_OPA_SURF2, "G_RM_RA_ZB_OPA_SURF2"}, + {G_RM_RA_ZB_OPA_DECAL, "G_RM_RA_ZB_OPA_DECAL"}, + {G_RM_RA_ZB_OPA_DECAL2, "G_RM_RA_ZB_OPA_DECAL2"}, + {G_RM_RA_ZB_OPA_INTER, "G_RM_RA_ZB_OPA_INTER"}, + {G_RM_RA_ZB_OPA_INTER2, "G_RM_RA_ZB_OPA_INTER2"}, + {G_RM_AA_OPA_SURF, "G_RM_AA_OPA_SURF"}, + {G_RM_AA_OPA_SURF2, "G_RM_AA_OPA_SURF2"}, + {G_RM_AA_XLU_SURF, "G_RM_AA_XLU_SURF"}, + {G_RM_AA_XLU_SURF2, "G_RM_AA_XLU_SURF2"}, + {G_RM_AA_XLU_LINE, "G_RM_AA_XLU_LINE"}, + {G_RM_AA_XLU_LINE2, "G_RM_AA_XLU_LINE2"}, + {G_RM_AA_DEC_LINE, "G_RM_AA_DEC_LINE"}, + {G_RM_AA_DEC_LINE2, "G_RM_AA_DEC_LINE2"}, + {G_RM_AA_TEX_EDGE, "G_RM_AA_TEX_EDGE"}, + {G_RM_AA_TEX_EDGE2, "G_RM_AA_TEX_EDGE2"}, + {G_RM_AA_SUB_SURF, "G_RM_AA_SUB_SURF"}, + {G_RM_AA_SUB_SURF2, "G_RM_AA_SUB_SURF2"}, + {G_RM_AA_PCL_SURF, "G_RM_AA_PCL_SURF"}, + {G_RM_AA_PCL_SURF2, "G_RM_AA_PCL_SURF2"}, + {G_RM_AA_OPA_TERR, "G_RM_AA_OPA_TERR"}, + {G_RM_AA_OPA_TERR2, "G_RM_AA_OPA_TERR2"}, + {G_RM_AA_TEX_TERR, "G_RM_AA_TEX_TERR"}, + {G_RM_AA_TEX_TERR2, "G_RM_AA_TEX_TERR2"}, + {G_RM_AA_TEX_TERR, "G_RM_AA_TEX_TERR"}, + {G_RM_AA_TEX_TERR2, "G_RM_AA_TEX_TERR2"}, + {G_RM_AA_SUB_TERR, "G_RM_AA_SUB_TERR"}, + {G_RM_AA_SUB_TERR2, "G_RM_AA_SUB_TERR2"}, + {G_RM_RA_OPA_SURF, "G_RM_RA_OPA_SURF"}, + {G_RM_RA_OPA_SURF2, "G_RM_RA_OPA_SURF2"}, + {G_RM_ZB_OPA_SURF, "G_RM_ZB_OPA_SURF"}, + {G_RM_ZB_OPA_SURF2, "G_RM_ZB_OPA_SURF2"}, + {G_RM_ZB_XLU_SURF, "G_RM_ZB_XLU_SURF"}, + {G_RM_ZB_XLU_SURF2, "G_RM_ZB_XLU_SURF2"}, + {G_RM_ZB_OPA_DECAL, "G_RM_ZB_OPA_DECAL"}, + {G_RM_ZB_OPA_DECAL2, "G_RM_ZB_OPA_DECAL2"}, + {G_RM_ZB_XLU_DECAL, "G_RM_ZB_XLU_DECAL"}, + {G_RM_ZB_XLU_DECAL2, "G_RM_ZB_XLU_DECAL2"}, + {G_RM_ZB_CLD_SURF, "G_RM_ZB_CLD_SURF"}, + {G_RM_ZB_CLD_SURF2, "G_RM_ZB_CLD_SURF2"}, + {G_RM_ZB_OVL_SURF, "G_RM_ZB_OVL_SURF"}, + {G_RM_ZB_OVL_SURF2, "G_RM_ZB_OVL_SURF2"}, + {G_RM_ZB_PCL_SURF, "G_RM_ZB_PCL_SURF"}, + {G_RM_ZB_PCL_SURF2, "G_RM_ZB_PCL_SURF2"}, + {G_RM_OPA_SURF, "G_RM_OPA_SURF"}, + {G_RM_OPA_SURF2, "G_RM_OPA_SURF2"}, + {G_RM_XLU_SURF, "G_RM_XLU_SURF"}, + {G_RM_XLU_SURF2, "G_RM_XLU_SURF2"}, + {G_RM_CLD_SURF, "G_RM_CLD_SURF"}, + {G_RM_CLD_SURF2, "G_RM_CLD_SURF2"}, + {G_RM_TEX_EDGE, "G_RM_TEX_EDGE"}, + {G_RM_TEX_EDGE2, "G_RM_TEX_EDGE2"}, + {G_RM_PCL_SURF, "G_RM_PCL_SURF"}, + {G_RM_PCL_SURF2, "G_RM_PCL_SURF2"}, + {G_RM_ADD, "G_RM_ADD"}, + {G_RM_ADD2, "G_RM_ADD2"}, + {G_RM_NOOP, "G_RM_NOOP"}, + {G_RM_NOOP2, "G_RM_NOOP2"}, + {G_RM_VISCVG, "G_RM_VISCVG"}, + {G_RM_VISCVG2, "G_RM_VISCVG2"}, + {G_RM_OPA_CI, "G_RM_OPA_CI"}, + {G_RM_OPA_CI2, "G_RM_OPA_CI2"}, + }; + + for (uint32_t k = 0; k < sizeof(tblA) / 4; k++) + { + if ((dd & tblA[k]) == tblA[k]) + { + if (tblA[k] > mode1) + mode1 = tblA[k]; + } + } + + for (uint32_t k = 0; k < sizeof(tblB) / 4; k++) + { + if ((dd & tblB[k]) == tblB[k]) + { + if (tblB[k] > mode2) + mode2 = tblB[k]; + } + } + + std::string mode1Str = str[mode1]; + std::string mode2Str = str[mode2]; + + if (mode1Str == "") + { + mode1Str = StringHelper::Sprintf("0x%08X", mode1); + } + + if (mode2Str == "") + { + if (mode2 & AA_EN) + { + mode2Str += "AA_EN | "; + } + + if (mode2 & Z_CMP) + { + mode2Str += "Z_CMP | "; + } + + if (mode2 & Z_UPD) + { + mode2Str += "Z_UPD | "; + } + + if (mode2 & IM_RD) + { + mode2Str += "IM_RD | "; + } + + if (mode2 & CLR_ON_CVG) + { + mode2Str += "CLR_ON_CVG | "; + } + + if (mode2 & CVG_DST_CLAMP) + { + mode2Str += "CVG_DST_CLAMP | "; + } + + if (mode2 & CVG_DST_WRAP) + { + mode2Str += "CVG_DST_WRAP | "; + } + + if (mode2 & CVG_DST_FULL) + { + mode2Str += "CVG_DST_FULL | "; + } + + if (mode2 & CVG_DST_SAVE) + { + mode2Str += "CVG_DST_SAVE | "; + } + + int32_t zMode = mode2 & 0xC00; + + if (zMode == ZMODE_INTER) + { + mode2Str += "ZMODE_INTER | "; + } + else if (zMode == ZMODE_XLU) + { + mode2Str += "ZMODE_XLU | "; + } + else if (zMode == ZMODE_DEC) + { + mode2Str += "ZMODE_DEC | "; + } + + if (mode2 & CVG_X_ALPHA) + { + mode2Str += "CVG_X_ALPHA | "; + } + + if (mode2 & ALPHA_CVG_SEL) + { + mode2Str += "ALPHA_CVG_SEL | "; + } + + if (mode2 & FORCE_BL) + { + mode2Str += "FORCE_BL | "; + } + + int32_t bp = (mode2 >> 28) & 0b11; + int32_t ba = (mode2 >> 24) & 0b11; + int32_t bm = (mode2 >> 20) & 0b11; + int32_t bb = (mode2 >> 16) & 0b11; + + mode2Str += StringHelper::Sprintf("GBL_c2(%i, %i, %i, %i)", bp, ba, bm, bb); + // mode2Str = StringHelper::Sprintf("0x%08X", mode2); + } + + sprintf(line, "gsDPSetRenderMode(%s, %s),", mode1Str.c_str(), mode2Str.c_str()); + } + else + { + sprintf(line, "gsSPSetOtherMode(0xE2, %i, %i, 0x%08X),", sft, len, dd); + } +} + +void ZDisplayList::Opcode_G_SETOTHERMODE_H(uint64_t data, char* line) +{ + int32_t ss = (data & 0x0000FF0000000000) >> 40; + int32_t nn = (data & 0x000000FF00000000) >> 32; + int32_t dd = (data & 0xFFFFFFFF); + + int32_t sft = 32 - (nn + 1) - ss; + + if (sft == 14) // G_MDSFT_TEXTLUT + { + const char* types[] = {"G_TT_NONE", "G_TT_NONE", "G_TT_RGBA16", "G_TT_IA16"}; + sprintf(line, "gsDPSetTextureLUT(%s),", types[dd >> 14]); + } + else + sprintf(line, "gsSPSetOtherMode(0xE3, %i, %i, 0x%08X),", sft, nn + 1, dd); +} + +void ZDisplayList::Opcode_G_LOADTLUT(uint64_t data, [[maybe_unused]] const std::string& prefix, + char* line) +{ + int32_t t = (data & 0x0000000007000000) >> 24; + int32_t ccc = (data & 0x00000000003FF000) >> 14; + + lastTexWidth = sqrt(ccc + 1); + lastTexHeight = sqrt(ccc + 1); + + lastTexLoaded = true; + lastTexIsPalette = true; + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + printf("TextureGenCheck G_LOADTLUT (lastCISiz: %i)\n", (uint32_t)lastCISiz); + + TextureGenCheck(); + + sprintf(line, "gsDPLoadTLUTCmd(%i, %i),", t, ccc); +} + +void ZDisplayList::Opcode_G_ENDDL([[maybe_unused]] const std::string& prefix, char* line) +{ + sprintf(line, "gsSPEndDisplayList(),"); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + printf("TextureGenCheck G_ENDDL\n"); + + TextureGenCheck(); +} + +static int32_t GfxdCallback_FormatSingleEntry() +{ + ZDisplayList* self = static_cast(gfxd_udata_get()); + gfxd_puts("\t"); + gfxd_macro_dflt(); + gfxd_puts(","); + + auto macroId = gfxd_macro_id(); + + switch (macroId) + { + case gfxd_SP1Triangle: + case gfxd_SP2Triangles: + if (self->lastTexture != nullptr && self->lastTexture->IsColorIndexed() && + !self->lastTexture->HasTlut()) + { + auto tex = self->lastTexture; + auto tlut = self->lastTlut; + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + { + if (tlut != nullptr) + printf("CI texture '%s' (0x%X), TLUT: '%s' (0x%X)\n", tex->GetName().c_str(), + tex->GetRawDataIndex(), tlut->GetName().c_str(), + tlut->GetRawDataIndex()); + else + printf("CI texture '%s' (0x%X), TLUT: null\n", tex->GetName().c_str(), + tex->GetRawDataIndex()); + } + + if (tlut != nullptr && !tex->HasTlut()) + tex->SetTlut(tlut); + } + break; + } + + // dont print a new line after the last command + switch (macroId) + { + case gfxd_SPEndDisplayList: + case gfxd_SPBranchList: + break; + + default: + gfxd_puts("\n"); + break; + } + + return 0; +} + +static int32_t GfxdCallback_Vtx(uint32_t seg, int32_t count) +{ + ZDisplayList* self = static_cast(gfxd_udata_get()); + uint32_t vtxOffset = Seg2Filespace(seg, self->parent->baseAddress); + + if (GETSEGNUM(seg) == self->parent->segment) + { + Declaration* decl; + + // Check for vertex intersections from other display lists + // TODO: These two could probably be condenced to one... + decl = self->parent->GetDeclarationRanged(vtxOffset + (count * 16)); + if (decl != nullptr) + { + int32_t diff = decl->address - vtxOffset; + + if (diff > 0) + count = diff / 16; + else + count = 0; + } + + decl = self->parent->GetDeclarationRanged(vtxOffset); + if (decl != nullptr) + { + int32_t diff = decl->address - vtxOffset; + + if (diff > 0) + count = diff / 16; + else + count = 0; + } + + if (count > 0) + { + std::vector vtxList; + vtxList.reserve(count); + + uint32_t currentPtr = vtxOffset; + for (int32_t i = 0; i < count; i++) + { + ZVtx vtx(self->parent); + vtx.ExtractFromFile(currentPtr); + + vtxList.push_back(vtx); + currentPtr += 16; + } + self->vertices[vtxOffset] = vtxList; + } + } + + self->references.push_back(seg); + gfxd_puts("@r"); + + return 1; +} + +static int32_t GfxdCallback_Texture(segptr_t seg, int32_t fmt, int32_t siz, int32_t width, + int32_t height, [[maybe_unused]] int32_t pal) +{ + ZDisplayList* self = static_cast(gfxd_udata_get()); + uint32_t texOffset = Seg2Filespace(seg, self->parent->baseAddress); + + self->lastTexWidth = width; + self->lastTexHeight = height; + self->lastTexAddr = texOffset; + self->lastTexSeg = seg; + self->lastTexFmt = static_cast(fmt); + self->lastTexSiz = static_cast(siz); + self->lastTexLoaded = true; + self->lastTexIsPalette = false; + + self->TextureGenCheck(); + + std::string texName; + Globals::Instance->GetSegmentedPtrName(seg, self->parent, "", texName); + + gfxd_puts(texName.c_str()); + + return 1; +} + +static int32_t GfxdCallback_Palette(uint32_t seg, [[maybe_unused]] int32_t idx, int32_t count) +{ + ZDisplayList* self = static_cast(gfxd_udata_get()); + uint32_t palOffset = Seg2Filespace(seg, self->parent->baseAddress); + + self->lastTexWidth = sqrt(count); + self->lastTexHeight = sqrt(count); + self->lastTexAddr = palOffset; + self->lastTexSeg = seg; + self->lastTexSiz = F3DZEXTexSizes::G_IM_SIZ_16b; + self->lastTexFmt = F3DZEXTexFormats::G_IM_FMT_RGBA; + self->lastTexLoaded = true; + self->lastTexIsPalette = true; + + self->TextureGenCheck(); + + std::string palName; + Globals::Instance->GetSegmentedPtrName(seg, self->parent, "", palName); + + gfxd_puts(palName.c_str()); + + return 1; +} + +static int32_t GfxdCallback_DisplayList(uint32_t seg) +{ + ZDisplayList* self = static_cast(gfxd_udata_get()); + uint32_t dListOffset = GETSEGOFFSET(seg); + uint32_t dListSegNum = GETSEGNUM(seg); + + std::string dListName = ""; + bool addressFound = Globals::Instance->GetSegmentedPtrName(seg, self->parent, "Gfx", dListName); + + if (!addressFound && self->parent->segment == dListSegNum) + { + ZDisplayList* newDList = new ZDisplayList(self->parent); + newDList->ExtractFromBinary( + dListOffset, + self->GetDListLength(self->parent->GetRawData(), dListOffset, self->dListType)); + newDList->SetName(newDList->GetDefaultName(self->parent->GetName())); + self->otherDLists.push_back(newDList); + dListName = newDList->GetName(); + } + + gfxd_puts(dListName.c_str()); + + return 1; +} + +static int32_t GfxdCallback_Matrix(uint32_t seg) +{ + std::string mtxName; + ZDisplayList* self = static_cast(gfxd_udata_get()); + + bool addressFound = Globals::Instance->GetSegmentedPtrName(seg, self->parent, "Mtx", mtxName); + if (!addressFound && GETSEGNUM(seg) == self->parent->segment) + { + Declaration* decl = + self->parent->GetDeclaration(Seg2Filespace(seg, self->parent->baseAddress)); + if (decl == nullptr) + { + ZMtx* mtx = new ZMtx(self->parent); + mtx->SetName(mtx->GetDefaultName(self->GetName())); + mtx->ExtractFromFile(Seg2Filespace(seg, self->parent->baseAddress)); + mtx->DeclareVar(self->GetName(), ""); + + mtx->GetSourceOutputCode(self->GetName()); + self->mtxList.push_back(*mtx); + self->parent->resources.push_back(mtx); + mtxName = "&" + mtx->GetName(); + } + } + + gfxd_puts(mtxName.c_str()); + + return 1; +} + +void ZDisplayList::DeclareReferences(const std::string& prefix) +{ + std::string sourceOutput; + + if (Globals::Instance->useLegacyZDList) + sourceOutput += ProcessLegacy(prefix); + else + sourceOutput += ProcessGfxDis(prefix); + + // Iterate through our vertex lists, connect intersecting lists. + if (vertices.size() > 0) + { + std::vector>> verticesSorted(vertices.begin(), + vertices.end()); + + for (size_t i = 0; i < verticesSorted.size() - 1; i++) + { + size_t vtxSize = vertices[verticesSorted[i].first].size() * 16; + + if ((verticesSorted[i].first + vtxSize) > verticesSorted[i + 1].first) + { + int32_t intersectAmt = + (verticesSorted[i].first + vtxSize) - verticesSorted[i + 1].first; + int32_t intersectIndex = intersectAmt / 16; + + for (size_t j = intersectIndex; j < verticesSorted[i + 1].second.size(); j++) + vertices[verticesSorted[i].first].push_back(verticesSorted[i + 1].second[j]); + + vertices.erase(verticesSorted[i + 1].first); + verticesSorted.erase(verticesSorted.begin() + i + 1); + + i--; + } + } + + // Generate Vertex Declarations + for (auto& item : vertices) + { + std::string declaration = ""; + + offset_t curAddr = item.first; + auto& firstVtx = item.second.at(0); + + for (auto vtx : item.second) + declaration += StringHelper::Sprintf("\t%s,\n", vtx.GetBodySourceCode().c_str()); + + Declaration* decl = parent->AddDeclarationArray( + curAddr, firstVtx.GetDeclarationAlignment(), + item.second.size() * firstVtx.GetRawDataSize(), firstVtx.GetSourceTypeName(), + firstVtx.GetDefaultName(name), item.second.size(), declaration); + decl->isExternal = true; + } + } + + Declaration* decl = DeclareVar("", sourceOutput); + decl->references = references; + + // Iterate through our vertex lists, connect intersecting lists. + if (vertices.size() > 0) + { + std::vector>> verticesSorted(vertices.begin(), + vertices.end()); + + for (size_t i = 0; i < verticesSorted.size() - 1; i++) + { + // int32_t vtxSize = verticesSorted[i].second.size() * 16; + size_t vtxSize = vertices[verticesSorted[i].first].size() * 16; + + if ((verticesSorted[i].first + vtxSize) > verticesSorted[i + 1].first) + { + int32_t intersectAmt = + (verticesSorted[i].first + vtxSize) - verticesSorted[i + 1].first; + int32_t intersectIndex = intersectAmt / 16; + + for (size_t j = intersectIndex; j < verticesSorted[i + 1].second.size(); j++) + vertices[verticesSorted[i].first].push_back(verticesSorted[i + 1].second[j]); + + vertices.erase(verticesSorted[i + 1].first); + verticesSorted.erase(verticesSorted.begin() + i + 1); + + i--; + } + } + + // Generate Vertex Declarations + std::vector vtxKeys; + + for (auto& item : vertices) + vtxKeys.push_back(item.first); + + // for (pair> item : vertices) + for (size_t i = 0; i < vtxKeys.size(); i++) + { + auto& item = vertices[vtxKeys[i]]; + + std::string declaration; + + for (auto& vtx : item) + declaration += StringHelper::Sprintf("\t%s,\n", vtx.GetBodySourceCode().c_str()); + + // 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. + declaration += "\n"; + + if (parent != nullptr) + { + std::string vtxName; + ZResource* vtxRes = parent->FindResource(vtxKeys[i]); + + if (vtxRes != nullptr) + vtxName = vtxRes->GetName(); + else + vtxName = StringHelper::Sprintf("%sVtx_%06X", prefix.c_str(), vtxKeys[i]); + + + if (StringHelper::Contains(vtxName, "4B18")) + { + int bp = 0; + } + + auto filepath = Globals::Instance->outputPath / vtxName; + std::string incStr = StringHelper::Sprintf("%s.%s.inc", filepath.string().c_str(), "vtx"); + + Declaration* vtxDecl = parent->AddDeclarationIncludeArray( + vtxKeys[i], incStr, item.size() * 16, "Vtx", vtxName, item.size()); + vtxDecl->isExternal = true; + } + } + } +} + +std::string ZDisplayList::ProcessLegacy(const std::string& prefix) +{ + char line[4096]; + std::string sourceOutput; + + for (size_t i = 0; i < instructions.size(); i++) + { + uint8_t opcode = (uint8_t)(instructions[i] >> 56); + uint64_t data = instructions[i]; + sourceOutput += " "; + + auto start = std::chrono::steady_clock::now(); + + int32_t optimizationResult = OptimizationChecks(i, sourceOutput, prefix); + + if (optimizationResult != -1) + { + i += optimizationResult - 1; + line[0] = '\0'; + } + else + { + if (dListType == DListType::F3DZEX) + ParseF3DZEX((F3DZEXOpcode)opcode, data, i, prefix, line); + else + ParseF3DEX((F3DEXOpcode)opcode, data, prefix, line); + } + + auto end = std::chrono::steady_clock::now(); + int64_t diff = std::chrono::duration_cast(end - start).count(); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG && diff > 5) + printf("F3DOP: 0x%02X, TIME: %" PRIi64 "ms\n", opcode, diff); + + sourceOutput += line; + + if (i < instructions.size() - 1) + sourceOutput += "\n"; + } + + return sourceOutput; +} + +std::string ZDisplayList::ProcessGfxDis([[maybe_unused]] const std::string& prefix) +{ + std::string sourceOutput; + + OutputFormatter outputformatter; + int32_t dListSize = instructions.size() * sizeof(instructions[0]); + + gfxd_input_buffer(instructions.data(), dListSize); + gfxd_endian(gfxd_endian_little, sizeof(uint64_t)); // tell gfxdis what format the data is + + gfxd_macro_fn(GfxdCallback_FormatSingleEntry); // format for each command entry + gfxd_vtx_callback(GfxdCallback_Vtx); // handle vertices + gfxd_timg_callback(GfxdCallback_Texture); // handle textures + gfxd_tlut_callback(GfxdCallback_Palette); // handle palettes + gfxd_dl_callback(GfxdCallback_DisplayList); // handle child display lists + gfxd_mtx_callback(GfxdCallback_Matrix); // handle matrices + gfxd_output_callback( + outputformatter.StaticWriter()); // convert tabs to 4 spaces and enforce 120 line limit + + gfxd_enable(gfxd_emit_dec_color); // use decimal for colors + + // set microcode. see gfxd.h for more options. + if (dListType == DListType::F3DZEX) + gfxd_target(gfxd_f3dex2); + else + gfxd_target(gfxd_f3dex); + + gfxd_udata_set(this); + gfxd_execute(); // generate display list + sourceOutput += outputformatter.GetOutput(); // write formatted display list + + return sourceOutput; +} + +void ZDisplayList::TextureGenCheck() +{ + if (TextureGenCheck(lastTexWidth, lastTexHeight, lastTexAddr, lastTexSeg, lastTexFmt, + lastTexSiz, lastTexLoaded, lastTexIsPalette, this)) + { + lastTexAddr = 0; + lastTexLoaded = false; + lastTexIsPalette = false; + } +} + +bool ZDisplayList::TextureGenCheck(int32_t texWidth, int32_t texHeight, uint32_t texAddr, + uint32_t texSeg, F3DZEXTexFormats texFmt, F3DZEXTexSizes texSiz, + bool texLoaded, bool texIsPalette, ZDisplayList* self) +{ + uint32_t segmentNumber = GETSEGNUM(texSeg); + + if (!texIsPalette) + self->lastTexture = nullptr; + else + self->lastTlut = nullptr; + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + printf("TextureGenCheck seg=%i width=%i height=%i ispal=%i addr=0x%06X\n", segmentNumber, + texWidth, texHeight, texIsPalette, texAddr); + + if ((texSeg != 0 || texAddr != 0) && texWidth > 0 && texHeight > 0 && texLoaded && + Globals::Instance->HasSegment(segmentNumber)) + { + ZFile* auxParent = nullptr; + if (segmentNumber == self->parent->segment) + { + auxParent = self->parent; + } + else + { + // Try to find a non-external file (i.e., one we are actually extracting) + // which has the same segment number we are looking for. + for (auto& otherFile : Globals::Instance->cfg.segmentRefFiles[segmentNumber]) + { + if (!otherFile->isExternalFile) + { + auxParent = otherFile; + } + } + } + + if (auxParent == nullptr) + { + // We can't declare the texture in any of the files we are extracting. + return false; + } + + if (auxParent->IsOffsetInFileRange(texAddr)) + { + ZTexture* tex = auxParent->GetTextureResource(texAddr); + if (tex != nullptr) + tex->isPalette = texIsPalette; + else + { + tex = new ZTexture(auxParent); + tex->ExtractFromBinary(texAddr, texWidth, texHeight, + TexFormatToTexType(texFmt, texSiz), texIsPalette); + auxParent->AddTextureResource(texAddr, tex); + } + + if (!texIsPalette) + self->lastTexture = tex; + else + self->lastTlut = tex; + + if (auxParent->GetDeclaration(texAddr) == nullptr) + { + tex->DeclareVar(self->GetName(), ""); + } + + return true; + } + } + + return false; +} + +TextureType ZDisplayList::TexFormatToTexType(F3DZEXTexFormats fmt, F3DZEXTexSizes siz) +{ + if (fmt == F3DZEXTexFormats::G_IM_FMT_RGBA) + { + if (siz == F3DZEXTexSizes::G_IM_SIZ_16b) + return TextureType::RGBA16bpp; + else if (siz == F3DZEXTexSizes::G_IM_SIZ_32b) + return TextureType::RGBA32bpp; + } + else if (fmt == F3DZEXTexFormats::G_IM_FMT_CI) + { + if (Globals::Instance->useLegacyZDList) + return TextureType::Palette8bpp; + else + { + if (siz == F3DZEXTexSizes::G_IM_SIZ_4b) + return TextureType::Palette4bpp; + else if (siz == F3DZEXTexSizes::G_IM_SIZ_8b) + return TextureType::Palette8bpp; + } + } + else if (fmt == F3DZEXTexFormats::G_IM_FMT_IA) + { + if (siz == F3DZEXTexSizes::G_IM_SIZ_4b) + return TextureType::GrayscaleAlpha4bpp; + else if (siz == F3DZEXTexSizes::G_IM_SIZ_8b) + return TextureType::GrayscaleAlpha8bpp; + else if (siz == F3DZEXTexSizes::G_IM_SIZ_16b) + return TextureType::GrayscaleAlpha16bpp; + } + else if (fmt == F3DZEXTexFormats::G_IM_FMT_I) + { + if (siz == F3DZEXTexSizes::G_IM_SIZ_4b) + return TextureType::Grayscale4bpp; + else if (siz == F3DZEXTexSizes::G_IM_SIZ_8b) + return TextureType::Grayscale8bpp; + else if (siz == F3DZEXTexSizes::G_IM_SIZ_16b) + return TextureType::Grayscale8bpp; + } + + return TextureType::RGBA16bpp; +} + +bool ZDisplayList::IsExternalResource() const +{ + return false; +} + +std::string ZDisplayList::GetExternalExtension() const +{ + return "dlist"; +} + +std::string ZDisplayList::GetSourceTypeName() const +{ + return "Gfx"; +} + +ZResourceType ZDisplayList::GetResourceType() const +{ + return ZResourceType::DisplayList; +} + +size_t ZDisplayList::GetRawDataSize() const +{ + return instructions.size() * 8; +} + +DeclarationAlignment ZDisplayList::GetDeclarationAlignment() const +{ + return DeclarationAlignment::Align8; +} diff --git a/ZAPDTR/ZAPD/ZDisplayList.h b/ZAPDTR/ZAPD/ZDisplayList.h new file mode 100644 index 000000000..96808315d --- /dev/null +++ b/ZAPDTR/ZAPD/ZDisplayList.h @@ -0,0 +1,378 @@ +#pragma once + +#include "ZMtx.h" +#include "ZResource.h" +#include "ZRoom/ZRoom.h" +#include "ZTexture.h" +#include "ZVtx.h" +#include "tinyxml2.h" + +#include +#include +#include + +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, +}; + +#define G_MDSFT_ALPHACOMPARE 0 +#define G_MDSFT_ZSRCSEL 2 +#define G_MDSFT_RENDERMODE 3 +#define G_MDSFT_BLENDER 16 + +#define G_RM_FOG_SHADE_A 0xC8000000 +#define G_RM_FOG_PRIM_A 0xC4000000 +#define G_RM_PASS 0x0C080000 +#define G_RM_AA_ZB_OPA_SURF 0x442078 +#define G_RM_AA_ZB_OPA_SURF2 0x112078 +#define G_RM_AA_ZB_XLU_SURF 0x4049D8 +#define G_RM_AA_ZB_XLU_SURF2 0x1049D8 +#define G_RM_AA_ZB_OPA_DECAL 0x442D58 +#define G_RM_AA_ZB_OPA_DECAL2 0x112D58 +#define G_RM_AA_ZB_XLU_DECAL 0x404DD8 +#define G_RM_AA_ZB_XLU_DECAL2 0x104DD8 +#define G_RM_AA_ZB_OPA_INTER 0x442478 +#define G_RM_AA_ZB_OPA_INTER2 0x112478 +#define G_RM_AA_ZB_XLU_INTER 0x4045D8 +#define G_RM_AA_ZB_XLU_INTER2 0x1045D8 +#define G_RM_AA_ZB_XLU_LINE 0x407858 +#define G_RM_AA_ZB_XLU_LINE2 0x107858 +#define G_RM_AA_ZB_DEC_LINE 0x407F58 +#define G_RM_AA_ZB_DEC_LINE2 0x107F58 +#define G_RM_AA_ZB_TEX_EDGE 0x443078 +#define G_RM_AA_ZB_TEX_EDGE2 0x113078 +#define G_RM_AA_ZB_TEX_INTER 0x443478 +#define G_RM_AA_ZB_TEX_INTER2 0x113478 +#define G_RM_AA_ZB_SUB_SURF 0x442878 +#define G_RM_AA_ZB_SUB_SURF2 0x112278 +#define G_RM_AA_ZB_PCL_SURF 0x40007B +#define G_RM_AA_ZB_PCL_SURF2 0x10007B +#define G_RM_AA_ZB_OPA_TERR 0x402078 +#define G_RM_AA_ZB_OPA_TERR2 0x102078 +#define G_RM_AA_ZB_TEX_TERR 0x403078 +#define G_RM_AA_ZB_TEX_TERR2 0x103078 +#define G_RM_AA_ZB_SUB_TERR 0x402278 +#define G_RM_AA_ZB_SUB_TERR2 0x102278 +#define G_RM_RA_ZB_OPA_SURF 0x442038 +#define G_RM_RA_ZB_OPA_SURF2 0x112038 +#define G_RM_RA_ZB_OPA_DECAL 0x442D18 +#define G_RM_RA_ZB_OPA_DECAL2 0x112D18 +#define G_RM_RA_ZB_OPA_INTER 0x442438 +#define G_RM_RA_ZB_OPA_INTER2 0x112438 +#define G_RM_AA_OPA_SURF 0x442048 +#define G_RM_AA_OPA_SURF2 0x112048 +#define G_RM_AA_XLU_SURF 0x4041C8 +#define G_RM_AA_XLU_SURF2 0x1041C8 +#define G_RM_AA_XLU_LINE 0x407048 +#define G_RM_AA_XLU_LINE2 0x107048 +#define G_RM_AA_DEC_LINE 0x407248 +#define G_RM_AA_DEC_LINE2 0x107248 +#define G_RM_AA_TEX_EDGE 0x443048 +#define G_RM_AA_TEX_EDGE2 0x113048 +#define G_RM_AA_SUB_SURF 0x442248 +#define G_RM_AA_SUB_SURF2 0x112248 +#define G_RM_AA_PCL_SURF 0x40004B +#define G_RM_AA_PCL_SURF2 0x10004B +#define G_RM_AA_OPA_TERR 0x402048 +#define G_RM_AA_OPA_TERR2 0x102048 +#define G_RM_AA_TEX_TERR 0x403048 +#define G_RM_AA_TEX_TERR2 0x103048 +#define G_RM_AA_SUB_TERR 0x402248 +#define G_RM_AA_SUB_TERR2 0x102248 +#define G_RM_RA_OPA_SURF 0x442008 +#define G_RM_RA_OPA_SURF2 0x112008 +#define G_RM_ZB_OPA_SURF 0x442230 +#define G_RM_ZB_OPA_SURF2 0x112230 +#define G_RM_ZB_XLU_SURF 0x404A50 +#define G_RM_ZB_XLU_SURF2 0x104A50 +#define G_RM_ZB_OPA_DECAL 0x442E10 +#define G_RM_ZB_OPA_DECAL2 0x112E10 +#define G_RM_ZB_XLU_DECAL 0x404E50 +#define G_RM_ZB_XLU_DECAL2 0x104E50 +#define G_RM_ZB_CLD_SURF 0x404B50 +#define G_RM_ZB_CLD_SURF2 0x104B50 +#define G_RM_ZB_OVL_SURF 0x404F50 +#define G_RM_ZB_OVL_SURF2 0x104F50 +#define G_RM_ZB_PCL_SURF 0x0C080233 +#define G_RM_ZB_PCL_SURF2 0x03020233 +#define G_RM_OPA_SURF 0x0C084000 +#define G_RM_OPA_SURF2 0x03024000 +#define G_RM_XLU_SURF 0x00404200 +#define G_RM_XLU_SURF2 0x00104240 +#define G_RM_CLD_SURF 0x00404340 +#define G_RM_CLD_SURF2 0x00104340 +#define G_RM_TEX_EDGE 0x0C087008 +#define G_RM_TEX_EDGE2 0x03027008 +#define G_RM_PCL_SURF 0x0C084203 +#define G_RM_PCL_SURF2 0x03024203 +#define G_RM_ADD 0x04484340 +#define G_RM_ADD2 0x01124340 +#define G_RM_NOOP 0x00000000 +#define G_RM_NOOP2 0x00000000 +#define G_RM_VISCVG 0x0C844040 +#define G_RM_VISCVG2 0x03214040 +#define G_RM_OPA_CI 0x0C080000 +#define G_RM_OPA_CI2 0x03020000 + +#define AA_EN 0x8 +#define Z_CMP 0x10 +#define Z_UPD 0x20 +#define IM_RD 0x40 +#define CLR_ON_CVG 0x80 +#define CVG_DST_CLAMP 0 +#define CVG_DST_WRAP 0x100 +#define CVG_DST_FULL 0x200 +#define CVG_DST_SAVE 0x300 +#define ZMODE_OPA 0 +#define ZMODE_INTER 0x400 +#define ZMODE_XLU 0x800 +#define ZMODE_DEC 0xc00 +#define CVG_X_ALPHA 0x1000 +#define ALPHA_CVG_SEL 0x2000 +#define FORCE_BL 0x4000 +#define TEX_EDGE 0x0000 + +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 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 instructions; + + int32_t lastTexWidth, lastTexHeight, lastTexAddr, lastTexSeg; + F3DZEXTexFormats lastTexFmt; + F3DZEXTexSizes lastTexSiz, lastTexSizTest, lastCISiz; + bool lastTexLoaded; + bool lastTexIsPalette; + + DListType dListType; + + std::map> vertices; + std::vector otherDLists; + + ZTexture* lastTexture = nullptr; + ZTexture* lastTlut = nullptr; + + std::vector references; + std::vector mtxList; + + ZDisplayList(ZFile* nParent); + ~ZDisplayList(); + + void ExtractFromXML(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& 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); + + bool IsExternalResource() const override; + std::string GetExternalExtension() const override; + std::string GetSourceTypeName() const override; + + ZResourceType GetResourceType() const override; + +protected: + size_t numInstructions; +}; diff --git a/ZAPDTR/ZAPD/ZFile.cpp b/ZAPDTR/ZAPD/ZFile.cpp new file mode 100644 index 000000000..13ab961f8 --- /dev/null +++ b/ZAPDTR/ZAPD/ZFile.cpp @@ -0,0 +1,1357 @@ +#include "ZFile.h" + +#include +#include +#include +#include + +#include "Globals.h" +#include "OutputFormatter.h" +#include "Utils/BinaryWriter.h" +#include "Utils/BitConverter.h" +#include "Utils/Directory.h" +#include "Utils/File.h" +#include "Utils/MemoryStream.h" +#include "Utils/Path.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZAnimation.h" +#include "ZArray.h" +#include "ZBackground.h" +#include "ZBlob.h" +#include "ZCollision.h" +#include "ZCutscene.h" +#include "ZDisplayList.h" +#include "ZLimb.h" +#include "ZMtx.h" +#include "ZRoom/ZRoom.h" +#include "ZScalar.h" +#include "ZSkeleton.h" +#include "ZSymbol.h" +#include "ZTexture.h" +#include "ZVector.h" +#include "ZVtx.h" + +ZFile::ZFile() +{ + resources = std::vector(); + basePath = ""; + declarations = std::map(); + defines = ""; + baseAddress = 0; + rangeStart = 0x000000000; + rangeEnd = 0xFFFFFFFF; +} + +ZFile::ZFile(const fs::path& nOutPath, const std::string& nName) : ZFile() +{ + name = nName; + outName = nName; + outputPath = nOutPath; +} + +ZFile::ZFile(ZFileMode nMode, tinyxml2::XMLElement* reader, const fs::path& nBasePath, + const fs::path& nOutPath, const std::string& filename, const fs::path& nXmlFilePath) + : ZFile() +{ + xmlFilePath = nXmlFilePath; + if (nBasePath == "") + basePath = Directory::GetCurrentDirectory(); + else + basePath = nBasePath; + + if (nOutPath == "") + outputPath = Directory::GetCurrentDirectory(); + else + outputPath = nOutPath; + + mode = nMode; + + ParseXML(reader, filename); + if (mode != ZFileMode::ExternalFile) + DeclareResourceSubReferences(); +} + +ZFile::~ZFile() +{ + for (ZResource* res : resources) + delete res; + + for (auto d : declarations) + delete d.second; + + for (auto sym : symbolResources) + delete sym.second; +} + +void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) +{ + assert(mode != ZFileMode::Invalid); + + if (filename == "") + name = reader->Attribute("Name"); + else + name = filename; + + outName = name; + const char* outNameXml = reader->Attribute("OutName"); + if (outNameXml != nullptr) + outName = outNameXml; + + // TODO: This should be a variable on the ZFile, but it is a large change in order to force all + // ZResource types to have a parent ZFile. + const char* gameStr = reader->Attribute("Game"); + if (reader->Attribute("Game") != nullptr) + { + if (std::string_view(gameStr) == "MM") + Globals::Instance->game = ZGame::MM_RETAIL; + else if (std::string_view(gameStr) == "SW97" || std::string_view(gameStr) == "OOTSW97") + Globals::Instance->game = ZGame::OOT_SW97; + else if (std::string_view(gameStr) == "OOT") + Globals::Instance->game = ZGame::OOT_RETAIL; + else + { + std::string errorHeader = + StringHelper::Sprintf("'Game' type '%s' is not supported.", gameStr); + HANDLE_ERROR_PROCESS(WarningType::InvalidAttributeValue, errorHeader, ""); + } + } + + if (reader->Attribute("BaseAddress") != nullptr) + baseAddress = StringHelper::StrToL(reader->Attribute("BaseAddress"), 16); + + if (reader->Attribute("RangeStart") != nullptr) + rangeStart = StringHelper::StrToL(reader->Attribute("RangeStart"), 16); + + if (reader->Attribute("RangeEnd") != nullptr) + rangeEnd = StringHelper::StrToL(reader->Attribute("RangeEnd"), 16); + + if (rangeStart > rangeEnd) + HANDLE_ERROR_PROCESS( + WarningType::Always, + StringHelper::Sprintf("'RangeStart' 0x%06X must be before 'RangeEnd' 0x%06X", + rangeStart, rangeEnd), + ""); + + const char* segmentXml = reader->Attribute("Segment"); + if (segmentXml != nullptr) + { + if (!StringHelper::HasOnlyDigits(segmentXml)) + { + HANDLE_ERROR_PROCESS(WarningType::Always, + StringHelper::Sprintf("error: Invalid segment value '%s': must be " + "a decimal between 0 and 15 inclusive", + segmentXml), + ""); + } + + segment = StringHelper::StrToL(segmentXml, 10); + if (segment > 15) + { + if (segment == 128) + { +#ifdef DEPRECATION_ON + HANDLE_WARNING_PROCESS( + WarningType::Always, "warning: segment 128 is deprecated.", + "Remove 'Segment=\"128\"' from the xml to use virtual addresses\n"); +#endif + } + else + { + HANDLE_ERROR_PROCESS( + WarningType::Always, + StringHelper::Sprintf("error: invalid segment value '%s': must be a decimal " + "number between 0 and 15 inclusive", + segmentXml), + ""); + } + } + } + Globals::Instance->AddSegment(segment, this); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO) + { + if (segment == 0x80) + { + printf("File '%s' using virtual addresses.\n", GetName().c_str()); + } + else + { + printf("File '%s' using segment %X.\n", GetName().c_str(), segment); + } + } + + if (mode == ZFileMode::Extract || mode == ZFileMode::ExternalFile) + { + if (!File::Exists((basePath / name).string())) + { + std::string errorHeader = StringHelper::Sprintf("binary file '%s' does not exist.", + (basePath / name).c_str()); + HANDLE_ERROR_PROCESS(WarningType::Always, errorHeader, ""); + } + + rawData = File::ReadAllBytes((basePath / name).string()); + + if (reader->Attribute("RangeEnd") == nullptr) + rangeEnd = rawData.size(); + } + + std::unordered_set nameSet; + std::unordered_set outNameSet; + std::unordered_set offsetSet; + + auto nodeMap = *GetNodeMap(); + uint32_t rawDataIndex = 0; + + for (tinyxml2::XMLElement* child = reader->FirstChildElement(); child != nullptr; + child = child->NextSiblingElement()) + { + const char* nameXml = child->Attribute("Name"); + const char* outNameXml = child->Attribute("OutName"); + const char* offsetXml = child->Attribute("Offset"); + + // Check for repeated attributes. + if (offsetXml != nullptr) + { + rawDataIndex = strtol(StringHelper::Split(offsetXml, "0x")[1].c_str(), NULL, 16); + + if (offsetSet.find(offsetXml) != offsetSet.end()) + { + std::string errorHeader = + StringHelper::Sprintf("repeated 'Offset' attribute: %s", offsetXml); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); + } + offsetSet.insert(offsetXml); + } + else + { + HANDLE_WARNING_RESOURCE(WarningType::MissingOffsets, this, nullptr, rawDataIndex, + StringHelper::Sprintf("no offset specified for %s.", nameXml), + ""); + } + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO) + printf("%s: 0x%06X\n", nameXml, rawDataIndex); + + if (outNameXml != nullptr) + { + if (outNameSet.find(outNameXml) != outNameSet.end()) + { + std::string errorHeader = + StringHelper::Sprintf("repeated 'OutName' attribute: %s", outNameXml); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); + } + outNameSet.insert(outNameXml); + } + if (nameXml != nullptr) + { + if (nameSet.find(nameXml) != nameSet.end()) + { + std::string errorHeader = + StringHelper::Sprintf("repeated 'Name' attribute: %s", nameXml); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); + } + nameSet.insert(nameXml); + } + + std::string nodeName = std::string(child->Name()); + + if (nodeMap.find(nodeName) != nodeMap.end()) + { + ZResource* nRes = nodeMap[nodeName](this); + + if (mode == ZFileMode::Extract || mode == ZFileMode::ExternalFile) + nRes->ExtractFromXML(child, rawDataIndex); + + switch (nRes->GetResourceType()) + { + case ZResourceType::Texture: + AddTextureResource(rawDataIndex, static_cast(nRes)); + break; + + case ZResourceType::Symbol: + AddSymbolResource(rawDataIndex, static_cast(nRes)); + break; + + default: + AddResource(nRes); + break; + } + + rawDataIndex += nRes->GetRawDataSize(); + } + else if (std::string_view(child->Name()) == "File") + { + std::string errorHeader = "Can't declare a inside a "; + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); + } + else + { + std::string errorHeader = StringHelper::Sprintf( + "Unknown element found inside a element: %s", nodeName.c_str()); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); + } + } +} + +void ZFile::DeclareResourceSubReferences() +{ + for (size_t i = 0; i < resources.size(); i++) + { + resources.at(i)->DeclareReferences(name); + } +} + +void ZFile::BuildSourceFile() +{ + if (mode == ZFileMode::ExternalFile) + return; + + if (!Directory::Exists(outputPath)) + Directory::CreateDirectory(outputPath.string()); + + GenerateSourceFiles(); +} + +std::string ZFile::GetName() const +{ + return name; +} + +std::string ZFile::GetOutName() const +{ + return outName.string(); +} + +ZFileMode ZFile::GetMode() const +{ + return mode; +} + +const fs::path& ZFile::GetXmlFilePath() const +{ + return xmlFilePath; +} + +const std::vector& ZFile::GetRawData() const +{ + return rawData; +} + +void ZFile::ExtractResources() +{ + if (mode == ZFileMode::ExternalFile) + return; + + if (!Directory::Exists(outputPath)) + Directory::CreateDirectory(outputPath.string()); + + if (!Directory::Exists(GetSourceOutputFolderPath())) + Directory::CreateDirectory(GetSourceOutputFolderPath().string()); + + for (size_t i = 0; i < resources.size(); i++) + resources[i]->ParseRawDataLate(); + for (size_t i = 0; i < resources.size(); i++) + resources[i]->DeclareReferencesLate(name); + + if (Globals::Instance->genSourceFile) + GenerateSourceFiles(); + + auto memStreamFile = std::shared_ptr(new MemoryStream()); + BinaryWriter writerFile = BinaryWriter(memStreamFile); + + ExporterSet* exporterSet = Globals::Instance->GetExporterSet(); + + if (exporterSet != nullptr && exporterSet->beginFileFunc != nullptr) + exporterSet->beginFileFunc(this); + + int totalMs = 0; + + for (ZResource* res : resources) + { + auto start = std::chrono::steady_clock::now(); + + auto memStreamRes = std::shared_ptr(new MemoryStream()); + BinaryWriter writerRes = BinaryWriter(memStreamRes); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO) + printf("Saving resource %s\n", res->GetName().c_str()); + + res->Save(outputPath); + + // Check if we have an exporter "registered" for this resource type + ZResourceExporter* exporter = Globals::Instance->GetExporter(res->GetResourceType()); + if (exporter != nullptr) + { + // exporter->Save(res, Globals::Instance->outputPath.string(), &writerFile); + exporter->Save(res, Globals::Instance->outputPath.string(), &writerRes); + } + + if (exporterSet != nullptr && exporterSet->resSaveFunc != nullptr) + exporterSet->resSaveFunc(res, writerRes); + + auto end = std::chrono::steady_clock::now(); + auto diff = std::chrono::duration_cast(end - start).count(); + + totalMs += diff; + + //printf("Res %s in %lims\n", res->GetName().c_str(), diff); + } + + //printf("File %s in %lims\n", GetName().c_str(), totalMs); + + if (memStreamFile->GetLength() > 0) + { + File::WriteAllBytes(StringHelper::Sprintf("%s%s.bin", + Globals::Instance->outputPath.string().c_str(), + GetName().c_str()), + memStreamFile->ToVector()); + } + + writerFile.Close(); + + if (exporterSet != nullptr && exporterSet->endFileFunc != nullptr) + exporterSet->endFileFunc(this); +} + +void ZFile::AddResource(ZResource* res) +{ + resources.push_back(res); +} + +ZResource* ZFile::FindResource(uint32_t rawDataIndex) +{ + for (ZResource* res : resources) + { + if (res->GetRawDataIndex() == rawDataIndex) + return res; + } + + return nullptr; +} + +std::vector ZFile::GetResourcesOfType(ZResourceType resType) +{ + std::vector resList; + + for (ZResource* res : resources) + { + if (res->GetResourceType() == resType) + resList.push_back(res); + } + + return resList; +} + +Declaration* ZFile::AddDeclaration(offset_t address, DeclarationAlignment alignment, size_t size, + const std::string& varType, const std::string& varName, + const std::string& body) +{ + bool validOffset = AddDeclarationChecks(address, varName); + if (!validOffset) + return nullptr; + + Declaration* decl = GetDeclaration(address); + if (decl == nullptr) + { + decl = new Declaration(address, alignment, size, varType, varName, false, body); + declarations[address] = decl; + } + else + { + decl->alignment = alignment; + decl->size = size; + decl->varType = varType; + decl->varName = varName; + decl->text = body; + } + return decl; +} + +Declaration* ZFile::AddDeclarationArray(offset_t address, DeclarationAlignment alignment, + size_t size, const std::string& varType, + const std::string& varName, size_t arrayItemCnt, + const std::string& body) +{ + bool validOffset = AddDeclarationChecks(address, varName); + if (!validOffset) + return nullptr; + + Declaration* decl = GetDeclaration(address); + if (decl == nullptr) + { + decl = + new Declaration(address, alignment, size, varType, varName, true, arrayItemCnt, body); + declarations[address] = decl; + } + else + { + if (decl->isPlaceholder) + decl->varName = varName; + decl->alignment = alignment; + decl->size = size; + decl->varType = varType; + decl->isArray = true; + decl->arrayItemCnt = arrayItemCnt; + decl->text = body; + } + + return decl; +} + +Declaration* ZFile::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) +{ + bool validOffset = AddDeclarationChecks(address, varName); + if (!validOffset) + return nullptr; + + Declaration* decl = GetDeclaration(address); + if (decl == nullptr) + { + decl = new Declaration(address, alignment, size, varType, varName, true, arrayItemCntStr, + body); + declarations[address] = decl; + } + else + { + decl->alignment = alignment; + decl->size = size; + decl->varType = varType; + decl->varName = varName; + decl->isArray = true; + decl->arrayItemCntStr = arrayItemCntStr; + decl->text = body; + } + return decl; +} + +Declaration* ZFile::AddDeclarationPlaceholder(offset_t address, const std::string& varName) +{ + bool validOffset = AddDeclarationChecks(address, varName); + if (!validOffset) + return nullptr; + + Declaration* decl; + if (declarations.find(address) == declarations.end()) + { + decl = new Declaration(address, DeclarationAlignment::Align4, 0, "", varName, false, ""); + decl->isPlaceholder = true; + declarations[address] = decl; + } + else + decl = declarations[address]; + + return decl; +} + +Declaration* ZFile::AddDeclarationInclude(offset_t address, const std::string& includePath, + size_t size, const std::string& varType, + const std::string& varName) +{ + bool validOffset = AddDeclarationChecks(address, varName); + if (!validOffset) + return nullptr; + + Declaration* decl = GetDeclaration(address); + if (decl == nullptr) + { + decl = new Declaration(address, includePath, size, varType, varName); + declarations[address] = decl; + } + else + { + decl->includePath = includePath; + decl->size = size; + decl->varType = varType; + decl->varName = varName; + } + return decl; +} + +Declaration* ZFile::AddDeclarationIncludeArray(offset_t address, std::string& includePath, + size_t size, const std::string& varType, + const std::string& varName, size_t arrayItemCnt) +{ + bool validOffset = AddDeclarationChecks(address, varName); + if (!validOffset) + return nullptr; + + if (StringHelper::StartsWith(includePath, "assets/extracted/")) + includePath = "assets/" + StringHelper::Split(includePath, "assets/extracted/")[1]; + if (StringHelper::StartsWith(includePath, "assets/custom/")) + includePath = "assets/" + StringHelper::Split(includePath, "assets/custom/")[1]; + + Declaration* decl = GetDeclaration(address); + if (decl == nullptr) + { + decl = new Declaration(address, includePath, size, varType, varName); + + decl->isArray = true; + decl->arrayItemCnt = arrayItemCnt; + + declarations[address] = decl; + } + else + { + decl->includePath = includePath; + decl->varType = varType; + decl->varName = varName; + decl->size = size; + decl->isArray = true; + decl->arrayItemCnt = arrayItemCnt; + } + return decl; +} + +bool ZFile::AddDeclarationChecks(uint32_t address, const std::string& varName) +{ + assert(GETSEGNUM(address) == 0); + assert(varName != ""); +#ifdef DEVELOPMENT + if (address == 0x0000) + { + [[maybe_unused]] int32_t bp = 0; + } +#endif + + if (!IsOffsetInFileRange(address)) + { + fprintf(stderr, + "%s: Warning in %s\n" + "\t Tried to declare a variable outside of this file's range. Ignoring...\n" + "\t\t Variable's name: %s\n" + "\t\t Variable's offset: 0x%06X\n", + __PRETTY_FUNCTION__, name.c_str(), varName.c_str(), address); + return false; + } + + return true; +} + +bool ZFile::GetDeclarationPtrName(segptr_t segAddress, const std::string& expectedType, + std::string& declName) const +{ + if (segAddress == 0) + { + declName = "NULL"; + return true; + } + + uint32_t offset = Seg2Filespace(segAddress, baseAddress); + Declaration* decl = GetDeclaration(offset); + if (GETSEGNUM(segAddress) != segment || decl == nullptr) + { + declName = StringHelper::Sprintf("0x%08X", segAddress); + return false; + } + + if (expectedType != "" && expectedType != "void*") + { + if (expectedType != decl->varType && "static " + expectedType != decl->varType) + { + declName = StringHelper::Sprintf("0x%08X", segAddress); + return false; + } + } + + if (!decl->isArray) + declName = "&" + decl->varName; + else + declName = decl->varName; + return true; +} + +bool ZFile::GetDeclarationArrayIndexedName(segptr_t segAddress, size_t elementSize, + const std::string& expectedType, + std::string& declName) const +{ + if (segAddress == 0) + { + declName = "NULL"; + return true; + } + + uint32_t address = Seg2Filespace(segAddress, baseAddress); + Declaration* decl = GetDeclarationRanged(address); + if (GETSEGNUM(segAddress) != segment || decl == nullptr || !decl->isArray) + { + declName = StringHelper::Sprintf("0x%08X", segAddress); + return false; + } + + if (expectedType != "" && expectedType != "void*") + { + if (expectedType != decl->varType && "static " + expectedType != decl->varType) + { + declName = StringHelper::Sprintf("0x%08X", segAddress); + return false; + } + } + + if (decl->address == address) + { + declName = decl->varName; + return true; + } + + if ((address - decl->address) % elementSize != 0 || !(address < decl->address + decl->size)) + { + declName = StringHelper::Sprintf("0x%08X", segAddress); + return false; + } + + uint32_t index = (address - decl->address) / elementSize; + declName = StringHelper::Sprintf("&%s[%u]", decl->varName.c_str(), index); + return true; +} + +Declaration* ZFile::GetDeclaration(uint32_t address) const +{ + if (declarations.find(address) != declarations.end()) + return declarations.at(address); + + return nullptr; +} + +Declaration* ZFile::GetDeclarationRanged(uint32_t address) const +{ + for (const auto decl : declarations) + { + if (address >= decl.first && address < decl.first + decl.second->size) + return decl.second; + } + + return nullptr; +} + +bool ZFile::HasDeclaration(uint32_t address) +{ + assert(GETSEGNUM(address) == 0); + return declarations.find(address) != declarations.end(); +} + +void ZFile::GenerateSourceFiles() +{ + std::string sourceOutput; + + sourceOutput += "#include \"ultra64.h\"\n"; + sourceOutput += "#include \"z64.h\"\n"; + sourceOutput += "#include \"macros.h\"\n"; + sourceOutput += GetHeaderInclude(); + + bool hasZRoom = false; + for (const auto& res : resources) + { + ZResourceType resType = res->GetResourceType(); + if (resType == ZResourceType::Room || resType == ZResourceType::Scene || + resType == ZResourceType::AltHeader) + { + hasZRoom = true; + break; + } + } + + if (hasZRoom) + { + sourceOutput += GetZRoomHeaderInclude(); + } + + sourceOutput += GetExternalFileHeaderInclude(); + + GeneratePlaceholderDeclarations(); + + // Generate Code + for (size_t i = 0; i < resources.size(); i++) + { + ZResource* res = resources.at(i); + res->GetSourceOutputCode(name); + } + + sourceOutput += ProcessDeclarations(); + + fs::path outPath = GetSourceOutputFolderPath() / outName.stem().concat(".c"); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO) + printf("Writing C file: %s\n", outPath.c_str()); + + if (!Globals::Instance->otrMode) + { + OutputFormatter formatter; + formatter.Write(sourceOutput); + + File::WriteAllText(outPath, formatter.GetOutput()); + } + + GenerateSourceHeaderFiles(); +} + +void ZFile::GenerateSourceHeaderFiles() +{ + OutputFormatter formatter; + + for (ZResource* res : resources) + { + std::string resSrc = res->GetSourceOutputHeader(""); + formatter.Write(resSrc); + + if (resSrc != "") + formatter.Write("\n"); + } + + for (auto& sym : symbolResources) + { + formatter.Write(sym.second->GetSourceOutputHeader("")); + } + + formatter.Write(ProcessExterns()); + + fs::path headerFilename = GetSourceOutputFolderPath() / outName.stem().concat(".h"); + + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO) + printf("Writing H file: %s\n", headerFilename.c_str()); + + File::WriteAllText(headerFilename, formatter.GetOutput()); +} + +std::string ZFile::GetHeaderInclude() const +{ + std::string headers = StringHelper::Sprintf("#include \"%s.h\"\n", + (outName.parent_path() / outName.stem()).string().c_str()); + + return headers; +} + +std::string ZFile::GetZRoomHeaderInclude() const +{ + std::string headers; + headers += "#include \"segment_symbols.h\"\n"; + headers += "#include \"command_macros_base.h\"\n"; + headers += "#include \"z64cutscene_commands.h\"\n"; + headers += "#include \"variables.h\"\n"; + return headers; +} + +std::string ZFile::GetExternalFileHeaderInclude() const +{ + std::string externalFilesIncludes = ""; + + for (ZFile* externalFile : Globals::Instance->files) + { + if (externalFile != this) + { + fs::path outputFolderPath = externalFile->GetSourceOutputFolderPath(); + if (outputFolderPath == this->GetSourceOutputFolderPath()) + { + outputFolderPath = externalFile->outName.stem(); + } + else + { + outputFolderPath /= externalFile->outName.stem(); + } + + externalFilesIncludes += + StringHelper::Sprintf("#include \"%s.h\"\n", outputFolderPath.string().c_str()); + } + } + + return externalFilesIncludes; +} + +void ZFile::GeneratePlaceholderDeclarations() +{ + // Generate placeholder declarations + for (ZResource* res : resources) + { + if (GetDeclaration(res->GetRawDataIndex()) != nullptr) + { + continue; + } + + Declaration* decl = res->DeclareVar(GetName(), ""); + + if (decl != nullptr) + { + decl->staticConf = res->GetStaticConf(); + if (res->GetResourceType() == ZResourceType::Symbol) + { + decl->staticConf = StaticConfig::Off; + } + } + } +} + +void ZFile::AddTextureResource(uint32_t offset, ZTexture* tex) +{ + for (auto res : resources) + assert(res->GetRawDataIndex() != offset); + + resources.push_back(tex); + texturesResources[offset] = tex; +} + +ZTexture* ZFile::GetTextureResource(uint32_t offset) const +{ + auto tex = texturesResources.find(offset); + if (tex != texturesResources.end()) + return tex->second; + + return nullptr; +} + +void ZFile::AddSymbolResource(uint32_t offset, ZSymbol* sym) +{ + symbolResources[offset] = sym; +} + +ZSymbol* ZFile::GetSymbolResource(uint32_t offset) const +{ + auto sym = symbolResources.find(offset); + if (sym != symbolResources.end()) + return sym->second; + + return nullptr; +} + +ZSymbol* ZFile::GetSymbolResourceRanged(uint32_t offset) const +{ + for (const auto decl : symbolResources) + { + if (offset >= decl.first && offset < decl.first + decl.second->GetRawDataSize()) + return decl.second; + } + + return nullptr; +} + +fs::path ZFile::GetSourceOutputFolderPath() const +{ + return outputPath / outName.parent_path(); +} + +bool ZFile::IsOffsetInFileRange(uint32_t offset) const +{ + if (!(offset < rawData.size())) + return false; + + return rangeStart <= offset && offset < rangeEnd; +} +bool ZFile::IsSegmentedInFilespaceRange(segptr_t segAddress) const +{ + uint8_t segnum = GETSEGNUM(segAddress); + uint32_t offset = Seg2Filespace(segAddress, baseAddress); + + if (segment != segnum) + return false; + + return IsOffsetInFileRange(offset); +} + +std::map* ZFile::GetNodeMap() +{ + static std::map nodeMap; + return &nodeMap; +} + +void ZFile::RegisterNode(std::string nodeName, ZResourceFactoryFunc* nodeFunc) +{ + std::map* nodeMap = GetNodeMap(); + (*nodeMap)[nodeName] = nodeFunc; +} + +std::string ZFile::ProcessDeclarations() +{ + std::string output; + + if (declarations.size() == 0) + return output; + + defines += ProcessTextureIntersections(name); + + // printf("RANGE START: 0x%06X - RANGE END: 0x%06X\n", rangeStart, rangeEnd); + + // Optimization: See if there are any arrays side by side that can be merged... + std::vector> declarationKeys(declarations.begin(), + declarations.end()); + + std::pair lastItem = declarationKeys.at(0); + + for (size_t i = 1; i < declarationKeys.size(); i++) + { + std::pair curItem = declarationKeys[i]; + + if (curItem.second->isArray && lastItem.second->isArray) + { + if (curItem.second->varType == lastItem.second->varType) + { + if (!curItem.second->declaredInXml && !lastItem.second->declaredInXml) + { + // TEST: For now just do Vtx declarations... + if (lastItem.second->varType == "Vtx") + { + int32_t sizeDiff = curItem.first - (lastItem.first + lastItem.second->size); + + // Make sure there isn't an unaccounted inbetween these two + if (sizeDiff == 0) + { + lastItem.second->size += curItem.second->size; + lastItem.second->arrayItemCnt += curItem.second->arrayItemCnt; + lastItem.second->text += "\n" + curItem.second->text; + declarations.erase(curItem.first); + declarationKeys.erase(declarationKeys.begin() + i); + delete curItem.second; + i--; + continue; + } + } + } + } + } + + lastItem = curItem; + } + + for (std::pair item : declarations) + ProcessDeclarationText(item.second); + + for (std::pair item : declarations) + { + while (item.second->size % 4 != 0) + item.second->size++; + } + + HandleUnaccountedData(); + + // Go through include declarations + // First, handle the prototypes (static only for now) + for (std::pair item : declarations) + { + output += item.second->GetStaticForwardDeclarationStr(); + } + + output += "\n"; + + // Next, output the actual declarations + for (const auto& item : declarations) + { + if (!IsOffsetInFileRange(item.first)) + continue; + + if (item.second->includePath != "") + { + if (item.second->isExternal) + { + if (!Globals::Instance->otrMode) + { + // HACK + std::string extType; + + if (item.second->varType == "Gfx") + extType = "dlist"; + else if (item.second->varType == "Vtx") + extType = "vtx"; + + auto filepath = outputPath / item.second->varName; + File::WriteAllText( + StringHelper::Sprintf("%s.%s.inc", filepath.string().c_str(), extType.c_str()), + item.second->text); + } + } + + output += item.second->GetExternalDeclarationStr(); + } + else if (item.second->varType != "") + { + output += item.second->GetNormalDeclarationStr(); + } + } + + return output; +} + +void ZFile::ProcessDeclarationText(Declaration* decl) +{ + size_t refIndex = 0; + + if (!(decl->references.size() > 0)) + return; + + for (size_t i = 0; i < decl->text.size() - 1; i++) + { + char c = decl->text[i]; + char c2 = decl->text[i + 1]; + + if (c == '@' && c2 == 'r') + { + std::string vtxName; + Globals::Instance->GetSegmentedArrayIndexedName(decl->references[refIndex], 0x10, this, + "Vtx", vtxName); + decl->text.replace(i, 2, vtxName); + + refIndex++; + + if (refIndex >= decl->references.size()) + break; + } + } +} + +std::string ZFile::ProcessExterns() +{ + std::string output; + + for (const auto& item : declarations) + { + if (!IsOffsetInFileRange(item.first)) + { + continue; + } + + output += item.second->GetExternStr(); + } + + output += "\n"; + + output += defines; + + return output; +} + +std::string ZFile::ProcessTextureIntersections([[maybe_unused]] const std::string& prefix) +{ + if (texturesResources.empty()) + return ""; + + std::string defines; + std::vector> texturesSorted(texturesResources.begin(), + texturesResources.end()); + + for (size_t i = 0; i < texturesSorted.size() - 1; i++) + { + uint32_t currentOffset = texturesSorted[i].first; + uint32_t nextOffset = texturesSorted[i + 1].first; + auto& currentTex = texturesResources.at(currentOffset); + int texSize = currentTex->GetRawDataSize(); + + if (currentTex->WasDeclaredInXml()) + { + // We believe the user is right. + continue; + } + + if ((currentOffset + texSize) > nextOffset) + { + uint32_t offsetDiff = nextOffset - currentOffset; + if (currentTex->isPalette) + { + // Shrink palette so it doesn't overlap + currentTex->SetDimensions(offsetDiff / currentTex->GetPixelMultiplyer(), 1); + + if (declarations.find(currentOffset) != declarations.end()) + declarations.at(currentOffset)->size = currentTex->GetRawDataSize(); + + currentTex->DeclareVar(GetName(), ""); + } + else + { + std::string texName; + std::string texNextName; + GetDeclarationPtrName(currentOffset, "", texName); + + Declaration* nextDecl = GetDeclaration(nextOffset); + if (nextDecl == nullptr) + texNextName = texturesResources.at(nextOffset)->GetName(); + else + texNextName = nextDecl->varName; + +#if 0 + defines += StringHelper::Sprintf("#define %s ((u32)%s + 0x%06X)\n", + texNextName.c_str(), texName.c_str(), offsetDiff); +#endif + + delete declarations[nextOffset]; + declarations.erase(nextOffset); + texturesResources.erase(nextOffset); + texturesSorted.erase(texturesSorted.begin() + i + 1); + + i--; + } + } + } + + return defines; +} + +void ZFile::HandleUnaccountedData() +{ + uint32_t lastAddr = 0; + uint32_t lastSize = 0; + std::vector declsAddresses; + + for (const auto& item : declarations) + { + declsAddresses.push_back(item.first); + } + + bool breakLoop = false; + for (offset_t currentAddress : declsAddresses) + { + if (currentAddress >= rangeEnd) + { + breakLoop = true; + break; + } + + if (currentAddress < rangeStart) + { + lastAddr = currentAddress; + continue; + } + + breakLoop = HandleUnaccountedAddress(currentAddress, lastAddr, lastSize); + if (breakLoop) + break; + + lastAddr = currentAddress; + } + + if (!breakLoop) + { + // TODO: change rawData.size() to rangeEnd + // HandleUnaccountedAddress(rangeEnd, lastAddr, lastSize); + HandleUnaccountedAddress(rawData.size(), lastAddr, lastSize); + } +} + +bool ZFile::HandleUnaccountedAddress(offset_t currentAddress, offset_t lastAddr, uint32_t& lastSize) +{ + if (currentAddress != lastAddr && declarations.find(lastAddr) != declarations.end()) + { + Declaration* lastDecl = declarations.at(lastAddr); + lastSize = lastDecl->size; + + if (lastAddr + lastSize > currentAddress) + { + Declaration* currentDecl = declarations.at(currentAddress); + + std::string intersectionInfo = StringHelper::Sprintf( + "Resource from 0x%06X:0x%06X (%s) conflicts with 0x%06X (%s).", lastAddr, + lastAddr + lastSize, lastDecl->varName.c_str(), currentAddress, + currentDecl->varName.c_str()); + HANDLE_WARNING_RESOURCE(WarningType::Intersection, this, nullptr, currentAddress, + "intersection detected", intersectionInfo); + } + } + + uint32_t unaccountedAddress = lastAddr + lastSize; + + if (unaccountedAddress != currentAddress && lastAddr >= rangeStart && + unaccountedAddress < rangeEnd) + { + int diff = currentAddress - unaccountedAddress; + bool nonZeroUnaccounted = false; + + std::string src = " "; + + if (currentAddress > rawData.size()) + { + throw std::runtime_error(StringHelper::Sprintf( + "ZFile::ProcessDeclarations(): Fatal error while processing XML '%s'.\n" + "\t Offset '0x%X' is outside of the limits of file '%s', which has a size of " + "'0x%X'.\n" + "\t Aborting...", + xmlFilePath.c_str(), currentAddress, name.c_str(), rawData.size())); + } + + // Handle Align8 + if (currentAddress % 8 == 0 && diff % 8 != 0) + { + Declaration* currentDecl = GetDeclaration(currentAddress); + + if (currentDecl != nullptr) + { + if (currentDecl->alignment == DeclarationAlignment::Align8) + { + // Check removed bytes are zeroes + if (BitConverter::ToUInt32BE(rawData, unaccountedAddress + diff - 4) == 0) + { + diff -= 4; + } + } + + if (diff == 0) + { + return false; + } + } + } + + for (int i = 0; i < diff; i++) + { + uint8_t val = rawData.at(unaccountedAddress + i); + src += StringHelper::Sprintf("0x%02X, ", val); + if (val != 0x00) + { + nonZeroUnaccounted = true; + } + + if (Globals::Instance->verboseUnaccounted) + { + if ((i % 4 == 3)) + { + src += StringHelper::Sprintf(" // 0x%06X", unaccountedAddress + i - 3); + if (i != (diff - 1)) + { + src += "\n\t"; + } + } + } + else + { + if ((i % 16 == 15) && (i != (diff - 1))) + src += "\n "; + } + } + + if (declarations.find(unaccountedAddress) == declarations.end() && diff > 0) + { + std::string unaccountedPrefix = "unaccounted"; + + if (diff < 16 && !nonZeroUnaccounted) + { + unaccountedPrefix = "possiblePadding"; + + // Strip unnecessary padding at the end of the file. + if (unaccountedAddress + diff >= rawData.size()) + return true; + } + + Declaration* decl = AddDeclarationArray( + unaccountedAddress, DeclarationAlignment::Align4, diff, "u8", + StringHelper::Sprintf("%s_%s_%06X", name.c_str(), unaccountedPrefix.c_str(), + unaccountedAddress), + diff, src); + + decl->isUnaccounted = true; + if (Globals::Instance->forceUnaccountedStatic) + decl->staticConf = StaticConfig::On; + + if (nonZeroUnaccounted) + { + HANDLE_WARNING_RESOURCE(WarningType::Unaccounted, this, nullptr, unaccountedAddress, + "a non-zero unaccounted block was found", + StringHelper::Sprintf("Block size: '0x%X'", diff)); + } + else if (diff >= 16) + { + HANDLE_WARNING_RESOURCE(WarningType::Unaccounted, this, nullptr, unaccountedAddress, + "a big (size>=0x10) zero-only unaccounted block was found", + StringHelper::Sprintf("Block size: '0x%X'", diff)); + } + } + } + + return false; +} diff --git a/ZAPDTR/ZAPD/ZFile.h b/ZAPDTR/ZAPD/ZFile.h new file mode 100644 index 000000000..ac4062d5b --- /dev/null +++ b/ZAPDTR/ZAPD/ZFile.h @@ -0,0 +1,137 @@ +#pragma once + +#include +#include + +#include "ZSymbol.h" +#include "ZTexture.h" +#include "tinyxml2.h" + +enum class ZFileMode +{ + BuildTexture, + BuildOverlay, + BuildBlob, + BuildSourceFile, + BuildBackground, + Extract, + ExternalFile, + Invalid, + Custom = 1000, // Used for exporter file modes +}; + +enum class ZGame +{ + OOT_RETAIL, + OOT_SW97, + MM_RETAIL +}; + +class ZFile +{ +public: + std::map declarations; + std::string defines; + std::vector resources; + + // Default to using virtual addresses + uint32_t segment = 0x80; + uint32_t baseAddress, rangeStart, rangeEnd; + bool isExternalFile = 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); + ~ZFile(); + + std::string GetName() const; + std::string GetOutName() const; + ZFileMode GetMode() const; + const fs::path& GetXmlFilePath() const; + const std::vector& GetRawData() const; + void ExtractResources(); + void BuildSourceFile(); + void AddResource(ZResource* res); + ZResource* FindResource(uint32_t rawDataIndex); + std::vector 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); + + 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(uint32_t address) const; + Declaration* GetDeclarationRanged(uint32_t address) const; + bool HasDeclaration(uint32_t address); + + 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* GetNodeMap(); + static void RegisterNode(std::string nodeName, ZResourceFactoryFunc* nodeFunc); + +protected: + std::vector rawData; + std::string name; + fs::path outName = ""; + fs::path basePath; + fs::path outputPath; + fs::path xmlFilePath; + + // 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 texturesResources; + std::map symbolResources; + ZFileMode mode = ZFileMode::Invalid; + + ZFile(); + void ParseXML(tinyxml2::XMLElement* reader, const std::string& filename); + void DeclareResourceSubReferences(); + void GenerateSourceFiles(); + void GenerateSourceHeaderFiles(); + bool AddDeclarationChecks(uint32_t address, const std::string& varName); + std::string ProcessDeclarations(); + 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); +}; diff --git a/ZAPDTR/ZAPD/ZLimb.cpp b/ZAPDTR/ZAPD/ZLimb.cpp new file mode 100644 index 000000000..330fbaf7c --- /dev/null +++ b/ZAPDTR/ZAPD/ZLimb.cpp @@ -0,0 +1,385 @@ +#include "ZLimb.h" + +#include + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "WarningHandler.h" + +REGISTER_ZFILENODE(Limb, ZLimb); + +ZLimb::ZLimb(ZFile* nParent) : ZResource(nParent), segmentStruct(nParent) +{ + 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); + + // Reading from a + std::string limbType = registeredAttributes.at("LimbType").value; + if (limbType == "") // Reading from a + limbType = registeredAttributes.at("Type").value; + + if (limbType == "") + { + HANDLE_ERROR_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + "missing 'LimbType' attribute in ", ""); + } + + 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(BitConverter::ToInt32BE(rawData, rawDataIndex + 8)); + skinSegment = BitConverter::ToUInt32BE(rawData, rawDataIndex + 12); + if (skinSegmentType == ZLimbSkinType::SkinType_4) + { + 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_4: + if (skinSegment != 0 && GETSEGNUM(skinSegment) == parent->segment) + { + segmentStruct.DeclareReferences(varPrefix); + segmentStruct.GetSourceOutputCode(varPrefix); + } + break; + + case ZLimbSkinType::SkinType_DList: + 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 +{ + std::string dListStr; + std::string dListStr2; + Globals::Instance->GetSegmentedArrayIndexedName(dListPtr, 8, parent, "Gfx", dListStr); + Globals::Instance->GetSegmentedArrayIndexedName(dList2Ptr, 8, parent, "Gfx", dListStr2); + + std::string entryStr = "\n\t"; + if (type == ZLimbType::Legacy) + { + std::string childName; + std::string siblingName; + Globals::Instance->GetSegmentedPtrName(childPtr, parent, "LegacyLimb", childName); + Globals::Instance->GetSegmentedPtrName(siblingPtr, parent, "LegacyLimb", siblingName); + + 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 + { + if (type != ZLimbType::Curve) + { + entryStr += StringHelper::Sprintf("{ %i, %i, %i }, ", transX, transY, transZ); + } + entryStr += StringHelper::Sprintf("0x%02X, 0x%02X,\n", childIndex, siblingIndex); + + 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); + 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::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); + 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); +} diff --git a/ZAPDTR/ZAPD/ZLimb.h b/ZAPDTR/ZAPD/ZLimb.h new file mode 100644 index 000000000..53a414329 --- /dev/null +++ b/ZAPDTR/ZAPD/ZLimb.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +#include "OtherStructs/SkinLimbStructs.h" +#include "ZDisplayList.h" +#include "ZFile.h" + +enum class ZLimbType +{ + Invalid, + Standard, + LOD, + Skin, + Curve, + Legacy, +}; + +class ZLimb : public ZResource +{ +public: + ZLimbType type = ZLimbType::Standard; + + ZLimbSkinType skinSegmentType = ZLimbSkinType::SkinType_0; // Skin only + segptr_t skinSegment = 0; // Skin only + Struct_800A5E28 segmentStruct; // Skin only + + // Legacy only + float legTransX, legTransY, legTransZ; // Vec3f + uint16_t rotX, rotY, rotZ; // Vec3s + segptr_t childPtr; // LegacyLimb* + segptr_t siblingPtr; // LegacyLimb* + + segptr_t dListPtr = 0; + segptr_t dList2Ptr = 0; // LOD and Curve Only + + int16_t transX, transY, transZ; + uint8_t childIndex, siblingIndex; + + 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); + +protected: + void DeclareDList(segptr_t dListSegmentedPtr, const std::string& prefix, + const std::string& limbSuffix); +}; diff --git a/ZAPDTR/ZAPD/ZMtx.cpp b/ZAPDTR/ZAPD/ZMtx.cpp new file mode 100644 index 000000000..b9ca3f22d --- /dev/null +++ b/ZAPDTR/ZAPD/ZMtx.cpp @@ -0,0 +1,58 @@ +#include "ZMtx.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Mtx, ZMtx); + +ZMtx::ZMtx(ZFile* nParent) : ZResource(nParent) +{ +} + +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; +} diff --git a/ZAPDTR/ZAPD/ZMtx.h b/ZAPDTR/ZAPD/ZMtx.h new file mode 100644 index 000000000..1b5513cd4 --- /dev/null +++ b/ZAPDTR/ZAPD/ZMtx.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#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, 4> mtx; +}; diff --git a/ZAPDTR/ZAPD/ZPath.cpp b/ZAPDTR/ZAPD/ZPath.cpp new file mode 100644 index 000000000..e19513db3 --- /dev/null +++ b/ZAPDTR/ZAPD/ZPath.cpp @@ -0,0 +1,209 @@ +#include "ZPath.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Path, ZPath); + +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; + + 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); + + 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); + 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->text = declaration; +} + +std::string PathwayEntry::GetBodySourceCode() const +{ + std::string declaration; + std::string listName; + Globals::Instance->GetSegmentedPtrName(listSegmentAddress, parent, "Vec3s", listName); + + if (Globals::Instance->game == ZGame::MM_RETAIL) + declaration += + StringHelper::Sprintf("%i, %i, %i, %s", numPoints, unk1, unk2, 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; +} diff --git a/ZAPDTR/ZAPD/ZPath.h b/ZAPDTR/ZAPD/ZPath.h new file mode 100644 index 000000000..722e84afe --- /dev/null +++ b/ZAPDTR/ZAPD/ZPath.h @@ -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 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 pathways; +}; diff --git a/ZAPDTR/ZAPD/ZPlayerAnimationData.cpp b/ZAPDTR/ZAPD/ZPlayerAnimationData.cpp new file mode 100644 index 000000000..a96604fda --- /dev/null +++ b/ZAPDTR/ZAPD/ZPlayerAnimationData.cpp @@ -0,0 +1,97 @@ +#include "ZPlayerAnimationData.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.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::ToUInt16BE(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 = ""; + + size_t index = 0; + for (const auto& entry : limbRotData) + { + if (index % 8 == 0) + { + declaration += "\t"; + } + + 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; +} diff --git a/ZAPDTR/ZAPD/ZPlayerAnimationData.h b/ZAPDTR/ZAPD/ZPlayerAnimationData.h new file mode 100644 index 000000000..20835f236 --- /dev/null +++ b/ZAPDTR/ZAPD/ZPlayerAnimationData.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include "ZResource.h" + +class ZPlayerAnimationData : public ZResource +{ +public: + int16_t frameCount = 0; + std::vector 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; +}; diff --git a/ZAPDTR/ZAPD/ZResource.cpp b/ZAPDTR/ZAPD/ZResource.cpp new file mode 100644 index 000000000..a5ad4cf21 --- /dev/null +++ b/ZAPDTR/ZAPD/ZResource.cpp @@ -0,0 +1,380 @@ +#include "ZResource.h" + +#include +#include + +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZFile.h" +#include +#include + +ZResource::ZResource(ZFile* nParent) +{ + // assert(nParent != nullptr); + parent = nParent; + name = ""; + outName = ""; + sourceOutput = ""; + rawDataIndex = 0; + outputDeclaration = true; + + RegisterRequiredAttribute("Name"); + RegisterOptionalAttribute("OutName"); + RegisterOptionalAttribute("Offset"); + RegisterOptionalAttribute("Custom"); + RegisterOptionalAttribute("Static", "Global"); +} + +void ZResource::ExtractFromXML(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 (!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; + + 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; +} + +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->text = bodyStr; + + if (decl != nullptr) + decl->staticConf = staticConf; + } +} + +std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix) +{ + 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")) + prefix = "scenes"; + 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 %s \"__OTR__%s/%s/%s\"", name.c_str(), prefix.c_str(), outName.c_str(), nameStr.c_str()); + else + str += StringHelper::Sprintf("#define %s \"__OTR__%s/%s\"", name.c_str(), outName.c_str(), nameStr.c_str()); + + 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; +} diff --git a/ZAPDTR/ZAPD/ZResource.h b/ZAPDTR/ZAPD/ZResource.h new file mode 100644 index 000000000..82709aec0 --- /dev/null +++ b/ZAPDTR/ZAPD/ZResource.h @@ -0,0 +1,244 @@ +#pragma once + +#include +#include +#include +#include +#include +#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, + Text +}; + +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; + + // Parsing from File + virtual void ExtractFromXML(tinyxml2::XMLElement* reader, offset_t nRawDataIndex); + 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); + 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 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; + /** + * 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 nodes + /** + * Is this resource an inner node of another resource? + * (namely inside an ) + */ + 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 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(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 diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.cpp new file mode 100644 index 000000000..3f64af168 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.cpp @@ -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; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.h b/ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.h new file mode 100644 index 000000000..daa477c94 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/EndMarker.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class EndMarker : public ZRoomCommand +{ +public: + EndMarker(ZFile* nParent); + + std::string GetBodySourceCode() const override; + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetActorCutsceneList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorCutsceneList.cpp new file mode 100644 index 000000000..60391a9d1 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorCutsceneList.cpp @@ -0,0 +1,93 @@ +#include "SetActorCutsceneList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetActorCutsceneList::SetActorCutsceneList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetActorCutsceneList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + int numCutscenes = cmdArg1; + int32_t currentPtr = segmentOffset; + + for (int32_t i = 0; i < numCutscenes; i++) + { + ActorCutsceneEntry entry(parent->GetRawData(), currentPtr); + cutscenes.push_back(entry); + + currentPtr += 16; + } +} + +void SetActorCutsceneList::DeclareReferences(const std::string& prefix) +{ + if (cutscenes.size() > 0) + { + std::string declaration; + + for (size_t i = 0; i < cutscenes.size(); i++) + { + const auto& entry = cutscenes.at(i); + declaration += StringHelper::Sprintf(" { %s },", entry.GetBodySourceCode().c_str()); + + if (i + 1 < cutscenes.size()) + { + declaration += "\n"; + } + } + + std::string typeName = cutscenes.at(0).GetSourceTypeName(); + + parent->AddDeclarationArray( + segmentOffset, GetDeclarationAlignment(), cutscenes.size() * 16, typeName, + StringHelper::Sprintf("%s%sList_%06X", prefix.c_str(), typeName.c_str(), segmentOffset), + cutscenes.size(), declaration); + } +} + +std::string SetActorCutsceneList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "ActorCutscene", listName); + return StringHelper::Sprintf("SCENE_CMD_ACTOR_CUTSCENE_LIST(%i, %s)", cutscenes.size(), + listName.c_str()); +} + +std::string SetActorCutsceneList::GetCommandCName() const +{ + return "SCmdCutsceneActorList"; +} + +RoomCommand SetActorCutsceneList::GetRoomCommand() const +{ + return RoomCommand::SetActorCutsceneList; +} + +ActorCutsceneEntry::ActorCutsceneEntry(const std::vector& rawData, uint32_t rawDataIndex) + : priority(BitConverter::ToInt16BE(rawData, rawDataIndex + 0)), + length(BitConverter::ToInt16BE(rawData, rawDataIndex + 2)), + unk4(BitConverter::ToInt16BE(rawData, rawDataIndex + 4)), + unk6(BitConverter::ToInt16BE(rawData, rawDataIndex + 6)), + additionalCutscene(BitConverter::ToInt16BE(rawData, rawDataIndex + 8)), + sound(rawData[rawDataIndex + 0xA]), unkB(rawData[rawDataIndex + 0xB]), + unkC(BitConverter::ToInt16BE(rawData, rawDataIndex + 0xC)), unkE(rawData[rawDataIndex + 0xE]), + letterboxSize(rawData[rawDataIndex + 0xF]) +{ +} + +std::string ActorCutsceneEntry::GetBodySourceCode() const +{ + return StringHelper::Sprintf("%i, %i, %i, %i, %i, %i, %i, %i, %i, %i", priority, length, unk4, + unk6, additionalCutscene, sound, unkB, unkC, unkE, letterboxSize); +} + +std::string ActorCutsceneEntry::GetSourceTypeName() const +{ + return "ActorCutscene"; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetActorCutsceneList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorCutsceneList.h new file mode 100644 index 000000000..8fd48e425 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorCutsceneList.h @@ -0,0 +1,42 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class ActorCutsceneEntry +{ +protected: + int16_t priority; + int16_t length; + int16_t unk4; + int16_t unk6; + int16_t additionalCutscene; + uint8_t sound; + uint8_t unkB; + int16_t unkC; + uint8_t unkE; + uint8_t letterboxSize; + +public: + ActorCutsceneEntry(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; + std::string GetSourceTypeName() const; +}; + +class SetActorCutsceneList : public ZRoomCommand +{ +public: + std::vector cutscenes; + + SetActorCutsceneList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; + +private: +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetActorList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorList.cpp new file mode 100644 index 000000000..919d86f57 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorList.cpp @@ -0,0 +1,179 @@ +#include "SetActorList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZNames.h" +#include "ZRoom/ZRoom.h" + +SetActorList::SetActorList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetActorList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + numActors = cmdArg1; +} + +void SetActorList::DeclareReferences(const std::string& prefix) +{ + if (numActors != 0 && cmdArg2 != 0) + { + std::string varName = + StringHelper::Sprintf("%sActorList_%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationPlaceholder(segmentOffset, varName); + } +} + +void SetActorList::ParseRawDataLate() +{ + ZRoomCommand::ParseRawDataLate(); + size_t actorsAmount = zRoom->GetDeclarationSizeFromNeighbor(segmentOffset) / 0x10; + + uint32_t currentPtr = segmentOffset; + + for (size_t i = 0; i < actorsAmount; i++) + { + ActorSpawnEntry entry(parent->GetRawData(), currentPtr); + + currentPtr += entry.GetRawDataSize(); + actors.push_back(entry); + } +} + +void SetActorList::DeclareReferencesLate(const std::string& prefix) +{ + if (actors.empty()) + return; + + std::string declaration; + + size_t largestlength = 0; + for (const auto& entry : actors) + { + size_t actorNameLength = ZNames::GetActorName(entry.GetActorId()).size(); + if (actorNameLength > largestlength) + largestlength = actorNameLength; + } + + size_t index = 0; + for (auto& entry : actors) + { + entry.SetLargestActorName(largestlength); + declaration += StringHelper::Sprintf("\t{ %s },", entry.GetBodySourceCode().c_str()); + + if (index < actors.size() - 1) + declaration += "\n"; + + index++; + } + + const auto& entry = actors.front(); + + std::string varName = StringHelper::Sprintf("%sActorList_%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationArray(segmentOffset, DeclarationAlignment::Align4, + actors.size() * entry.GetRawDataSize(), entry.GetSourceTypeName(), + varName, GetActorListArraySize(), declaration); +} + +std::string SetActorList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "ActorEntry", listName); + if (numActors != actors.size()) + { + printf("%s: numActors(%i) ~ actors(%li)\n", parent->GetName().c_str(), numActors, + actors.size()); + } + return StringHelper::Sprintf("SCENE_CMD_ACTOR_LIST(%i, %s)", numActors, listName.c_str()); +} + +size_t SetActorList::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; +} + +std::string SetActorList::GetCommandCName() const +{ + return "SCmdActorList"; +} + +RoomCommand SetActorList::GetRoomCommand() const +{ + return RoomCommand::SetActorList; +} + +ActorSpawnEntry::ActorSpawnEntry(const std::vector& 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); + initVar = 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", initVar); + + return body; +} + +std::string ActorSpawnEntry::GetSourceTypeName() const +{ + return "ActorEntry"; +} + +int32_t ActorSpawnEntry::GetRawDataSize() const +{ + return 16; +} + +uint16_t ActorSpawnEntry::GetActorId() const +{ + return actorNum; +} + +void ActorSpawnEntry::SetLargestActorName(size_t nameSize) +{ + largestActorName = nameSize; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetActorList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorList.h new file mode 100644 index 000000000..7b341256c --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetActorList.h @@ -0,0 +1,50 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.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 initVar; + size_t largestActorName = 16; + + ActorSpawnEntry(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; + + std::string GetSourceTypeName() const; + int32_t GetRawDataSize() const; + + uint16_t GetActorId() const; + void SetLargestActorName(size_t nameSize); +}; + +class SetActorList : public ZRoomCommand +{ +public: + uint8_t numActors; + std::vector actors; + + SetActorList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + void ParseRawDataLate() override; + void DeclareReferencesLate(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; + +protected: + size_t GetActorListArraySize() const; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetAlternateHeaders.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetAlternateHeaders.cpp new file mode 100644 index 000000000..629d4a0b0 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetAlternateHeaders.cpp @@ -0,0 +1,81 @@ +#include "SetAlternateHeaders.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" + +SetAlternateHeaders::SetAlternateHeaders(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetAlternateHeaders::DeclareReferences([[maybe_unused]] const std::string& prefix) +{ + if (cmdArg2 != 0) + { + std::string varName = + StringHelper::Sprintf("%sAlternateHeaders0x%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationPlaceholder(segmentOffset, varName); + } +} + +void SetAlternateHeaders::ParseRawDataLate() +{ + int numHeaders = zRoom->GetDeclarationSizeFromNeighbor(segmentOffset) / 4; + + for (int32_t i = 0; i < numHeaders; i++) + { + int32_t address = BitConverter::ToInt32BE(parent->GetRawData(), segmentOffset + (i * 4)); + headers.push_back(address); + + if (address != 0 && parent->GetDeclaration(GETSEGOFFSET(address)) == nullptr) + { + ZRoom* altheader = new ZRoom(parent); + altheader->ExtractFromBinary(GETSEGOFFSET(address), zRoom->GetResourceType()); + altheader->DeclareReferences(parent->GetName()); + + parent->resources.push_back(altheader); + } + } +} + +void SetAlternateHeaders::DeclareReferencesLate(const std::string& prefix) +{ + if (!headers.empty()) + { + std::string declaration; + + for (size_t i = 0; i < headers.size(); i++) + { + std::string altHeaderName; + Globals::Instance->GetSegmentedPtrName(headers.at(i), parent, "", altHeaderName); + + declaration += StringHelper::Sprintf("\t%s,", altHeaderName.c_str()); + + if (i + 1 < headers.size()) + declaration += "\n"; + } + + std::string varName = + StringHelper::Sprintf("%sAlternateHeaders0x%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationArray(segmentOffset, GetDeclarationAlignment(), headers.size() * 4, + "SceneCmd*", varName, headers.size(), declaration); + } +} + +std::string SetAlternateHeaders::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "SceneCmd*", listName); + return StringHelper::Sprintf("SCENE_CMD_ALTERNATE_HEADER_LIST(%s)", listName.c_str()); +} + +std::string SetAlternateHeaders::GetCommandCName() const +{ + return "SCmdAltHeaders"; +} + +RoomCommand SetAlternateHeaders::GetRoomCommand() const +{ + return RoomCommand::SetAlternateHeaders; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetAlternateHeaders.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetAlternateHeaders.h new file mode 100644 index 000000000..e66df936d --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetAlternateHeaders.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ZRoom/ZRoom.h" +#include "ZRoom/ZRoomCommand.h" + +class SetAlternateHeaders : public ZRoomCommand +{ +public: + std::vector headers; + + SetAlternateHeaders(ZFile* nParent); + + void DeclareReferences(const std::string& prefix) override; + void ParseRawDataLate() override; + void DeclareReferencesLate(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; + +private: +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetAnimatedMaterialList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetAnimatedMaterialList.cpp new file mode 100644 index 000000000..0b9a67e0e --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetAnimatedMaterialList.cpp @@ -0,0 +1,48 @@ +/** + * File: SetAnimatedMaterialList.cpp + * Description: Defines a class SetAnimatedMaterialList to enable ZRoom to declare + * ZTextureAnimations, using that ZResource to do the work. + */ +#include "SetAnimatedMaterialList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" +#include "ZTextureAnimation.h" + +SetAnimatedMaterialList::SetAnimatedMaterialList(ZFile* nParent) + : ZRoomCommand(nParent), textureAnimation(nParent) +{ +} + +void SetAnimatedMaterialList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + textureAnimation.ExtractFromFile(segmentOffset); +} + +void SetAnimatedMaterialList::DeclareReferences(const std::string& prefix) +{ + textureAnimation.SetName(textureAnimation.GetDefaultName(prefix.c_str())); + textureAnimation.DeclareReferences(prefix); + textureAnimation.GetSourceOutputCode(prefix); +} + +std::string SetAnimatedMaterialList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "AnimatedMaterial", listName); + return StringHelper::Sprintf("SCENE_CMD_ANIMATED_MATERIAL_LIST(%s)", listName.c_str()); +} + +std::string SetAnimatedMaterialList::GetCommandCName() const +{ + return "SCmdTextureAnimations"; +} + +RoomCommand SetAnimatedMaterialList::GetRoomCommand() const +{ + return RoomCommand::SetAnimatedMaterialList; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetAnimatedMaterialList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetAnimatedMaterialList.h new file mode 100644 index 000000000..3dbbf9684 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetAnimatedMaterialList.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" +#include "ZTextureAnimation.h" + +class SetAnimatedMaterialList : public ZRoomCommand +{ +public: + SetAnimatedMaterialList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; + +private: + ZTextureAnimation textureAnimation; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCameraSettings.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetCameraSettings.cpp new file mode 100644 index 000000000..ae2d31c81 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCameraSettings.cpp @@ -0,0 +1,31 @@ +#include "SetCameraSettings.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" + +SetCameraSettings::SetCameraSettings(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetCameraSettings::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + cameraMovement = cmdArg1; + mapHighlight = BitConverter::ToUInt32BE(parent->GetRawData(), rawDataIndex + 4); +} + +std::string SetCameraSettings::GetBodySourceCode() const +{ + return StringHelper::Sprintf("SCENE_CMD_MISC_SETTINGS(0x%02X, 0x%08X)", cameraMovement, + mapHighlight); +} + +std::string SetCameraSettings::GetCommandCName() const +{ + return "SCmdMiscSettings"; +} + +RoomCommand SetCameraSettings::GetRoomCommand() const +{ + return RoomCommand::SetCameraSettings; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCameraSettings.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetCameraSettings.h new file mode 100644 index 000000000..a8fed44ec --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCameraSettings.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetCameraSettings : public ZRoomCommand +{ +public: + uint8_t cameraMovement; + uint32_t mapHighlight; + + SetCameraSettings(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; + +private: +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCollisionHeader.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetCollisionHeader.cpp new file mode 100644 index 000000000..03aaa4bbb --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCollisionHeader.cpp @@ -0,0 +1,44 @@ +#include "SetCollisionHeader.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetCollisionHeader::SetCollisionHeader(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetCollisionHeader::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + + collisionHeader = new ZCollisionHeader(parent); + collisionHeader->SetName( + StringHelper::Sprintf("%sCollisionHeader_%06X", parent->GetName().c_str(), segmentOffset)); + collisionHeader->ExtractFromFile(segmentOffset); + parent->AddResource(collisionHeader); +} + +void SetCollisionHeader::DeclareReferences(const std::string& prefix) +{ + collisionHeader->DeclareVar(prefix, ""); +} + +std::string SetCollisionHeader::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "CollisionHeader", listName); + return StringHelper::Sprintf("SCENE_CMD_COL_HEADER(%s)", listName.c_str()); +} + +std::string SetCollisionHeader::GetCommandCName() const +{ + return "SCmdColHeader"; +} + +RoomCommand SetCollisionHeader::GetRoomCommand() const +{ + return RoomCommand::SetCollisionHeader; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCollisionHeader.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetCollisionHeader.h new file mode 100644 index 000000000..f7d5ecf35 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCollisionHeader.h @@ -0,0 +1,20 @@ +#pragma once + +#include "ZCollision.h" +#include "ZRoom/ZRoomCommand.h" + +class SetCollisionHeader : public ZRoomCommand +{ +public: + ZCollisionHeader* collisionHeader; + + SetCollisionHeader(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCsCamera.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetCsCamera.cpp new file mode 100644 index 000000000..5cf0a3d03 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCsCamera.cpp @@ -0,0 +1,152 @@ +#include "SetCsCamera.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetCsCamera::SetCsCamera(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetCsCamera::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + int numCameras = cmdArg1; + + uint32_t currentPtr = segmentOffset; + int32_t numPoints = 0; + + for (int32_t i = 0; i < numCameras; i++) + { + CsCameraEntry entry(parent->GetRawData(), currentPtr); + numPoints += entry.GetNumPoints(); + + currentPtr += entry.GetRawDataSize(); + cameras.push_back(entry); + } + + if (numPoints > 0) + { + uint32_t currentPtr = cameras.at(0).GetSegmentOffset(); + + 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 SetCsCamera::DeclareReferences(const std::string& prefix) +{ + if (points.size() > 0) + { + std::string declaration; + size_t index = 0; + for (auto& point : points) + { + declaration += StringHelper::Sprintf("\t{ %s },", point.GetBodySourceCode().c_str()); + + if (index < points.size() - 1) + declaration += "\n"; + + index++; + } + + uint32_t segOffset = cameras.at(0).GetSegmentOffset(); + + parent->AddDeclarationArray( + segOffset, DeclarationAlignment::Align4, points.size() * points.at(0).GetRawDataSize(), + points.at(0).GetSourceTypeName().c_str(), + StringHelper::Sprintf("%sCsCameraPoints_%06X", prefix.c_str(), segOffset), + points.size(), declaration); + } + + if (!cameras.empty()) + { + std::string camPointsName; + Globals::Instance->GetSegmentedPtrName(cameras.at(0).GetCamAddress(), parent, "Vec3s", + camPointsName); + std::string declaration; + + size_t index = 0; + size_t pointsIndex = 0; + for (const auto& entry : cameras) + { + declaration += + StringHelper::Sprintf("\t{ %i, %i, &%s[%i] },", entry.type, entry.numPoints, + camPointsName.c_str(), pointsIndex); + + if (index < cameras.size() - 1) + declaration += "\n"; + + index++; + pointsIndex += entry.GetNumPoints(); + } + + const auto& entry = cameras.front(); + std::string camTypename = entry.GetSourceTypeName(); + + parent->AddDeclarationArray( + segmentOffset, DeclarationAlignment::Align4, cameras.size() * entry.GetRawDataSize(), + camTypename, + StringHelper::Sprintf("%s%s_%06X", prefix.c_str(), camTypename.c_str(), segmentOffset), + cameras.size(), declaration); + } +} + +std::string SetCsCamera::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "CsCameraEntry", listName); + return StringHelper::Sprintf("SCENE_CMD_ACTOR_CUTSCENE_CAM_LIST(%i, %s)", cameras.size(), + listName.c_str()); +} + +std::string SetCsCamera::GetCommandCName() const +{ + return "SCmdCsCameraList"; +} + +RoomCommand SetCsCamera::GetRoomCommand() const +{ + return RoomCommand::SetCsCamera; +} + +CsCameraEntry::CsCameraEntry(const std::vector& rawData, uint32_t rawDataIndex) + : baseOffset(rawDataIndex), type(BitConverter::ToInt16BE(rawData, rawDataIndex + 0)), + numPoints(BitConverter::ToInt16BE(rawData, rawDataIndex + 2)) +{ + camAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 4); + segmentOffset = GETSEGOFFSET(camAddress); +} + +std::string CsCameraEntry::GetSourceTypeName() const +{ + return "CsCameraEntry"; +} + +int32_t CsCameraEntry::GetRawDataSize() const +{ + return 8; +} + +int16_t CsCameraEntry::GetNumPoints() const +{ + return numPoints; +} + +segptr_t CsCameraEntry::GetCamAddress() const +{ + return camAddress; +} + +uint32_t CsCameraEntry::GetSegmentOffset() const +{ + return segmentOffset; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCsCamera.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetCsCamera.h new file mode 100644 index 000000000..5e0e3c825 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCsCamera.h @@ -0,0 +1,40 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" +#include "ZVector.h" + +class CsCameraEntry +{ +public: + CsCameraEntry(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetSourceTypeName() const; + int32_t GetRawDataSize() const; + + int16_t GetNumPoints() const; + segptr_t GetCamAddress() const; + uint32_t GetSegmentOffset() const; + + int baseOffset; + int16_t type; + int16_t numPoints; + segptr_t camAddress; + uint32_t segmentOffset; +}; + +class SetCsCamera : public ZRoomCommand +{ +public: + std::vector cameras; + std::vector points; + + SetCsCamera(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCutscenes.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetCutscenes.cpp new file mode 100644 index 000000000..e51e550b0 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCutscenes.cpp @@ -0,0 +1,112 @@ +#include "SetCutscenes.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetCutscenes::SetCutscenes(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +SetCutscenes::~SetCutscenes() +{ + for (ZCutsceneBase* cutscene : cutscenes) + delete cutscene; +} + +void SetCutscenes::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + std::string output; + + numCutscenes = cmdArg1; + if (Globals::Instance->game == ZGame::OOT_RETAIL || Globals::Instance->game == ZGame::OOT_SW97) + { + ZCutscene* cutscene = new ZCutscene(parent); + cutscene->ExtractFromFile(segmentOffset); + + auto decl = parent->GetDeclaration(segmentOffset); + if (decl == nullptr) + { + cutscene->DeclareVar(zRoom->GetName().c_str(), ""); + } + + cutscenes.push_back(cutscene); + } + else + { + int32_t currentPtr = segmentOffset; + std::string declaration; + + for (uint8_t i = 0; i < numCutscenes; i++) + { + CutsceneEntry entry(parent->GetRawData(), currentPtr); + cutsceneEntries.push_back(entry); + currentPtr += 8; + + // TODO: don't hardcode %sCutsceneData_%06X, look up for the declared name instead + declaration += StringHelper::Sprintf( + " { %sCutsceneData_%06X, 0x%04X, 0x%02X, 0x%02X },", zRoom->GetName().c_str(), + entry.segmentOffset, entry.exit, entry.entrance, entry.flag); + + if (i < numCutscenes - 1) + declaration += "\n"; + + ZCutsceneMM* cutscene = new ZCutsceneMM(parent); + cutscene->ExtractFromFile(entry.segmentOffset); + cutscenes.push_back(cutscene); + } + + parent->AddDeclarationArray(segmentOffset, DeclarationAlignment::Align4, + cutsceneEntries.size() * 8, "CutsceneEntry", + StringHelper::Sprintf("%sCutsceneEntryList_%06X", + zRoom->GetName().c_str(), segmentOffset), + cutsceneEntries.size(), declaration); + } + + for (ZCutsceneBase* cutscene : cutscenes) + { + if (cutscene->GetRawDataIndex() != 0) + { + Declaration* decl = parent->GetDeclaration(cutscene->GetRawDataIndex()); + if (decl == nullptr) + { + cutscene->GetSourceOutputCode(zRoom->GetName()); + } + else if (decl->text == "") + { + decl->text = cutscene->GetBodySourceCode(); + } + } + } +} + +std::string SetCutscenes::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "CutsceneData", listName); + + if (Globals::Instance->game == ZGame::MM_RETAIL) + return StringHelper::Sprintf("SCENE_CMD_CUTSCENE_LIST(%i, %s)", numCutscenes, + listName.c_str()); + return StringHelper::Sprintf("SCENE_CMD_CUTSCENE_DATA(%s)", listName.c_str()); +} + +std::string SetCutscenes::GetCommandCName() const +{ + return "SCmdCutsceneData"; +} + +RoomCommand SetCutscenes::GetRoomCommand() const +{ + return RoomCommand::SetCutscenes; +} + +CutsceneEntry::CutsceneEntry(const std::vector& rawData, uint32_t rawDataIndex) + : segmentOffset(GETSEGOFFSET(BitConverter::ToInt32BE(rawData, rawDataIndex + 0))), + exit(BitConverter::ToInt16BE(rawData, rawDataIndex + 4)), entrance(rawData[rawDataIndex + 6]), + flag(rawData[rawDataIndex + 7]) +{ +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetCutscenes.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetCutscenes.h new file mode 100644 index 000000000..ad032bbe6 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetCutscenes.h @@ -0,0 +1,34 @@ +#pragma once + +#include "ZCutscene.h" +#include "ZCutsceneMM.h" +#include "ZRoom/ZRoomCommand.h" + +class CutsceneEntry +{ +public: + CutsceneEntry(const std::vector& rawData, uint32_t rawDataIndex); + + uint32_t segmentOffset; + uint16_t exit; + uint8_t entrance; + uint8_t flag; +}; + +class SetCutscenes : public ZRoomCommand +{ +public: + std::vector cutscenes; + std::vector cutsceneEntries; // (MM Only) + uint8_t numCutscenes; // (MM Only) + + SetCutscenes(ZFile* nParent); + ~SetCutscenes(); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetEchoSettings.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetEchoSettings.cpp new file mode 100644 index 000000000..79a278bc6 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetEchoSettings.cpp @@ -0,0 +1,27 @@ +#include "SetEchoSettings.h" +#include "Utils/StringHelper.h" + +SetEchoSettings::SetEchoSettings(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetEchoSettings::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + echo = parent->GetRawData().at(rawDataIndex + 0x07); +} + +std::string SetEchoSettings::GetBodySourceCode() const +{ + return StringHelper::Sprintf("SCENE_CMD_ECHO_SETTINGS(%i)", echo); +} + +std::string SetEchoSettings::GetCommandCName() const +{ + return "SCmdEchoSettings"; +} + +RoomCommand SetEchoSettings::GetRoomCommand() const +{ + return RoomCommand::SetEchoSettings; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetEchoSettings.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetEchoSettings.h new file mode 100644 index 000000000..82b8c27db --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetEchoSettings.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetEchoSettings : public ZRoomCommand +{ +public: + uint8_t echo; + + SetEchoSettings(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetEntranceList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetEntranceList.cpp new file mode 100644 index 000000000..8099bacf1 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetEntranceList.cpp @@ -0,0 +1,89 @@ +#include "SetEntranceList.h" + +#include "Globals.h" +#include "SetStartPositionList.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetEntranceList::SetEntranceList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetEntranceList::DeclareReferences([[maybe_unused]] const std::string& prefix) +{ + if (segmentOffset != 0) + { + std::string varName = + StringHelper::Sprintf("%sEntranceList0x%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationPlaceholder(segmentOffset, varName); + } +} + +void SetEntranceList::ParseRawDataLate() +{ + // Parse Entrances and Generate Declaration + int numEntrances = zRoom->GetDeclarationSizeFromNeighbor(segmentOffset) / 2; + uint32_t currentPtr = segmentOffset; + + for (int32_t i = 0; i < numEntrances; i++) + { + EntranceEntry entry(parent->GetRawData(), currentPtr); + entrances.push_back(entry); + + currentPtr += 2; + } +} + +void SetEntranceList::DeclareReferencesLate([[maybe_unused]] const std::string& prefix) +{ + if (!entrances.empty()) + { + std::string declaration; + + size_t index = 0; + for (const auto& entry : entrances) + { + declaration += StringHelper::Sprintf(" { %s },", entry.GetBodySourceCode().c_str()); + if (index + 1 < entrances.size()) + declaration += "\n"; + + index++; + } + + std::string varName = + StringHelper::Sprintf("%sEntranceList0x%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationArray(segmentOffset, DeclarationAlignment::Align4, + entrances.size() * 2, "EntranceEntry", varName, + entrances.size(), declaration); + } +} + +std::string SetEntranceList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "EntranceEntry", listName); + return StringHelper::Sprintf("SCENE_CMD_ENTRANCE_LIST(%s)", listName.c_str()); +} + +std::string SetEntranceList::GetCommandCName() const +{ + return "SCmdEntranceList"; +} + +RoomCommand SetEntranceList::GetRoomCommand() const +{ + return RoomCommand::SetEntranceList; +} + +EntranceEntry::EntranceEntry(const std::vector& rawData, uint32_t rawDataIndex) +{ + startPositionIndex = rawData.at(rawDataIndex + 0); + roomToLoad = rawData.at(rawDataIndex + 1); +} + +std::string EntranceEntry::GetBodySourceCode() const +{ + return StringHelper::Sprintf("0x%02X, 0x%02X", startPositionIndex, roomToLoad); +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetEntranceList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetEntranceList.h new file mode 100644 index 000000000..e13e9a8ce --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetEntranceList.h @@ -0,0 +1,31 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class EntranceEntry +{ +public: + uint8_t startPositionIndex; + uint8_t roomToLoad; + + EntranceEntry(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; +}; + +class SetEntranceList : public ZRoomCommand +{ +public: + std::vector entrances; + + SetEntranceList(ZFile* nParent); + + void DeclareReferences(const std::string& prefix) override; + void ParseRawDataLate() override; + void DeclareReferencesLate(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetExitList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetExitList.cpp new file mode 100644 index 000000000..ddc4c5d43 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetExitList.cpp @@ -0,0 +1,73 @@ +#include "SetExitList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetExitList::SetExitList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetExitList::DeclareReferences([[maybe_unused]] const std::string& prefix) +{ + if (segmentOffset != 0) + { + std::string varName = + StringHelper::Sprintf("%sExitList_%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationPlaceholder(segmentOffset, varName); + } +} + +void SetExitList::ParseRawDataLate() +{ + // Parse Entrances and Generate Declaration + int numEntrances = zRoom->GetDeclarationSizeFromNeighbor(segmentOffset) / 2; + uint32_t currentPtr = segmentOffset; + + for (int32_t i = 0; i < numEntrances; i++) + { + uint16_t exit = BitConverter::ToUInt16BE(parent->GetRawData(), currentPtr); + exits.push_back(exit); + + currentPtr += 2; + } +} + +void SetExitList::DeclareReferencesLate([[maybe_unused]] const std::string& prefix) +{ + if (!exits.empty()) + { + std::string declaration; + + for (size_t i = 0; i < exits.size(); i++) + { + declaration += StringHelper::Sprintf(" 0x%04X,", exits.at(i)); + if (i + 1 < exits.size()) + declaration += "\n"; + } + + std::string varName = + StringHelper::Sprintf("%sExitList_%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationArray(segmentOffset, DeclarationAlignment::Align4, exits.size() * 2, + "u16", varName, exits.size(), declaration); + } +} + +std::string SetExitList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "u16", listName); + return StringHelper::Sprintf("SCENE_CMD_EXIT_LIST(%s)", listName.c_str()); +} + +std::string SetExitList::GetCommandCName() const +{ + return "SCmdExitList"; +} + +RoomCommand SetExitList::GetRoomCommand() const +{ + return RoomCommand::SetExitList; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetExitList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetExitList.h new file mode 100644 index 000000000..9d2791a83 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetExitList.h @@ -0,0 +1,20 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetExitList : public ZRoomCommand +{ +public: + std::vector exits; + + SetExitList(ZFile* nParent); + + void DeclareReferences(const std::string& prefix) override; + void ParseRawDataLate() override; + void DeclareReferencesLate(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetLightList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightList.cpp new file mode 100644 index 000000000..2e023ff20 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightList.cpp @@ -0,0 +1,97 @@ +#include "SetLightList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" + +SetLightList::SetLightList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetLightList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + std::string declarations; + + numLights = cmdArg1; + int32_t currentPtr = segmentOffset; + for (int i = 0; i < this->numLights; i++) + { + LightInfo light(parent->GetRawData(), currentPtr); + + currentPtr += light.GetRawDataSize(); + lights.push_back(light); + } +} + +void SetLightList::DeclareReferences(const std::string& prefix) +{ + if (!lights.empty()) + { + std::string declarations; + + for (size_t i = 0; i < lights.size(); i++) + { + declarations += + StringHelper::Sprintf("\t{ %s },", lights.at(i).GetBodySourceCode().c_str()); + + if (i < lights.size() - 1) + declarations += "\n"; + } + + const auto& light = lights.front(); + + parent->AddDeclarationArray( + segmentOffset, DeclarationAlignment::Align4, lights.size() * light.GetRawDataSize(), + light.GetSourceTypeName(), + StringHelper::Sprintf("%sLightInfo0x%06X", prefix.c_str(), segmentOffset), + lights.size(), declarations); + } +} + +std::string SetLightList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "LightInfo", listName); + return StringHelper::Sprintf("SCENE_CMD_LIGHT_LIST(%i, %s)", numLights, listName.c_str()); +} + +std::string SetLightList::GetCommandCName() const +{ + return "SCmdLightList"; +} + +RoomCommand SetLightList::GetRoomCommand() const +{ + return RoomCommand::SetLightList; +} + +LightInfo::LightInfo(const std::vector& rawData, uint32_t rawDataIndex) +{ + type = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0); + x = BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + y = BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + z = BitConverter::ToInt16BE(rawData, rawDataIndex + 6); + r = BitConverter::ToUInt8BE(rawData, rawDataIndex + 8); + g = BitConverter::ToUInt8BE(rawData, rawDataIndex + 9); + b = BitConverter::ToUInt8BE(rawData, rawDataIndex + 10); + drawGlow = BitConverter::ToUInt8BE(rawData, rawDataIndex + 11); + radius = BitConverter::ToInt16BE(rawData, rawDataIndex + 12); +} + +std::string LightInfo::GetBodySourceCode() const +{ + return StringHelper::Sprintf( + "0x%02X, { %i, %i, %i, { 0x%02X, 0x%02X, 0x%02X }, 0x%02X, 0x%04X }", type, x, y, z, r, g, + b, drawGlow, radius); +} + +std::string LightInfo::GetSourceTypeName() const +{ + return "LightInfo"; +} + +size_t LightInfo::GetRawDataSize() const +{ + return 0x0E; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetLightList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightList.h new file mode 100644 index 000000000..894a21530 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightList.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "ZFile.h" +#include "ZRoom/ZRoom.h" +#include "ZRoom/ZRoomCommand.h" + +class LightInfo +{ +public: + LightInfo(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; + + std::string GetSourceTypeName() const; + size_t GetRawDataSize() const; + +public: + uint8_t type; + int16_t x, y, z; + uint8_t r, g, b; + uint8_t drawGlow; + int16_t radius; +}; + +class SetLightList : public ZRoomCommand +{ +public: + uint8_t numLights; + std::vector lights; + + SetLightList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetLightingSettings.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightingSettings.cpp new file mode 100644 index 000000000..08cd83d14 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightingSettings.cpp @@ -0,0 +1,105 @@ +#include "SetLightingSettings.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetLightingSettings::SetLightingSettings(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetLightingSettings::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + uint8_t numLights = cmdArg1; + + for (int i = 0; i < numLights; i++) + settings.push_back(LightingSettings(parent->GetRawData(), segmentOffset + (i * 22))); +} + +void SetLightingSettings::DeclareReferences(const std::string& prefix) +{ + if (settings.size() > 0) + { + std::string declaration; + + for (size_t i = 0; i < settings.size(); i++) + { + declaration += + StringHelper::Sprintf("\t{ %s },", settings.at(i).GetBodySourceCode().c_str()); + if (i + 1 < settings.size()) + declaration += "\n"; + } + + parent->AddDeclarationArray( + segmentOffset, DeclarationAlignment::Align4, + settings.size() * settings.front().GetRawDataSize(), "LightSettings", + StringHelper::Sprintf("%sLightSettings0x%06X", prefix.c_str(), segmentOffset), + settings.size(), declaration); + } +} + +std::string SetLightingSettings::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "LightSettings", listName); + return StringHelper::Sprintf("SCENE_CMD_ENV_LIGHT_SETTINGS(%i, %s)", settings.size(), + listName.c_str()); +} + +std::string SetLightingSettings::GetCommandCName() const +{ + return "SCmdLightSettingList"; +} + +RoomCommand SetLightingSettings::GetRoomCommand() const +{ + return RoomCommand::SetLightingSettings; +} + +LightingSettings::LightingSettings(const std::vector& rawData, uint32_t rawDataIndex) +{ + ambientClrR = rawData.at(rawDataIndex + 0); + ambientClrG = rawData.at(rawDataIndex + 1); + ambientClrB = rawData.at(rawDataIndex + 2); + + diffuseClrA_R = rawData.at(rawDataIndex + 3); + diffuseClrA_G = rawData.at(rawDataIndex + 4); + diffuseClrA_B = rawData.at(rawDataIndex + 5); + + diffuseDirA_X = rawData.at(rawDataIndex + 6); + diffuseDirA_Y = rawData.at(rawDataIndex + 7); + diffuseDirA_Z = rawData.at(rawDataIndex + 8); + + diffuseClrB_R = rawData.at(rawDataIndex + 9); + diffuseClrB_G = rawData.at(rawDataIndex + 10); + diffuseClrB_B = rawData.at(rawDataIndex + 11); + + diffuseDirB_X = rawData.at(rawDataIndex + 12); + diffuseDirB_Y = rawData.at(rawDataIndex + 13); + diffuseDirB_Z = rawData.at(rawDataIndex + 14); + + fogClrR = rawData.at(rawDataIndex + 15); + fogClrG = rawData.at(rawDataIndex + 16); + fogClrB = rawData.at(rawDataIndex + 17); + + unk = BitConverter::ToInt16BE(rawData, rawDataIndex + 18); + drawDistance = BitConverter::ToInt16BE(rawData, rawDataIndex + 20); +} + +std::string LightingSettings::GetBodySourceCode() const +{ + return StringHelper::Sprintf( + "0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, " + "0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%04X, 0x%04X", + ambientClrR, ambientClrG, ambientClrB, diffuseClrA_R, diffuseClrA_G, diffuseClrA_B, + diffuseDirA_X, diffuseDirA_Y, diffuseDirA_Z, diffuseClrB_R, diffuseClrB_G, diffuseClrB_B, + diffuseDirB_X, diffuseDirB_Y, diffuseDirB_Z, fogClrR, fogClrG, fogClrB, unk, drawDistance); +} + +size_t LightingSettings::GetRawDataSize() const +{ + return 0x16; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetLightingSettings.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightingSettings.h new file mode 100644 index 000000000..29caf4aa6 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetLightingSettings.h @@ -0,0 +1,38 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class LightingSettings +{ +public: + uint8_t ambientClrR, ambientClrG, ambientClrB; + uint8_t diffuseClrA_R, diffuseClrA_G, diffuseClrA_B; + uint8_t diffuseDirA_X, diffuseDirA_Y, diffuseDirA_Z; + uint8_t diffuseClrB_R, diffuseClrB_G, diffuseClrB_B; + uint8_t diffuseDirB_X, diffuseDirB_Y, diffuseDirB_Z; + uint8_t fogClrR, fogClrG, fogClrB; + uint16_t unk; + uint16_t drawDistance; + + LightingSettings(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; + + size_t GetRawDataSize() const; +}; + +class SetLightingSettings : public ZRoomCommand +{ +public: + std::vector settings; + + SetLightingSettings(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetMesh.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetMesh.cpp new file mode 100644 index 000000000..ba0bbe2c2 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetMesh.cpp @@ -0,0 +1,612 @@ +#include "SetMesh.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/Path.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZBackground.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +void GenDListDeclarations(ZRoom* zRoom, ZFile* parent, ZDisplayList* dList); + +SetMesh::SetMesh(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetMesh::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + auto& parentRawData = parent->GetRawData(); + meshHeaderType = parentRawData.at(segmentOffset); + + switch (meshHeaderType) + { + case 0: + polyType = std::make_shared(parent, segmentOffset, zRoom); + break; + + case 1: + polyType = std::make_shared(parent, segmentOffset, zRoom); + break; + + case 2: + polyType = std::make_shared(parent, segmentOffset, zRoom); + break; + + default: + HANDLE_ERROR(WarningType::InvalidExtractedData, + StringHelper::Sprintf("unknown meshHeaderType: %i", meshHeaderType), ""); + } + + polyType->ParseRawData(); +} + +void SetMesh::DeclareReferences(const std::string& prefix) +{ + polyType->SetName(polyType->GetDefaultName(prefix)); + polyType->DeclareReferences(prefix); + polyType->DeclareAndGenerateOutputCode(prefix); +} + +// TODO: is this really needed? +void GenDListDeclarations(ZRoom* zRoom, ZFile* parent, ZDisplayList* dList) +{ + if (dList == nullptr) + return; + + dList->DeclareReferences(zRoom->GetName()); + + for (ZDisplayList* otherDList : dList->otherDLists) + GenDListDeclarations(zRoom, parent, otherDList); +} + +std::string SetMesh::GenDListExterns(ZDisplayList* dList) +{ + std::string sourceOutput; + + sourceOutput += StringHelper::Sprintf("extern Gfx %sDL_%06X[];\n", zRoom->GetName().c_str(), + dList->GetRawDataIndex()); + + for (ZDisplayList* otherDList : dList->otherDLists) + sourceOutput += GenDListExterns(otherDList); + + return sourceOutput; +} + +std::string SetMesh::GetBodySourceCode() const +{ + std::string list; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "", list); + return StringHelper::Sprintf("SCENE_CMD_MESH(%s)", list.c_str()); +} + +std::string SetMesh::GetCommandCName() const +{ + return "SCmdMesh"; +} + +RoomCommand SetMesh::GetRoomCommand() const +{ + return RoomCommand::SetMesh; +} + +PolygonDlist::PolygonDlist(ZFile* nParent) : ZResource(nParent) +{ +} + +void PolygonDlist::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + switch (polyType) + { + case 2: + x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + y = BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + z = BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + unk_06 = BitConverter::ToInt16BE(rawData, rawDataIndex + 6); + + opa = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8); + xlu = BitConverter::ToUInt32BE(rawData, rawDataIndex + 12); + break; + + default: + opa = BitConverter::ToUInt32BE(rawData, rawDataIndex); + xlu = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4); + break; + } +} + +void PolygonDlist::DeclareReferences(const std::string& prefix) +{ + opaDList = MakeDlist(opa, prefix); + xluDList = MakeDlist(xlu, prefix); +} + +std::string PolygonDlist::GetBodySourceCode() const +{ + std::string bodyStr; + std::string opaStr; + std::string xluStr; + Globals::Instance->GetSegmentedPtrName(opa, parent, "Gfx", opaStr); + Globals::Instance->GetSegmentedPtrName(xlu, parent, "Gfx", xluStr); + + if (polyType == 2) + { + bodyStr += StringHelper::Sprintf("{ %6i, %6i, %6i }, %6i, ", x, y, z, unk_06); + } + + bodyStr += StringHelper::Sprintf("%s, %s", opaStr.c_str(), xluStr.c_str()); + + return bodyStr; +} + +void PolygonDlist::GetSourceOutputCode(const std::string& prefix) +{ + std::string bodyStr = StringHelper::Sprintf("\n\t%s\n", GetBodySourceCode().c_str()); + + Declaration* decl = parent->GetDeclaration(rawDataIndex); + + if (decl == nullptr) + DeclareVar(prefix, bodyStr); + else + decl->text = bodyStr; +} + +std::string PolygonDlist::GetSourceTypeName() const +{ + switch (polyType) + { + case 2: + return "PolygonDlist2"; + + default: + return "PolygonDlist"; + } +} + +ZResourceType PolygonDlist::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +size_t PolygonDlist::GetRawDataSize() const +{ + switch (polyType) + { + case 2: + return 0x10; + + default: + return 0x08; + } +} + +void PolygonDlist::SetPolyType(uint8_t nPolyType) +{ + polyType = nPolyType; +} + +ZDisplayList* PolygonDlist::MakeDlist(segptr_t ptr, [[maybe_unused]] const std::string& prefix) +{ + if (ptr == 0) + { + return nullptr; + } + + uint32_t dlistAddress = Seg2Filespace(ptr, parent->baseAddress); + + int32_t dlistLength = ZDisplayList::GetDListLength( + parent->GetRawData(), dlistAddress, + Globals::Instance->game == ZGame::OOT_SW97 ? DListType::F3DEX : DListType::F3DZEX); + ZDisplayList* dlist = new ZDisplayList(parent); + parent->AddResource(dlist); + dlist->ExtractFromBinary(dlistAddress, dlistLength); + dlist->SetName(dlist->GetDefaultName(prefix)); + GenDListDeclarations(zRoom, parent, dlist); + + return dlist; +} + +/* BgImage */ + +BgImage::BgImage(ZFile* nParent) : ZResource(nParent) +{ +} + +BgImage::BgImage(bool nIsSubStruct, const std::string& prefix, uint32_t nRawDataIndex, + ZFile* nParent) + : BgImage(nParent) +{ + rawDataIndex = nRawDataIndex; + parent = nParent; + isSubStruct = nIsSubStruct; + + name = GetDefaultName(prefix); + + ParseRawData(); + sourceBackground = MakeBackground(source, prefix); +} + +void BgImage::ParseRawData() +{ + size_t pad = 0x00; + const auto& rawData = parent->GetRawData(); + if (!isSubStruct) + { + pad = 0x04; + + unk_00 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x00); + id = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x02); + } + source = BitConverter::ToUInt32BE(rawData, rawDataIndex + pad + 0x00); + unk_0C = BitConverter::ToUInt32BE(rawData, rawDataIndex + pad + 0x04); + tlut = BitConverter::ToUInt32BE(rawData, rawDataIndex + pad + 0x08); + width = BitConverter::ToUInt16BE(rawData, rawDataIndex + pad + 0x0C); + height = BitConverter::ToUInt16BE(rawData, rawDataIndex + pad + 0x0E); + fmt = BitConverter::ToUInt8BE(rawData, rawDataIndex + pad + 0x10); + siz = BitConverter::ToUInt8BE(rawData, rawDataIndex + pad + 0x11); + mode0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + pad + 0x12); + tlutCount = BitConverter::ToUInt16BE(rawData, rawDataIndex + pad + 0x14); +} + +ZBackground* BgImage::MakeBackground(segptr_t ptr, const std::string& prefix) +{ + if (ptr == 0) + return nullptr; + + uint32_t backAddress = Seg2Filespace(ptr, parent->baseAddress); + + ZBackground* background = new ZBackground(parent); + background->ExtractFromFile(backAddress); + + std::string defaultName = background->GetDefaultName(prefix); + background->SetName(defaultName); + background->SetOutName(defaultName); + + background->DeclareVar(prefix, ""); + parent->resources.push_back(background); + + return background; +} + +size_t BgImage::GetRawDataSize() const +{ + return 0x1C; +} + +std::string BgImage::GetBodySourceCode() const +{ + std::string bodyStr = " "; + if (!isSubStruct) + { + bodyStr += "{ \n "; + } + + if (!isSubStruct) + { + bodyStr += StringHelper::Sprintf("0x%04X, ", unk_00); + bodyStr += StringHelper::Sprintf("%i, ", id); + bodyStr += "\n "; + bodyStr += " "; + } + + std::string backgroundName; + Globals::Instance->GetSegmentedPtrName(source, parent, "", backgroundName); + bodyStr += StringHelper::Sprintf("%s, ", backgroundName.c_str()); + bodyStr += "\n "; + if (!isSubStruct) + { + bodyStr += " "; + } + + bodyStr += StringHelper::Sprintf("0x%08X, ", unk_0C); + bodyStr += StringHelper::Sprintf("0x%08X, ", tlut); + bodyStr += "\n "; + if (!isSubStruct) + { + bodyStr += " "; + } + + bodyStr += StringHelper::Sprintf("%i, ", width); + bodyStr += StringHelper::Sprintf("%i, ", height); + bodyStr += "\n "; + if (!isSubStruct) + { + bodyStr += " "; + } + + bodyStr += StringHelper::Sprintf("%i, ", fmt); + bodyStr += StringHelper::Sprintf("%i, ", siz); + bodyStr += "\n "; + if (!isSubStruct) + { + bodyStr += " "; + } + + bodyStr += StringHelper::Sprintf("0x%04X, ", mode0); + bodyStr += StringHelper::Sprintf("0x%04X, ", tlutCount); + if (!isSubStruct) + { + bodyStr += " \n }, "; + } + else + { + bodyStr += "\n"; + } + + return bodyStr; +} + +std::string BgImage::GetSourceTypeName() const +{ + return "BgImage"; +} + +ZResourceType BgImage::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +/* PolygonType section */ + +PolygonTypeBase::PolygonTypeBase(ZFile* nParent, uint32_t nRawDataIndex, ZRoom* nRoom) + : ZResource(nParent), zRoom{nRoom} +{ + rawDataIndex = nRawDataIndex; + type = BitConverter::ToUInt8BE(parent->GetRawData(), rawDataIndex); +} + +void PolygonTypeBase::DeclareAndGenerateOutputCode(const std::string& prefix) +{ + std::string bodyStr = GetBodySourceCode(); + + Declaration* decl = parent->GetDeclaration(rawDataIndex); + if (decl == nullptr) + { + DeclareVar(prefix, bodyStr); + } + else + { + decl->text = bodyStr; + } +} + +std::string PolygonTypeBase::GetSourceTypeName() const +{ + switch (type) + { + case 2: + return "PolygonType2"; + + case 1: + return "PolygonType1"; + + default: + return "PolygonType0"; + } +} + +ZResourceType PolygonTypeBase::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +PolygonType1::PolygonType1(ZFile* nParent, uint32_t nRawDataIndex, ZRoom* nRoom) + : PolygonTypeBase(nParent, nRawDataIndex, nRoom), single(nParent) +{ +} + +void PolygonType1::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + format = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x01); + dlist = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x04); + + if (format == 2) + { + count = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x08); + list = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0C); + } + + if (dlist != 0) + { + PolygonDlist polyGfxList(parent); + polyGfxList.zRoom = zRoom; + polyGfxList.SetPolyType(type); + polyGfxList.ExtractFromFile(Seg2Filespace(dlist, parent->baseAddress)); + polyGfxList.DeclareReferences(zRoom->GetName()); + polyDLists.push_back(polyGfxList); + } +} + +void PolygonType1::DeclareReferences(const std::string& prefix) +{ + polyDLists.at(0).GetSourceOutputCode(prefix); + + uint32_t listAddress; + std::string bgImageArrayBody; + switch (format) + { + case 1: + single = BgImage(true, prefix, rawDataIndex + 0x08, parent); + break; + + case 2: + if (list != 0) + { + listAddress = Seg2Filespace(list, parent->baseAddress); + uint32_t auxPtr = listAddress; + for (size_t i = 0; i < count; ++i) + { + BgImage bg(false, prefix, auxPtr, parent); + multiList.push_back(bg); + auxPtr += bg.GetRawDataSize(); + bgImageArrayBody += bg.GetBodySourceCode(); + if (i + 1 < count) + { + bgImageArrayBody += "\n"; + } + } + + Declaration* decl = parent->GetDeclaration(listAddress); + if (decl == nullptr) + { + parent->AddDeclarationArray( + listAddress, DeclarationAlignment::Align4, + count * multiList.at(0).GetRawDataSize(), multiList.at(0).GetSourceTypeName(), + multiList.at(0).GetName().c_str(), count, bgImageArrayBody); + } + } + break; + + default: + HANDLE_ERROR(WarningType::InvalidExtractedData, + StringHelper::Sprintf("unknown format: %i", format), ""); + break; + } +} + +size_t PolygonType1::GetRawDataSize() const +{ + switch (format) + { + case 1: + return 0x20; + + case 2: + return 0x10; + } + return 0x20; +} + +std::string PolygonType1::GetBodySourceCode() const +{ + std::string bodyStr = "\n "; + + bodyStr += "{ "; + bodyStr += StringHelper::Sprintf("%i, %i, ", type, format); + + std::string dlistStr; + Globals::Instance->GetSegmentedPtrName(dlist, parent, "", dlistStr); + + bodyStr += StringHelper::Sprintf("%s, ", dlistStr.c_str()); + bodyStr += "}, \n"; + + std::string listStr = "NULL"; + switch (format) + { + case 1: + bodyStr += single.GetBodySourceCode(); + break; + case 2: + Globals::Instance->GetSegmentedPtrName(list, parent, "BgImage", listStr); + bodyStr += StringHelper::Sprintf(" %i, %s, \n", count, listStr.c_str()); + break; + + default: + break; + } + + return bodyStr; +} + +std::string PolygonType1::GetSourceTypeName() const +{ + switch (format) + { + case 1: + return "MeshHeader1Single"; + + case 2: + return "MeshHeader1Multi"; + } + return "ERROR"; + // return "PolygonType1"; +} + +PolygonType2::PolygonType2(ZFile* nParent, uint32_t nRawDataIndex, ZRoom* nRoom) + : PolygonTypeBase(nParent, nRawDataIndex, nRoom) +{ +} + +void PolygonType2::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + num = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x01); + + start = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x04); + end = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x08); + + uint32_t currentPtr = GETSEGOFFSET(start); + for (size_t i = 0; i < num; i++) + { + PolygonDlist entry(parent); + entry.zRoom = zRoom; + entry.SetPolyType(type); + entry.ExtractFromFile(currentPtr); + entry.DeclareReferences(zRoom->GetName()); + polyDLists.push_back(entry); + currentPtr += entry.GetRawDataSize(); + } +} + +void PolygonType2::DeclareReferences(const std::string& prefix) +{ + if (num > 0) + { + std::string declaration; + + for (size_t i = 0; i < polyDLists.size(); i++) + { + declaration += + StringHelper::Sprintf("\t{ %s },", polyDLists.at(i).GetBodySourceCode().c_str()); + if (i + 1 < polyDLists.size()) + declaration += "\n"; + } + + std::string polyDlistType = polyDLists.at(0).GetSourceTypeName(); + std::string polyDListName; + polyDListName = StringHelper::Sprintf("%s%s_%06X", prefix.c_str(), polyDlistType.c_str(), + GETSEGOFFSET(start)); + + Declaration* decl = parent->AddDeclarationArray( + GETSEGOFFSET(start), DeclarationAlignment::Align4, + polyDLists.size() * polyDLists.at(0).GetRawDataSize(), polyDlistType, polyDListName, + polyDLists.size(), declaration); + decl->forceArrayCnt = true; + } + + parent->AddDeclaration(GETSEGOFFSET(end), DeclarationAlignment::Align4, 4, "s32", + StringHelper::Sprintf("%s_terminatorMaybe_%06X", + parent->GetName().c_str(), GETSEGOFFSET(end)), + "0x01000000"); +} + +std::string PolygonType2::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(start, parent, "", listName); + + std::string body = StringHelper::Sprintf("\n %i, %i,\n", type, polyDLists.size()); + body += StringHelper::Sprintf(" %s,\n", listName.c_str()); + body += + StringHelper::Sprintf(" %s + ARRAY_COUNTU(%s)\n", listName.c_str(), listName.c_str()); + return body; +} + +size_t PolygonType2::GetRawDataSize() const +{ + return 0x0C; +} + +DeclarationAlignment PolygonType2::GetDeclarationAlignment() const +{ + return DeclarationAlignment::Align4; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetMesh.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetMesh.h new file mode 100644 index 000000000..9d9037417 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetMesh.h @@ -0,0 +1,159 @@ +#pragma once + +#include +#include "ZBackground.h" +#include "ZDisplayList.h" +#include "ZRoom/ZRoomCommand.h" + +class PolygonDlist : public ZResource +{ +public: + ZRoom* zRoom; + + uint8_t polyType; + + int16_t x, y, z; // polyType == 2 + int16_t unk_06; // polyType == 2 + + segptr_t opa = 0; // Gfx* + segptr_t xlu = 0; // Gfx* + + ZDisplayList* opaDList = nullptr; // Gfx* + ZDisplayList* xluDList = nullptr; // Gfx* + + PolygonDlist(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + void GetSourceOutputCode(const std::string& prefix) override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; + + void SetPolyType(uint8_t nPolyType); + +protected: + ZDisplayList* MakeDlist(segptr_t ptr, const std::string& prefix); +}; + +class BgImage : public ZResource +{ +public: + uint16_t unk_00; + uint8_t id; + segptr_t source; + uint32_t unk_0C; + uint32_t tlut; + uint16_t width; + uint16_t height; + uint8_t fmt; + uint8_t siz; + uint16_t mode0; + uint16_t tlutCount; + + ZBackground* sourceBackground; + + bool isSubStruct; + + BgImage(ZFile* nParent); + BgImage(bool nIsSubStruct, const std::string& prefix, uint32_t nRawDataIndex, 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: + ZBackground* MakeBackground(segptr_t ptr, const std::string& prefix); +}; + +class PolygonTypeBase : public ZResource +{ +public: + uint8_t type; + std::vector polyDLists; + + PolygonTypeBase(ZFile* nParent, uint32_t nRawDataIndex, ZRoom* nRoom); + + void DeclareAndGenerateOutputCode(const std::string& prefix); + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + +protected: + ZRoom* zRoom; +}; + +class PolygonType1 : public PolygonTypeBase +{ +public: + uint8_t format; + segptr_t dlist; + + // single + BgImage single; + + // multi + uint8_t count; + segptr_t list; // BgImage* + std::vector multiList; + + PolygonType1(ZFile* nParent, uint32_t nRawDataIndex, ZRoom* nRoom); + + 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; +}; + +class PolygonType2 : public PolygonTypeBase +{ +public: + uint8_t num; + segptr_t start; + segptr_t end; + + PolygonType2(ZFile* nParent, uint32_t nRawDataIndex, ZRoom* nRoom); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + size_t GetRawDataSize() const override; + DeclarationAlignment GetDeclarationAlignment() const override; +}; + +class SetMesh : public ZRoomCommand +{ +public: + uint8_t data; + uint8_t meshHeaderType; + std::shared_ptr polyType; + + SetMesh(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; + +private: + std::string GenDListExterns(ZDisplayList* dList); +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapChests.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapChests.cpp new file mode 100644 index 000000000..ec432b7d9 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapChests.cpp @@ -0,0 +1,81 @@ +#include "SetMinimapChests.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetMinimapChests::SetMinimapChests(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetMinimapChests::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + int numChests = cmdArg1; + + int32_t currentPtr = segmentOffset; + + for (int32_t i = 0; i < numChests; i++) + { + MinimapChest chest(parent->GetRawData(), currentPtr); + chests.push_back(chest); + + currentPtr += 10; + } +} + +void SetMinimapChests::DeclareReferences(const std::string& prefix) +{ + std::string declaration; + + size_t index = 0; + for (const auto& chest : chests) + { + declaration += StringHelper::Sprintf(" { %s },", chest.GetBodySourceCode().c_str()); + + if (index < chests.size() - 1) + declaration += "\n"; + + index++; + } + + parent->AddDeclarationArray( + segmentOffset, DeclarationAlignment::Align4, chests.size() * 10, "MinimapChest", + StringHelper::Sprintf("%sMinimapChests0x%06X", prefix.c_str(), segmentOffset), + chests.size(), declaration); +} + +std::string SetMinimapChests::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "MinimapChest", listName); + return StringHelper::Sprintf("SCENE_CMD_MINIMAP_COMPASS_ICON_INFO(0x%02X, %s)", chests.size(), + listName.c_str()); +} + +std::string SetMinimapChests::GetCommandCName() const +{ + return "SCmdMinimapChests"; +} + +RoomCommand SetMinimapChests::GetRoomCommand() const +{ + return RoomCommand::SetMinimapChests; +} + +MinimapChest::MinimapChest(const std::vector& rawData, uint32_t rawDataIndex) + : unk0(BitConverter::ToUInt16BE(rawData, rawDataIndex + 0)), + unk2(BitConverter::ToUInt16BE(rawData, rawDataIndex + 2)), + unk4(BitConverter::ToUInt16BE(rawData, rawDataIndex + 4)), + unk6(BitConverter::ToUInt16BE(rawData, rawDataIndex + 6)), + unk8(BitConverter::ToUInt16BE(rawData, rawDataIndex + 8)) +{ +} + +std::string MinimapChest::GetBodySourceCode() const +{ + return StringHelper::Sprintf("0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X", unk0, unk2, unk4, unk6, + unk8); +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapChests.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapChests.h new file mode 100644 index 000000000..0db09a8a2 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapChests.h @@ -0,0 +1,34 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class MinimapChest +{ +public: + MinimapChest(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; + +protected: + uint16_t unk0; + uint16_t unk2; + uint16_t unk4; + uint16_t unk6; + uint16_t unk8; +}; + +class SetMinimapChests : public ZRoomCommand +{ +public: + std::vector chests; + + SetMinimapChests(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapList.cpp new file mode 100644 index 000000000..be5d8f15d --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapList.cpp @@ -0,0 +1,95 @@ +#include "SetMinimapList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetMinimapList::SetMinimapList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetMinimapList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + listSegmentAddr = BitConverter::ToInt32BE(parent->GetRawData(), segmentOffset); + listSegmentOffset = GETSEGOFFSET(listSegmentAddr); + unk4 = BitConverter::ToInt32BE(parent->GetRawData(), segmentOffset + 4); + + int32_t currentPtr = listSegmentOffset; + + for (int32_t i = 0; i < zRoom->roomCount; i++) + { + MinimapEntry entry(parent->GetRawData(), currentPtr); + minimaps.push_back(entry); + + currentPtr += 10; + } +} + +void SetMinimapList::DeclareReferences(const std::string& prefix) +{ + { + std::string declaration; + + size_t index = 0; + for (const auto& entry : minimaps) + { + declaration += StringHelper::Sprintf(" { %s },", entry.GetBodySourceCode().c_str()); + + if (index < minimaps.size() - 1) + declaration += "\n"; + + index++; + } + + parent->AddDeclarationArray( + listSegmentOffset, DeclarationAlignment::Align4, minimaps.size() * 10, "MinimapEntry", + StringHelper::Sprintf("%sMinimapEntryList0x%06X", prefix.c_str(), listSegmentOffset), + minimaps.size(), declaration); + } + + { + std::string listName; + Globals::Instance->GetSegmentedPtrName(listSegmentAddr, parent, "MinimapEntry", listName); + std::string declaration = StringHelper::Sprintf("\n\t%s, 0x%08X\n", listName.c_str(), unk4); + + parent->AddDeclaration( + segmentOffset, DeclarationAlignment::Align4, 8, "MinimapList", + StringHelper::Sprintf("%sMinimapList0x%06X", prefix.c_str(), segmentOffset), + declaration); + } +} + +std::string SetMinimapList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "MinimapList", listName); + return StringHelper::Sprintf("SCENE_CMD_MINIMAP_INFO(%s)", listName.c_str()); +} + +std::string SetMinimapList::GetCommandCName() const +{ + return "SCmdMinimapSettings"; +} + +RoomCommand SetMinimapList::GetRoomCommand() const +{ + return RoomCommand::SetMinimapList; +} + +MinimapEntry::MinimapEntry(const std::vector& rawData, uint32_t rawDataIndex) + : unk0(BitConverter::ToUInt16BE(rawData, rawDataIndex + 0)), + unk2(BitConverter::ToUInt16BE(rawData, rawDataIndex + 2)), + unk4(BitConverter::ToUInt16BE(rawData, rawDataIndex + 4)), + unk6(BitConverter::ToUInt16BE(rawData, rawDataIndex + 6)), + unk8(BitConverter::ToUInt16BE(rawData, rawDataIndex + 8)) +{ +} + +std::string MinimapEntry::GetBodySourceCode() const +{ + return StringHelper::Sprintf("0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X", unk0, unk2, unk4, unk6, + unk8); +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapList.h new file mode 100644 index 000000000..5b18b3dd7 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetMinimapList.h @@ -0,0 +1,39 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class MinimapEntry +{ +public: + MinimapEntry(const std::vector& rawData, uint32_t rawDataIndex); + + std::string GetBodySourceCode() const; + +protected: + uint16_t unk0; + uint16_t unk2; + uint16_t unk4; + uint16_t unk6; + uint16_t unk8; +}; + +class SetMinimapList : public ZRoomCommand +{ +public: + std::vector minimaps; + + SetMinimapList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; + +private: + segptr_t listSegmentAddr; + uint32_t listSegmentOffset; + uint32_t unk4; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetObjectList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetObjectList.cpp new file mode 100644 index 000000000..fdd41e6cb --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetObjectList.cpp @@ -0,0 +1,66 @@ +#include "SetObjectList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZNames.h" +#include "ZRoom/ZRoom.h" + +SetObjectList::SetObjectList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetObjectList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + uint8_t objectCnt = parent->GetRawData().at(rawDataIndex + 1); + uint32_t currentPtr = segmentOffset; + + for (uint8_t i = 0; i < objectCnt; i++) + { + uint16_t objectIndex = BitConverter::ToInt16BE(parent->GetRawData(), currentPtr); + objects.push_back(objectIndex); + currentPtr += 2; + } +} + +void SetObjectList::DeclareReferences(const std::string& prefix) +{ + if (!objects.empty()) + { + std::string declaration; + + for (size_t i = 0; i < objects.size(); i++) + { + uint16_t objectIndex = objects[i]; + declaration += + StringHelper::Sprintf(" %s,", ZNames::GetObjectName(objectIndex).c_str()); + + if (i < objects.size() - 1) + declaration += "\n"; + } + + parent->AddDeclarationArray( + segmentOffset, DeclarationAlignment::Align4, objects.size() * 2, "s16", + StringHelper::Sprintf("%sObjectList_%06X", prefix.c_str(), segmentOffset), + objects.size(), declaration); + } +} + +std::string SetObjectList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "s16", listName); + return StringHelper::Sprintf("SCENE_CMD_OBJECT_LIST(%i, %s)", objects.size(), listName.c_str()); +} + +std::string SetObjectList::GetCommandCName() const +{ + return "SCmdObjectList"; +} + +RoomCommand SetObjectList::GetRoomCommand() const +{ + return RoomCommand::SetObjectList; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetObjectList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetObjectList.h new file mode 100644 index 000000000..03c159483 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetObjectList.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetObjectList : public ZRoomCommand +{ +public: + std::vector objects; + + SetObjectList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetPathways.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetPathways.cpp new file mode 100644 index 000000000..468aad822 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetPathways.cpp @@ -0,0 +1,65 @@ +#include "SetPathways.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetPathways::SetPathways(ZFile* nParent) : ZRoomCommand(nParent), pathwayList(nParent) +{ +} + +void SetPathways::DeclareReferences([[maybe_unused]] const std::string& prefix) +{ + if (segmentOffset != 0) + { + std::string varName = + StringHelper::Sprintf("%sPathway_%06X", prefix.c_str(), segmentOffset); + parent->AddDeclarationPlaceholder(segmentOffset, varName); + } +} + +void SetPathways::ParseRawDataLate() +{ + if (Globals::Instance->game == ZGame::MM_RETAIL) + { + auto numPaths = zRoom->GetDeclarationSizeFromNeighbor(segmentOffset) / 8; + pathwayList.SetNumPaths(numPaths); + } + + if (Globals::Instance->otrMode) + { + auto zPath = (ZPath*)parent->FindResource(segmentOffset); + + if (zPath != nullptr) + pathwayList = *zPath; + } + + pathwayList.ExtractFromFile(segmentOffset); +} + +void SetPathways::DeclareReferencesLate(const std::string& prefix) +{ + std::string varName = StringHelper::Sprintf("%sPathway_%06X", prefix.c_str(), segmentOffset); + pathwayList.SetName(varName); + pathwayList.DeclareReferences(prefix); + pathwayList.GetSourceOutputCode(prefix); +} + +std::string SetPathways::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "Path", listName); + return StringHelper::Sprintf("SCENE_CMD_PATH_LIST(%s)", listName.c_str()); +} + +std::string SetPathways::GetCommandCName() const +{ + return "SCmdPathList"; +} + +RoomCommand SetPathways::GetRoomCommand() const +{ + return RoomCommand::SetPathways; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetPathways.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetPathways.h new file mode 100644 index 000000000..9abc93d32 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetPathways.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Vec3s.h" +#include "ZPath.h" +#include "ZResource.h" +#include "ZRoom/ZRoomCommand.h" + +class SetPathways : public ZRoomCommand +{ +public: + ZPath pathwayList; + + SetPathways(ZFile* nParent); + + void DeclareReferences(const std::string& prefix) override; + + void ParseRawDataLate() override; + void DeclareReferencesLate(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomBehavior.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomBehavior.cpp new file mode 100644 index 000000000..8c6f4bf51 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomBehavior.cpp @@ -0,0 +1,50 @@ +#include "SetRoomBehavior.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" + +SetRoomBehavior::SetRoomBehavior(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetRoomBehavior::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + gameplayFlags = cmdArg1; + gameplayFlags2 = BitConverter::ToInt32BE(parent->GetRawData(), rawDataIndex + 0x04); + + currRoomUnk2 = gameplayFlags2 & 0xFF; + + currRoomUnk5 = showInvisActors = (gameplayFlags2 >> 8) & 1; + + msgCtxUnk = (gameplayFlags2 >> 10) & 1; + + enablePosLights = (gameplayFlags2 >> 11) & 1; + kankyoContextUnkE2 = (gameplayFlags2 >> 12) & 1; +} + +std::string SetRoomBehavior::GetBodySourceCode() const +{ + if (Globals::Instance->game == ZGame::MM_RETAIL) + { + std::string enableLights = StringHelper::BoolStr(enablePosLights); + return StringHelper::Sprintf("SCENE_CMD_ROOM_BEHAVIOR(0x%02X, 0x%02X, %i, %i, %s, %i)", + gameplayFlags, currRoomUnk2, currRoomUnk5, msgCtxUnk, + enableLights.c_str(), kankyoContextUnkE2); + } + std::string showInvisible = StringHelper::BoolStr(showInvisActors); + std::string disableWarps = StringHelper::BoolStr(msgCtxUnk); + return StringHelper::Sprintf("SCENE_CMD_ROOM_BEHAVIOR(0x%02X, 0x%02X, %s, %s)", gameplayFlags, + currRoomUnk2, showInvisible.c_str(), disableWarps.c_str()); +} + +std::string SetRoomBehavior::GetCommandCName() const +{ + return "SCmdRoomBehavior"; +} + +RoomCommand SetRoomBehavior::GetRoomCommand() const +{ + return RoomCommand::SetRoomBehavior; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomBehavior.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomBehavior.h new file mode 100644 index 000000000..47b772d77 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomBehavior.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetRoomBehavior : public ZRoomCommand +{ +public: + uint8_t gameplayFlags; + uint32_t gameplayFlags2; + + uint8_t currRoomUnk2; + + uint8_t showInvisActors; + uint8_t currRoomUnk5; + + uint8_t msgCtxUnk; + + uint8_t enablePosLights; + uint8_t kankyoContextUnkE2; + + SetRoomBehavior(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomList.cpp new file mode 100644 index 000000000..7027fa1f9 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomList.cpp @@ -0,0 +1,154 @@ +#include "SetRoomList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZRoom.h" + +SetRoomList::SetRoomList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetRoomList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + int numRooms = cmdArg1; + + romfile = new RomFile(parent); + romfile->numRooms = numRooms; + romfile->ExtractFromFile(segmentOffset); + + parent->resources.push_back(romfile); + + zRoom->roomCount = numRooms; +} + +void SetRoomList::DeclareReferences(const std::string& prefix) +{ + ZRoomCommand::DeclareReferences(prefix); + + romfile->DeclareVar(prefix, ""); +} + +std::string SetRoomList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "RomFile", listName); + return StringHelper::Sprintf("SCENE_CMD_ROOM_LIST(%i, %s)", romfile->rooms.size(), + listName.c_str()); +} + +std::string SetRoomList::GetCommandCName() const +{ + return "SCmdRoomList"; +} + +RoomCommand SetRoomList::GetRoomCommand() const +{ + return RoomCommand::SetRoomList; +} + +RomFile::RomFile(ZFile* nParent) : ZResource(nParent) +{ +} + +void RomFile::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + if (reader->Attribute("NumRooms") != nullptr) + { + numRooms = StringHelper::StrToL(std::string(reader->Attribute("NumRooms"))); + } +} + +void RomFile::ParseRawData() +{ + ZResource::ParseRawData(); + + uint32_t currentPtr = rawDataIndex; + + for (int32_t i = 0; i < numRooms; i++) + { + RoomEntry entry(parent->GetRawData(), currentPtr); + rooms.push_back(entry); + + currentPtr += 8; + } +} + +Declaration* RomFile::DeclareVar(const std::string& prefix, const std::string& body) +{ + std::string auxName = name; + if (name == "") + auxName = StringHelper::Sprintf("%sRoomList0x%06X", prefix.c_str(), rawDataIndex); + + return parent->AddDeclarationArray(rawDataIndex, DeclarationAlignment::Align4, + rooms.size() * rooms.at(0).GetRawDataSize(), + GetSourceTypeName(), auxName, rooms.size(), body); +} + +std::string RomFile::GetBodySourceCode() const +{ + std::string declaration; + bool isFirst = true; + + for (ZFile* file : Globals::Instance->files) + { + for (ZResource* res : file->resources) + { + if (res->GetResourceType() == ZResourceType::Room) + { + std::string roomName = res->GetName(); + if (!isFirst) + declaration += "\n"; + + declaration += + StringHelper::Sprintf("\t{ (u32)_%sSegmentRomStart, (u32)_%sSegmentRomEnd },", + roomName.c_str(), roomName.c_str()); + isFirst = false; + } + } + } + + return declaration; +} + +void RomFile::GetSourceOutputCode(const std::string& prefix) +{ + DeclareVar(prefix, GetBodySourceCode()); +} + +std::string RomFile::GetSourceTypeName() const +{ + return "RomFile"; +} + +ZResourceType RomFile::GetResourceType() const +{ + // TODO + return ZResourceType::Error; +} + +size_t RomFile::GetRawDataSize() const +{ + return 8 * rooms.size(); +} + +RoomEntry::RoomEntry(uint32_t nVAS, uint32_t nVAE) +{ + virtualAddressStart = nVAS; + virtualAddressEnd = nVAE; +} + +RoomEntry::RoomEntry(const std::vector& rawData, uint32_t rawDataIndex) + : RoomEntry(BitConverter::ToInt32BE(rawData, rawDataIndex + 0), + BitConverter::ToInt32BE(rawData, rawDataIndex + 4)) +{ +} + +size_t RoomEntry::GetRawDataSize() const +{ + return 0x08; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomList.h new file mode 100644 index 000000000..2ae48b68d --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetRoomList.h @@ -0,0 +1,53 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class RoomEntry +{ +public: + int32_t virtualAddressStart; + int32_t virtualAddressEnd; + + RoomEntry(uint32_t nVAS, uint32_t nVAE); + RoomEntry(const std::vector& rawData, uint32_t rawDataIndex); + + size_t GetRawDataSize() const; +}; + +class RomFile : public ZResource +{ +public: + RomFile(ZFile* nParent); + + void ParseXML(tinyxml2::XMLElement* reader) override; + void ParseRawData() override; + + Declaration* DeclareVar(const std::string& prefix, const std::string& body) override; + std::string GetBodySourceCode() const override; + void GetSourceOutputCode(const std::string& prefix) override; + + std::string GetSourceTypeName() const override; + virtual ZResourceType GetResourceType() const override; + + virtual size_t GetRawDataSize() const override; + + uint8_t numRooms = 0; + std::vector rooms; +}; + +class SetRoomList : public ZRoomCommand +{ +public: + // Borrowed reference. Don't delete. + RomFile* romfile = nullptr; + + SetRoomList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxModifier.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxModifier.cpp new file mode 100644 index 000000000..b16f1355b --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxModifier.cpp @@ -0,0 +1,32 @@ +#include "SetSkyboxModifier.h" + +#include "Utils/StringHelper.h" + +SetSkyboxModifier::SetSkyboxModifier(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetSkyboxModifier::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + disableSky = parent->GetRawData().at(rawDataIndex + 0x04); + disableSunMoon = parent->GetRawData().at(rawDataIndex + 0x05); +} + +std::string SetSkyboxModifier::GetBodySourceCode() const +{ + std::string sky = StringHelper::BoolStr(disableSky); + std::string soonMoon = StringHelper::BoolStr(disableSunMoon); + return StringHelper::Sprintf("SCENE_CMD_SKYBOX_DISABLES(%s, %s)", sky.c_str(), + soonMoon.c_str()); +} + +std::string SetSkyboxModifier::GetCommandCName() const +{ + return "SCmdSkyboxDisables"; +} + +RoomCommand SetSkyboxModifier::GetRoomCommand() const +{ + return RoomCommand::SetSkyboxModifier; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxModifier.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxModifier.h new file mode 100644 index 000000000..65935bf92 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxModifier.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetSkyboxModifier : public ZRoomCommand +{ +public: + uint8_t disableSky; + uint8_t disableSunMoon; + + SetSkyboxModifier(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxSettings.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxSettings.cpp new file mode 100644 index 000000000..d5ae7ef76 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxSettings.cpp @@ -0,0 +1,36 @@ +#include "SetSkyboxSettings.h" +#include "Globals.h" +#include "Utils/StringHelper.h" + +SetSkyboxSettings::SetSkyboxSettings(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetSkyboxSettings::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + unk1 = cmdArg1; + skyboxNumber = parent->GetRawData().at(rawDataIndex + 0x04); + cloudsType = parent->GetRawData().at(rawDataIndex + 0x05); + isIndoors = parent->GetRawData().at(rawDataIndex + 0x06); +} + +std::string SetSkyboxSettings::GetBodySourceCode() const +{ + std::string indoors = StringHelper::BoolStr(isIndoors); + if (Globals::Instance->game == ZGame::MM_RETAIL) + return StringHelper::Sprintf("SCENE_CMD_SKYBOX_SETTINGS(0x%02X, %i, %i, %s)", unk1, + skyboxNumber, cloudsType, indoors.c_str()); + return StringHelper::Sprintf("SCENE_CMD_SKYBOX_SETTINGS(%i, %i, %s)", skyboxNumber, cloudsType, + indoors.c_str()); +} + +std::string SetSkyboxSettings::GetCommandCName() const +{ + return "SCmdSkyboxSettings"; +} + +RoomCommand SetSkyboxSettings::GetRoomCommand() const +{ + return RoomCommand::SetSkyboxSettings; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxSettings.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxSettings.h new file mode 100644 index 000000000..1c7e01ad4 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSkyboxSettings.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetSkyboxSettings : public ZRoomCommand +{ +public: + uint8_t unk1; // (MM Only) + uint8_t skyboxNumber; + uint8_t cloudsType; + uint8_t isIndoors; + + SetSkyboxSettings(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSoundSettings.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetSoundSettings.cpp new file mode 100644 index 000000000..54b91328f --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSoundSettings.cpp @@ -0,0 +1,30 @@ +#include "SetSoundSettings.h" +#include "Utils/StringHelper.h" + +SetSoundSettings::SetSoundSettings(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetSoundSettings::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + reverb = cmdArg1; + nightTimeSFX = parent->GetRawData().at(rawDataIndex + 0x06); + musicSequence = parent->GetRawData().at(rawDataIndex + 0x07); +} + +std::string SetSoundSettings::GetBodySourceCode() const +{ + return StringHelper::Sprintf("SCENE_CMD_SOUND_SETTINGS(%i, %i, %i)", reverb, nightTimeSFX, + musicSequence); +} + +std::string SetSoundSettings::GetCommandCName() const +{ + return "SCmdSoundSettings"; +} + +RoomCommand SetSoundSettings::GetRoomCommand() const +{ + return RoomCommand::SetSoundSettings; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSoundSettings.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetSoundSettings.h new file mode 100644 index 000000000..f378e5e4e --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSoundSettings.h @@ -0,0 +1,20 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetSoundSettings : public ZRoomCommand +{ +public: + uint8_t reverb; + uint8_t nightTimeSFX; + uint8_t musicSequence; + + SetSoundSettings(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSpecialObjects.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetSpecialObjects.cpp new file mode 100644 index 000000000..696a3de01 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSpecialObjects.cpp @@ -0,0 +1,34 @@ +#include "SetSpecialObjects.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZRoom/ZNames.h" + +SetSpecialObjects::SetSpecialObjects(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetSpecialObjects::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + elfMessage = cmdArg1; + globalObject = BitConverter::ToUInt16BE(parent->GetRawData(), rawDataIndex + 0x06); +} + +std::string SetSpecialObjects::GetBodySourceCode() const +{ + std::string objectName = ZNames::GetObjectName(globalObject); + + return StringHelper::Sprintf("SCENE_CMD_SPECIAL_FILES(0x%02X, %s)", elfMessage, + objectName.c_str()); +} + +std::string SetSpecialObjects::GetCommandCName() const +{ + return "SCmdSpecialFiles"; +} + +RoomCommand SetSpecialObjects::GetRoomCommand() const +{ + return RoomCommand::SetSpecialObjects; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetSpecialObjects.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetSpecialObjects.h new file mode 100644 index 000000000..3327d44c3 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetSpecialObjects.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetSpecialObjects : public ZRoomCommand +{ +public: + uint8_t elfMessage; + uint16_t globalObject; + + SetSpecialObjects(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetStartPositionList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetStartPositionList.cpp new file mode 100644 index 000000000..f75b5e0d5 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetStartPositionList.cpp @@ -0,0 +1,66 @@ +#include "SetStartPositionList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZNames.h" +#include "ZRoom/ZRoom.h" + +SetStartPositionList::SetStartPositionList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetStartPositionList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + uint8_t numActors = cmdArg1; + + uint32_t currentPtr = segmentOffset; + + for (int32_t i = 0; i < numActors; i++) + { + actors.push_back(ActorSpawnEntry(parent->GetRawData(), currentPtr)); + currentPtr += 16; + } +} + +void SetStartPositionList::DeclareReferences(const std::string& prefix) +{ + if (!actors.empty()) + { + std::string declaration; + + size_t index = 0; + for (const auto& entry : actors) + { + declaration += StringHelper::Sprintf(" { %s },", entry.GetBodySourceCode().c_str()); + if (index + 1 < actors.size()) + declaration += "\n"; + + index++; + } + + parent->AddDeclarationArray( + segmentOffset, DeclarationAlignment::Align4, actors.size() * 16, "ActorEntry", + StringHelper::Sprintf("%sStartPositionList0x%06X", prefix.c_str(), segmentOffset), + actors.size(), declaration); + } +} + +std::string SetStartPositionList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "ActorEntry", listName); + return StringHelper::Sprintf("SCENE_CMD_SPAWN_LIST(%i, %s)", actors.size(), listName.c_str()); +} + +std::string SetStartPositionList::GetCommandCName() const +{ + return "SCmdSpawnList"; +} + +RoomCommand SetStartPositionList::GetRoomCommand() const +{ + return RoomCommand::SetStartPositionList; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetStartPositionList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetStartPositionList.h new file mode 100644 index 000000000..10075adf3 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetStartPositionList.h @@ -0,0 +1,20 @@ +#pragma once + +#include "SetActorList.h" +#include "ZRoom/ZRoomCommand.h" + +class SetStartPositionList : public ZRoomCommand +{ +public: + std::vector actors; + + SetStartPositionList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetTimeSettings.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetTimeSettings.cpp new file mode 100644 index 000000000..9d4d356df --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetTimeSettings.cpp @@ -0,0 +1,30 @@ +#include "SetTimeSettings.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" + +SetTimeSettings::SetTimeSettings(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetTimeSettings::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + hour = parent->GetRawData().at(rawDataIndex + 4); + min = parent->GetRawData().at(rawDataIndex + 5); + unk = parent->GetRawData().at(rawDataIndex + 6); +} + +std::string SetTimeSettings::GetBodySourceCode() const +{ + return StringHelper::Sprintf("SCENE_CMD_TIME_SETTINGS(%i, %i, %i)", hour, min, unk); +} + +std::string SetTimeSettings::GetCommandCName() const +{ + return "SCmdTimeSettings"; +} + +RoomCommand SetTimeSettings::GetRoomCommand() const +{ + return RoomCommand::SetTimeSettings; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetTimeSettings.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetTimeSettings.h new file mode 100644 index 000000000..7ff2711d4 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetTimeSettings.h @@ -0,0 +1,20 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetTimeSettings : public ZRoomCommand +{ +public: + uint8_t hour; + uint8_t min; + uint8_t unk; + + SetTimeSettings(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetTransitionActorList.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetTransitionActorList.cpp new file mode 100644 index 000000000..a33d1c6e1 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetTransitionActorList.cpp @@ -0,0 +1,91 @@ +#include "SetTransitionActorList.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" +#include "ZRoom/ZNames.h" +#include "ZRoom/ZRoom.h" + +SetTransitionActorList::SetTransitionActorList(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetTransitionActorList::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + int numActors = cmdArg1; + uint32_t currentPtr = segmentOffset; + + for (int32_t i = 0; i < numActors; i++) + { + TransitionActorEntry entry(parent->GetRawData(), currentPtr); + transitionActors.push_back(entry); + + currentPtr += 16; + } +} + +void SetTransitionActorList::DeclareReferences(const std::string& prefix) +{ + std::string declaration; + + size_t index = 0; + for (const auto& entry : transitionActors) + { + declaration += StringHelper::Sprintf(" { %s },", entry.GetBodySourceCode().c_str()); + if (index + 1 < transitionActors.size()) + { + declaration += "\n"; + } + + index++; + } + + parent->AddDeclarationArray( + segmentOffset, DeclarationAlignment::Align4, transitionActors.size() * 16, + "TransitionActorEntry", + StringHelper::Sprintf("%sTransitionActorList_%06X", prefix.c_str(), segmentOffset), + transitionActors.size(), declaration); +} + +std::string SetTransitionActorList::GetBodySourceCode() const +{ + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmdArg2, parent, "TransitionActorEntry", listName); + return StringHelper::Sprintf("SCENE_CMD_TRANSITION_ACTOR_LIST(%i, %s)", transitionActors.size(), + listName.c_str()); +} + +std::string SetTransitionActorList::GetCommandCName() const +{ + return "SCmdTransiActorList"; +} + +RoomCommand SetTransitionActorList::GetRoomCommand() const +{ + return RoomCommand::SetTransitionActorList; +} + +TransitionActorEntry::TransitionActorEntry(const std::vector& rawData, int rawDataIndex) +{ + frontObjectRoom = rawData[rawDataIndex + 0]; + frontTransitionReaction = rawData[rawDataIndex + 1]; + backObjectRoom = rawData[rawDataIndex + 2]; + backTransitionReaction = rawData[rawDataIndex + 3]; + actorNum = BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + posX = BitConverter::ToInt16BE(rawData, rawDataIndex + 6); + posY = BitConverter::ToInt16BE(rawData, rawDataIndex + 8); + posZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 10); + rotY = BitConverter::ToInt16BE(rawData, rawDataIndex + 12); + initVar = BitConverter::ToInt16BE(rawData, rawDataIndex + 14); +} + +std::string TransitionActorEntry::GetBodySourceCode() const +{ + std::string actorStr = ZNames::GetActorName(actorNum); + + return StringHelper::Sprintf("%i, %i, %i, %i, %s, %i, %i, %i, %i, 0x%04X", frontObjectRoom, + frontTransitionReaction, backObjectRoom, backTransitionReaction, + actorStr.c_str(), posX, posY, posZ, rotY, initVar); +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetTransitionActorList.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetTransitionActorList.h new file mode 100644 index 000000000..a5ce2e66f --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetTransitionActorList.h @@ -0,0 +1,36 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class TransitionActorEntry +{ +public: + uint8_t frontObjectRoom; + uint8_t frontTransitionReaction; + uint8_t backObjectRoom; + uint8_t backTransitionReaction; + uint16_t actorNum; + int16_t posX, posY, posZ; + int16_t rotY; + uint16_t initVar; + + TransitionActorEntry(const std::vector& rawData, int rawDataIndex); + + std::string GetBodySourceCode() const; +}; + +class SetTransitionActorList : public ZRoomCommand +{ +public: + std::vector transitionActors; + + SetTransitionActorList(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetWind.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetWind.cpp new file mode 100644 index 000000000..1893b5601 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetWind.cpp @@ -0,0 +1,32 @@ +#include "SetWind.h" +#include "Utils/StringHelper.h" + +SetWind::SetWind(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +void SetWind::ParseRawData() +{ + ZRoomCommand::ParseRawData(); + auto& parentRawData = parent->GetRawData(); + windWest = parentRawData.at(rawDataIndex + 0x04); + windVertical = parentRawData.at(rawDataIndex + 0x05); + windSouth = parentRawData.at(rawDataIndex + 0x06); + clothFlappingStrength = parentRawData.at(rawDataIndex + 0x07); +} + +std::string SetWind::GetBodySourceCode() const +{ + return StringHelper::Sprintf("SCENE_CMD_WIND_SETTINGS(%i, %i, %i, %i)", windWest, windVertical, + windSouth, clothFlappingStrength); +} + +std::string SetWind::GetCommandCName() const +{ + return "SCmdWindSettings"; +} + +RoomCommand SetWind::GetRoomCommand() const +{ + return RoomCommand::SetWind; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetWind.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetWind.h new file mode 100644 index 000000000..05eaafeda --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetWind.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetWind : public ZRoomCommand +{ +public: + uint8_t windWest; + uint8_t windVertical; + uint8_t windSouth; + uint8_t clothFlappingStrength; + + SetWind(ZFile* nParent); + + void ParseRawData() override; + + std::string GetBodySourceCode() const override; + + std::string GetCommandCName() const override; + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetWorldMapVisited.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/SetWorldMapVisited.cpp new file mode 100644 index 000000000..d20e4a3e2 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetWorldMapVisited.cpp @@ -0,0 +1,22 @@ +#include "SetWorldMapVisited.h" + +#include "Utils/StringHelper.h" + +SetWorldMapVisited::SetWorldMapVisited(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +std::string SetWorldMapVisited::GetBodySourceCode() const +{ + return "SCENE_CMD_MISC_SETTINGS()"; +} + +std::string SetWorldMapVisited::GetCommandCName() const +{ + return "SCmdWorldMapVisited"; +} + +RoomCommand SetWorldMapVisited::GetRoomCommand() const +{ + return RoomCommand::SetWorldMapVisited; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/SetWorldMapVisited.h b/ZAPDTR/ZAPD/ZRoom/Commands/SetWorldMapVisited.h new file mode 100644 index 000000000..a7ad93154 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/SetWorldMapVisited.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class SetWorldMapVisited : public ZRoomCommand +{ +public: + SetWorldMapVisited(ZFile* nParent); + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/Unused09.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/Unused09.cpp new file mode 100644 index 000000000..9dfcaa5c2 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/Unused09.cpp @@ -0,0 +1,21 @@ +#include "Unused09.h" +#include "Utils/StringHelper.h" + +Unused09::Unused09(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +std::string Unused09::GetBodySourceCode() const +{ + return "SCENE_CMD_UNK_09()"; +} + +std::string Unused09::GetCommandCName() const +{ + return "SceneCmd"; +} + +RoomCommand Unused09::GetRoomCommand() const +{ + return RoomCommand::Unused09; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/Unused09.h b/ZAPDTR/ZAPD/ZRoom/Commands/Unused09.h new file mode 100644 index 000000000..a38985eea --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/Unused09.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class Unused09 : public ZRoomCommand +{ +public: + Unused09(ZFile* nParent); + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/Unused1D.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/Unused1D.cpp new file mode 100644 index 000000000..b8ea13652 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/Unused1D.cpp @@ -0,0 +1,21 @@ +#include "Unused1D.h" +#include "Utils/StringHelper.h" + +Unused1D::Unused1D(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +std::string Unused1D::GetBodySourceCode() const +{ + return StringHelper::Sprintf("{ %s, 0x00, 0x00 }", GetCommandHex().c_str()); +} + +std::string Unused1D::GetCommandCName() const +{ + return "SceneCmd"; +} + +RoomCommand Unused1D::GetRoomCommand() const +{ + return RoomCommand::Unused1D; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/Unused1D.h b/ZAPDTR/ZAPD/ZRoom/Commands/Unused1D.h new file mode 100644 index 000000000..dea0f98ee --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/Unused1D.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ZRoom/ZRoomCommand.h" + +class Unused1D : public ZRoomCommand +{ +public: + Unused1D(ZFile* nParent); + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; + std::string GetCommandCName() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/ZRoomCommandUnk.cpp b/ZAPDTR/ZAPD/ZRoom/Commands/ZRoomCommandUnk.cpp new file mode 100644 index 000000000..a892086c2 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/ZRoomCommandUnk.cpp @@ -0,0 +1,20 @@ +#include "ZRoomCommandUnk.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZRoom/ZRoom.h" + +ZRoomCommandUnk::ZRoomCommandUnk(ZFile* nParent) : ZRoomCommand(nParent) +{ +} + +std::string ZRoomCommandUnk::GetBodySourceCode() const +{ + return StringHelper::Sprintf("{ %s, 0x%02X, 0x%06X } /* WARNING: " + "UNIMPLEMENTED ROOM COMMAND */", + GetCommandHex().c_str(), cmdArg1, cmdArg2); +} + +RoomCommand ZRoomCommandUnk::GetRoomCommand() const +{ + return RoomCommand::Error; +} diff --git a/ZAPDTR/ZAPD/ZRoom/Commands/ZRoomCommandUnk.h b/ZAPDTR/ZAPD/ZRoom/Commands/ZRoomCommandUnk.h new file mode 100644 index 000000000..e381fe5a5 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/Commands/ZRoomCommandUnk.h @@ -0,0 +1,12 @@ +#pragma once +#include "ZRoom/ZRoomCommand.h" + +class ZRoomCommandUnk : public ZRoomCommand +{ +public: + ZRoomCommandUnk(ZFile* nParent); + + std::string GetBodySourceCode() const override; + + RoomCommand GetRoomCommand() const override; +}; diff --git a/ZAPDTR/ZAPD/ZRoom/ZNames.h b/ZAPDTR/ZAPD/ZRoom/ZNames.h new file mode 100644 index 000000000..94e08de0d --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/ZNames.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include "Globals.h" +#include "Utils/StringHelper.h" + +class ZNames +{ +public: + static std::string GetObjectName(size_t id) + { + if (id >= Globals::Instance->cfg.objectList.size()) + return StringHelper::Sprintf("0x%04X", id); + return Globals::Instance->cfg.objectList.at(id); + } + + static std::string GetActorName(int32_t id) + { + switch (Globals::Instance->game) + { + case ZGame::OOT_RETAIL: + case ZGame::OOT_SW97: + if (id < ZNames::GetNumActors()) + return Globals::Instance->cfg.actorList.at(id); + else + return StringHelper::Sprintf("0x%04X", id); + case ZGame::MM_RETAIL: + { + int32_t flags = id & 0xF000; + id &= 0xFFF; + std::string name; + if (id < ZNames::GetNumActors()) + name = Globals::Instance->cfg.actorList.at(id); + else + name = StringHelper::Sprintf("0x%04X", id); + + if (flags == 0) + return name; + else + return StringHelper::Sprintf("%s | 0x%04X", name.c_str(), flags); + } + } + + return ""; + } + + static int32_t GetNumActors() { return Globals::Instance->cfg.actorList.size(); } +}; diff --git a/ZAPDTR/ZAPD/ZRoom/ZRoom.cpp b/ZAPDTR/ZAPD/ZRoom/ZRoom.cpp new file mode 100644 index 000000000..5831eaa56 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/ZRoom.cpp @@ -0,0 +1,427 @@ +#include "ZRoom.h" +#include +#include +#include +#include +#include + +#include "Commands/EndMarker.h" +#include "Commands/SetActorCutsceneList.h" +#include "Commands/SetActorList.h" +#include "Commands/SetAlternateHeaders.h" +#include "Commands/SetAnimatedMaterialList.h" +#include "Commands/SetCameraSettings.h" +#include "Commands/SetCollisionHeader.h" +#include "Commands/SetCsCamera.h" +#include "Commands/SetCutscenes.h" +#include "Commands/SetEchoSettings.h" +#include "Commands/SetEntranceList.h" +#include "Commands/SetExitList.h" +#include "Commands/SetLightList.h" +#include "Commands/SetLightingSettings.h" +#include "Commands/SetMesh.h" +#include "Commands/SetMinimapChests.h" +#include "Commands/SetMinimapList.h" +#include "Commands/SetObjectList.h" +#include "Commands/SetPathways.h" +#include "Commands/SetRoomBehavior.h" +#include "Commands/SetRoomList.h" +#include "Commands/SetSkyboxModifier.h" +#include "Commands/SetSkyboxSettings.h" +#include "Commands/SetSoundSettings.h" +#include "Commands/SetSpecialObjects.h" +#include "Commands/SetStartPositionList.h" +#include "Commands/SetTimeSettings.h" +#include "Commands/SetTransitionActorList.h" +#include "Commands/SetWind.h" +#include "Commands/SetWorldMapVisited.h" +#include "Commands/Unused09.h" +#include "Commands/Unused1D.h" +#include "Commands/ZRoomCommandUnk.h" +#include "Globals.h" +#include "Utils/File.h" +#include "Utils/Path.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZBlob.h" +#include "ZCutscene.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Room, ZRoom); +REGISTER_ZFILENODE(Scene, ZRoom); +REGISTER_ZFILENODE(AltHeader, ZRoom); + +ZRoom::ZRoom(ZFile* nParent) : ZResource(nParent) +{ + roomCount = -1; + canHaveInner = true; + RegisterOptionalAttribute("HackMode"); +} + +ZRoom::~ZRoom() +{ + for (ZRoomCommand* cmd : commands) + delete cmd; +} + +void ZRoom::ExtractFromXML(tinyxml2::XMLElement* reader, uint32_t nRawDataIndex) +{ + ZResource::ExtractFromXML(reader, nRawDataIndex); + + if (hackMode == "syotes_room") + { + SyotesRoomHack(); + } + else + { + DeclareVar(name, ""); + } +} + +void ZRoom::ExtractFromBinary(uint32_t nRawDataIndex, ZResourceType parentType) +{ + rawDataIndex = nRawDataIndex; + name = GetDefaultName(parent->GetName()); + + zroomType = ZResourceType::AltHeader; + switch (parentType) + { + case ZResourceType::Scene: + case ZResourceType::Room: + case ZResourceType::AltHeader: + parentZroomType = parentType; + break; + + default: + // TODO: error message or something + assert(false); + break; + } + + ParseRawData(); + DeclareVar(name, ""); +} + +void ZRoom::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + // TODO: HACK: remove this specific check when the repo uses the correct HackMode="syotes_room" + if (name == "syotes_room_0") + { + hackMode = "syotes_room"; + } + + std::string nodeName = std::string(reader->Name()); + if (nodeName == "Scene") + { + zroomType = ZResourceType::Scene; + } + else if (nodeName == "Room") + zroomType = ZResourceType::Room; + else if (nodeName == "AltHeader") + zroomType = ZResourceType::AltHeader; + + if (reader->Attribute("HackMode") != nullptr) + { + hackMode = std::string(reader->Attribute("HackMode")); + if (hackMode != "syotes_room") + { + std::string headerError = StringHelper::Sprintf( + "invalid value found for 'HackMode' attribute: '%s'", hackMode.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + headerError, ""); + } + } +} + +void ZRoom::ParseRawData() +{ + if (hackMode == "syotes_room") + return; + + bool shouldContinue = true; + uint32_t currentIndex = 0; + uint32_t currentPtr = rawDataIndex; + + const auto& rawData = parent->GetRawData(); + while (shouldContinue) + { + RoomCommand opcode = static_cast(rawData.at(currentPtr)); + + ZRoomCommand* cmd = nullptr; + + auto start = std::chrono::steady_clock::now(); + + switch (opcode) + { + case RoomCommand::SetStartPositionList: + cmd = new SetStartPositionList(parent); + break; // 0x00 + case RoomCommand::SetActorList: + cmd = new SetActorList(parent); + break; // 0x01 + case RoomCommand::SetCsCamera: + cmd = new SetCsCamera(parent); + break; // 0x02 (MM-ONLY) + case RoomCommand::SetCollisionHeader: + cmd = new SetCollisionHeader(parent); + break; // 0x03 + case RoomCommand::SetRoomList: + cmd = new SetRoomList(parent); + break; // 0x04 + case RoomCommand::SetWind: + cmd = new SetWind(parent); + break; // 0x05 + case RoomCommand::SetEntranceList: + cmd = new SetEntranceList(parent); + break; // 0x06 + case RoomCommand::SetSpecialObjects: + cmd = new SetSpecialObjects(parent); + break; // 0x07 + case RoomCommand::SetRoomBehavior: + cmd = new SetRoomBehavior(parent); + break; // 0x08 + case RoomCommand::Unused09: + cmd = new Unused09(parent); + break; // 0x09 + case RoomCommand::SetMesh: + cmd = new SetMesh(parent); + break; // 0x0A + case RoomCommand::SetObjectList: + cmd = new SetObjectList(parent); + break; // 0x0B + case RoomCommand::SetLightList: + cmd = new SetLightList(parent); + break; // 0x0C (MM-ONLY) + case RoomCommand::SetPathways: + cmd = new SetPathways(parent); + break; // 0x0D + case RoomCommand::SetTransitionActorList: + cmd = new SetTransitionActorList(parent); + break; // 0x0E + case RoomCommand::SetLightingSettings: + cmd = new SetLightingSettings(parent); + break; // 0x0F + case RoomCommand::SetTimeSettings: + cmd = new SetTimeSettings(parent); + break; // 0x10 + case RoomCommand::SetSkyboxSettings: + cmd = new SetSkyboxSettings(parent); + break; // 0x11 + case RoomCommand::SetSkyboxModifier: + cmd = new SetSkyboxModifier(parent); + break; // 0x12 + case RoomCommand::SetExitList: + cmd = new SetExitList(parent); + break; // 0x13 + case RoomCommand::EndMarker: + cmd = new EndMarker(parent); + break; // 0x14 + case RoomCommand::SetSoundSettings: + cmd = new SetSoundSettings(parent); + break; // 0x15 + case RoomCommand::SetEchoSettings: + cmd = new SetEchoSettings(parent); + break; // 0x16 + case RoomCommand::SetCutscenes: + cmd = new SetCutscenes(parent); + break; // 0x17 + case RoomCommand::SetAlternateHeaders: + cmd = new SetAlternateHeaders(parent); + break; // 0x18 + case RoomCommand::SetCameraSettings: + if (Globals::Instance->game == ZGame::MM_RETAIL) + cmd = new SetWorldMapVisited(parent); + else + cmd = new SetCameraSettings(parent); + break; // 0x19 + case RoomCommand::SetAnimatedMaterialList: + cmd = new SetAnimatedMaterialList(parent); + break; // 0x1A (MM-ONLY) + case RoomCommand::SetActorCutsceneList: + cmd = new SetActorCutsceneList(parent); + break; // 0x1B (MM-ONLY) + case RoomCommand::SetMinimapList: + cmd = new SetMinimapList(parent); + break; // 0x1C (MM-ONLY) + case RoomCommand::Unused1D: + cmd = new Unused1D(parent); + break; // 0x1D + case RoomCommand::SetMinimapChests: + cmd = new SetMinimapChests(parent); + break; // 0x1E (MM-ONLY) + default: + cmd = new ZRoomCommandUnk(parent); + } + + cmd->commandSet = rawDataIndex; + cmd->ExtractCommandFromRoom(this, currentPtr); + + if (Globals::Instance->profile) + { + auto end = std::chrono::steady_clock::now(); + int64_t diff = + std::chrono::duration_cast(end - start).count(); + if (diff > 50) + printf("OP: %s, TIME: %" PRIi64 "ms\n", cmd->GetCommandCName().c_str(), diff); + } + + cmd->cmdIndex = currentIndex; + + commands.push_back(cmd); + + if (opcode == RoomCommand::EndMarker) + shouldContinue = false; + + currentPtr += 8; + currentIndex++; + } +} + +void ZRoom::DeclareReferences(const std::string& prefix) +{ + for (auto& cmd : commands) + cmd->DeclareReferences(prefix); +} + +void ZRoom::ParseRawDataLate() +{ + for (auto& cmd : commands) + cmd->ParseRawDataLate(); +} + +void ZRoom::DeclareReferencesLate(const std::string& prefix) +{ + for (auto& cmd : commands) + cmd->DeclareReferencesLate(prefix); +} + +Declaration* ZRoom::DeclareVar(const std::string& prefix, const std::string& body) +{ + std::string auxName = name; + if (auxName == "") + auxName = GetDefaultName(prefix); + if (zroomType == ZResourceType::Scene || zroomType == ZResourceType::Room) + auxName = StringHelper::Sprintf("%sCommands", name.c_str()); + + Declaration* decl = + parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(), + GetSourceTypeName(), auxName, commands.size(), body); + decl->staticConf = staticConf; + return decl; +} + +std::string ZRoom::GetBodySourceCode() const +{ + std::string declaration; + + for (size_t i = 0; i < commands.size(); i++) + { + ZRoomCommand* cmd = commands[i]; + declaration += StringHelper::Sprintf("\t%s,", cmd->GetBodySourceCode().c_str()); + + if (i + 1 < commands.size()) + declaration += "\n"; + } + + return declaration; +} + +std::string ZRoom::GetDefaultName(const std::string& prefix) const +{ + return StringHelper::Sprintf("%sSet_%06X", prefix.c_str(), rawDataIndex); +} + +/* + * There is one room in Ocarina of Time that lacks a header. Room 120, "Syotes", dates + * back to very early in the game's development. Since this room is a special case, + * declare automatically the data its contains whitout the need of a header. + */ +void ZRoom::SyotesRoomHack() +{ + PolygonType2 poly(parent, 0, this); + + poly.ParseRawData(); + poly.DeclareReferences(GetName()); + parent->AddDeclaration(0, poly.GetDeclarationAlignment(), poly.GetRawDataSize(), + poly.GetSourceTypeName(), poly.GetDefaultName(GetName()), + poly.GetBodySourceCode()); +} + +ZRoomCommand* ZRoom::FindCommandOfType(RoomCommand cmdType) +{ + for (size_t i = 0; i < commands.size(); i++) + { + if (commands[i]->GetRoomCommand() == cmdType) + return commands[i]; + } + + return nullptr; +} + +size_t ZRoom::GetDeclarationSizeFromNeighbor(uint32_t declarationAddress) +{ + auto currentDecl = parent->declarations.find(declarationAddress); + if (currentDecl == parent->declarations.end()) + return 0; + + auto nextDecl = currentDecl; + std::advance(nextDecl, 1); + if (nextDecl == parent->declarations.end()) + return parent->GetRawData().size() - currentDecl->first; + + return nextDecl->first - currentDecl->first; +} + +size_t ZRoom::GetCommandSizeFromNeighbor(ZRoomCommand* cmd) +{ + int32_t cmdIndex = -1; + + for (size_t i = 0; i < commands.size(); i++) + { + if (commands[i] == cmd) + { + cmdIndex = i; + break; + } + } + + if (cmdIndex != -1) + { + if (cmdIndex + 1 < (int32_t)commands.size()) + return commands[cmdIndex + 1]->cmdAddress - commands[cmdIndex]->cmdAddress; + else + return parent->GetRawData().size() - commands[cmdIndex]->cmdAddress; + } + + return 0; +} + +void ZRoom::GetSourceOutputCode([[maybe_unused]] const std::string& prefix) +{ + if (hackMode != "syotes_room") + DeclareVar(prefix, GetBodySourceCode()); +} + +size_t ZRoom::GetRawDataSize() const +{ + size_t size = 0; + + for (ZRoomCommand* cmd : commands) + size += cmd->GetRawDataSize(); + + return size; +} + +std::string ZRoom::GetSourceTypeName() const +{ + return "SceneCmd"; +} + +ZResourceType ZRoom::GetResourceType() const +{ + assert(zroomType == ZResourceType::Scene || zroomType == ZResourceType::Room || + zroomType == ZResourceType::AltHeader); + return zroomType; +} diff --git a/ZAPDTR/ZAPD/ZRoom/ZRoom.h b/ZAPDTR/ZAPD/ZRoom/ZRoom.h new file mode 100644 index 000000000..e837ec70a --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/ZRoom.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +#include "ZResource.h" +#include "ZRoomCommand.h" +#include "tinyxml2.h" + +class ZRoom : public ZResource +{ +public: + std::vector commands; + int32_t roomCount; // Only valid for scenes + + std::string hackMode; + + ZResourceType zroomType = ZResourceType::Error; + ZResourceType parentZroomType = ZResourceType::Error; + + ZRoom(ZFile* nParent); + virtual ~ZRoom(); + + void ExtractFromXML(tinyxml2::XMLElement* reader, uint32_t nRawDataIndex) override; + void ExtractFromBinary(uint32_t nRawDataIndex, ZResourceType parentType); + + void ParseXML(tinyxml2::XMLElement* reader) override; + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + void ParseRawDataLate() override; + void DeclareReferencesLate(const std::string& prefix) override; + + Declaration* DeclareVar(const std::string& prefix, const std::string& body) override; + std::string GetBodySourceCode() const override; + + void GetSourceOutputCode(const std::string& prefix) override; + + std::string GetDefaultName(const std::string& prefix) const override; + size_t GetDeclarationSizeFromNeighbor(uint32_t declarationAddress); + size_t GetCommandSizeFromNeighbor(ZRoomCommand* cmd); + ZRoomCommand* FindCommandOfType(RoomCommand cmdType); + + size_t GetRawDataSize() const override; + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + +protected: + void SyotesRoomHack(); +}; diff --git a/ZAPDTR/ZAPD/ZRoom/ZRoomCommand.cpp b/ZAPDTR/ZAPD/ZRoom/ZRoomCommand.cpp new file mode 100644 index 000000000..711c86a40 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/ZRoomCommand.cpp @@ -0,0 +1,58 @@ +#include "ZRoomCommand.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZRoom.h" + +ZRoomCommand::ZRoomCommand(ZFile* nParent) : ZResource(nParent) +{ +} + +void ZRoomCommand::ExtractCommandFromRoom(ZRoom* nZRoom, uint32_t nRawDataIndex) +{ + zRoom = nZRoom; + rawDataIndex = nRawDataIndex; + + ParseRawData(); +} + +void ZRoomCommand::ParseRawData() +{ + auto& parentRawData = parent->GetRawData(); + cmdID = static_cast(parentRawData.at(rawDataIndex)); + cmdAddress = rawDataIndex; + + cmdArg1 = parentRawData.at(rawDataIndex + 1); + cmdArg2 = BitConverter::ToUInt32BE(parentRawData, rawDataIndex + 4); + segmentOffset = Seg2Filespace(cmdArg2, parent->baseAddress); +} + +RoomCommand ZRoomCommand::GetRoomCommand() const +{ + return RoomCommand::Error; +} + +size_t ZRoomCommand::GetRawDataSize() const +{ + return 0x08; +} + +std::string ZRoomCommand::GetSourceTypeName() const +{ + return GetCommandCName(); +} + +ZResourceType ZRoomCommand::GetResourceType() const +{ + return ZResourceType::RoomCommand; +} + +std::string ZRoomCommand::GetCommandCName() const +{ + return "SceneCmd"; +} + +std::string ZRoomCommand::GetCommandHex() const +{ + return StringHelper::Sprintf("0x%02X", static_cast(cmdID)); +} diff --git a/ZAPDTR/ZAPD/ZRoom/ZRoomCommand.h b/ZAPDTR/ZAPD/ZRoom/ZRoomCommand.h new file mode 100644 index 000000000..5e4d0bc54 --- /dev/null +++ b/ZAPDTR/ZAPD/ZRoom/ZRoomCommand.h @@ -0,0 +1,84 @@ +#pragma once + +#include "tinyxml2.h" + +#include +#include + +#include "ZFile.h" +#include "ZResource.h" + +class ZRoom; + +enum class RoomCommand : uint8_t +{ + SetStartPositionList = 0x00, + SetActorList = 0x01, + SetCsCamera = 0x02, + SetCollisionHeader = 0x03, + SetRoomList = 0x04, + SetWind = 0x05, + SetEntranceList = 0x06, + SetSpecialObjects = 0x07, + SetRoomBehavior = 0x08, + Unused09 = 0x09, + SetMesh = 0x0A, + SetObjectList = 0x0B, + SetLightList = 0x0C, + SetPathways = 0x0D, + SetTransitionActorList = 0x0E, + SetLightingSettings = 0x0F, + SetTimeSettings = 0x10, + SetSkyboxSettings = 0x11, + SetSkyboxModifier = 0x12, + SetExitList = 0x13, + EndMarker = 0x14, + SetSoundSettings = 0x15, + SetEchoSettings = 0x16, + SetCutscenes = 0x17, + SetAlternateHeaders = 0x18, + SetCameraSettings = 0x19, + + // MM Commands + SetWorldMapVisited = 0x19, + SetAnimatedMaterialList = 0x1A, + SetActorCutsceneList = 0x1B, + SetMinimapList = 0x1C, + Unused1D = 0x1D, + SetMinimapChests = 0x1E, + + Error = 0xFF +}; + +class ZRoomCommand : public ZResource +{ +public: + int32_t cmdAddress; + uint32_t cmdIndex; + uint32_t commandSet; + RoomCommand cmdID; + offset_t segmentOffset; + + ZRoomCommand(ZFile* nParent); + virtual ~ZRoomCommand() = default; + + virtual void ExtractCommandFromRoom(ZRoom* nZRoom, uint32_t nRawDataIndex); + + void ParseRawData() override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + // Getters/Setters + virtual RoomCommand GetRoomCommand() const = 0; + size_t GetRawDataSize() const final override; + virtual std::string GetCommandCName() const; + + virtual std::string GetCommandHex() const; + +public: + ZRoom* zRoom; + + uint8_t cmdArg1; + segptr_t cmdArg2; +}; diff --git a/ZAPDTR/ZAPD/ZScalar.cpp b/ZAPDTR/ZAPD/ZScalar.cpp new file mode 100644 index 000000000..7e4be4d57 --- /dev/null +++ b/ZAPDTR/ZAPD/ZScalar.cpp @@ -0,0 +1,280 @@ +#include "ZScalar.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/File.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Scalar, ZScalar); + +ZScalar::ZScalar(ZFile* nParent) : ZResource(nParent) +{ + memset(&scalarData, 0, sizeof(ZScalarData)); + scalarType = ZScalarType::ZSCALAR_NONE; + RegisterRequiredAttribute("Type"); +} + +void ZScalar::ExtractFromBinary(uint32_t nRawDataIndex, ZScalarType nScalarType) +{ + rawDataIndex = nRawDataIndex; + scalarType = nScalarType; + + // Don't parse raw data of external files + if (parent->GetMode() == ZFileMode::ExternalFile) + return; + + ParseRawData(); +} + +void ZScalar::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + scalarType = ZScalar::MapOutputTypeToScalarType(registeredAttributes.at("Type").value); +} + +ZScalarType ZScalar::MapOutputTypeToScalarType(const std::string& type) +{ + if (type == "s8") + { + return ZScalarType::ZSCALAR_S8; + } + else if (type == "u8") + { + return ZScalarType::ZSCALAR_U8; + } + else if (type == "x8") + { + return ZScalarType::ZSCALAR_X8; + } + else if (type == "s16") + { + return ZScalarType::ZSCALAR_S16; + } + else if (type == "u16") + { + return ZScalarType::ZSCALAR_U16; + } + else if (type == "x16") + { + return ZScalarType::ZSCALAR_X16; + } + else if (type == "s32") + { + return ZScalarType::ZSCALAR_S32; + } + else if (type == "u32") + { + return ZScalarType::ZSCALAR_U32; + } + else if (type == "x32") + { + return ZScalarType::ZSCALAR_X32; + } + else if (type == "s64") + { + return ZScalarType::ZSCALAR_S64; + } + else if (type == "u64") + { + return ZScalarType::ZSCALAR_U64; + } + else if (type == "x64") + { + return ZScalarType::ZSCALAR_X64; + } + else if (type == "f32") + { + return ZScalarType::ZSCALAR_F32; + } + else if (type == "f64") + { + return ZScalarType::ZSCALAR_F64; + } + + return ZScalarType::ZSCALAR_NONE; +} + +std::string ZScalar::MapScalarTypeToOutputType(const ZScalarType scalarType) +{ + switch (scalarType) + { + case ZScalarType::ZSCALAR_S8: + return "s8"; + case ZScalarType::ZSCALAR_U8: + case ZScalarType::ZSCALAR_X8: + return "u8"; + case ZScalarType::ZSCALAR_S16: + return "s16"; + case ZScalarType::ZSCALAR_U16: + case ZScalarType::ZSCALAR_X16: + return "u16"; + case ZScalarType::ZSCALAR_S32: + return "s32"; + case ZScalarType::ZSCALAR_U32: + case ZScalarType::ZSCALAR_X32: + return "u32"; + case ZScalarType::ZSCALAR_S64: + return "s64"; + case ZScalarType::ZSCALAR_U64: + case ZScalarType::ZSCALAR_X64: + return "u64"; + case ZScalarType::ZSCALAR_F32: + return "f32"; + case ZScalarType::ZSCALAR_F64: + return "f64"; + default: + return ""; + } +} + +size_t ZScalar::MapTypeToSize(const ZScalarType scalarType) +{ + switch (scalarType) + { + case ZScalarType::ZSCALAR_S8: + return sizeof(scalarData.s8); + case ZScalarType::ZSCALAR_U8: + case ZScalarType::ZSCALAR_X8: + return sizeof(scalarData.u8); + case ZScalarType::ZSCALAR_S16: + return sizeof(scalarData.s16); + case ZScalarType::ZSCALAR_U16: + case ZScalarType::ZSCALAR_X16: + return sizeof(scalarData.u16); + case ZScalarType::ZSCALAR_S32: + return sizeof(scalarData.s32); + case ZScalarType::ZSCALAR_U32: + case ZScalarType::ZSCALAR_X32: + return sizeof(scalarData.u32); + case ZScalarType::ZSCALAR_S64: + return sizeof(scalarData.s64); + case ZScalarType::ZSCALAR_U64: + case ZScalarType::ZSCALAR_X64: + return sizeof(scalarData.u64); + case ZScalarType::ZSCALAR_F32: + return sizeof(scalarData.f32); + case ZScalarType::ZSCALAR_F64: + return sizeof(scalarData.f64); + default: + return 0; + } +} + +size_t ZScalar::GetRawDataSize() const +{ + return ZScalar::MapTypeToSize(scalarType); +} + +void ZScalar::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + switch (scalarType) + { + case ZScalarType::ZSCALAR_S8: + scalarData.s8 = BitConverter::ToInt8BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_U8: + case ZScalarType::ZSCALAR_X8: + scalarData.u8 = BitConverter::ToUInt8BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_S16: + scalarData.s16 = BitConverter::ToInt16BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_U16: + case ZScalarType::ZSCALAR_X16: + scalarData.u16 = BitConverter::ToUInt16BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_S32: + scalarData.s32 = BitConverter::ToInt32BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_U32: + case ZScalarType::ZSCALAR_X32: + scalarData.u32 = BitConverter::ToUInt32BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_S64: + scalarData.s64 = BitConverter::ToInt64BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_U64: + case ZScalarType::ZSCALAR_X64: + scalarData.u64 = BitConverter::ToUInt64BE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_F32: + scalarData.f32 = BitConverter::ToFloatBE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_F64: + scalarData.f64 = BitConverter::ToDoubleBE(rawData, rawDataIndex); + break; + case ZScalarType::ZSCALAR_NONE: + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'Type' attribute", "Defaulting to ''"); + break; + } +} + +std::string ZScalar::GetSourceTypeName() const +{ + return ZScalar::MapScalarTypeToOutputType(scalarType); +} + +std::string ZScalar::GetBodySourceCode() const +{ + switch (scalarType) + { + case ZScalarType::ZSCALAR_S8: + return StringHelper::Sprintf("%hhd", scalarData.s8); + case ZScalarType::ZSCALAR_U8: + return StringHelper::Sprintf("%hhu", scalarData.u8); + case ZScalarType::ZSCALAR_X8: + return StringHelper::Sprintf("0x%02X", scalarData.u8); + case ZScalarType::ZSCALAR_S16: + return StringHelper::Sprintf("%hd", scalarData.s16); + case ZScalarType::ZSCALAR_U16: + return StringHelper::Sprintf("%hu", scalarData.u16); + case ZScalarType::ZSCALAR_X16: + return StringHelper::Sprintf("0x%04X", scalarData.u16); + case ZScalarType::ZSCALAR_S32: + return StringHelper::Sprintf("%d", scalarData.s32); + case ZScalarType::ZSCALAR_U32: + return StringHelper::Sprintf("%u", scalarData.u32); + case ZScalarType::ZSCALAR_X32: + return StringHelper::Sprintf("0x%08X", scalarData.u32); + case ZScalarType::ZSCALAR_S64: + return StringHelper::Sprintf("%lld", scalarData.s64); + case ZScalarType::ZSCALAR_U64: + return StringHelper::Sprintf("%llu", scalarData.u64); + case ZScalarType::ZSCALAR_X64: + return StringHelper::Sprintf("0x%016X", scalarData.u64); + case ZScalarType::ZSCALAR_F32: + return StringHelper::Sprintf("%f", scalarData.f32); + case ZScalarType::ZSCALAR_F64: + return StringHelper::Sprintf("%lf", scalarData.f64); + default: + return "SCALAR_ERROR"; + } +} + +ZResourceType ZScalar::GetResourceType() const +{ + return ZResourceType::Scalar; +} + +bool ZScalar::DoesSupportArray() const +{ + return true; +} + +DeclarationAlignment ZScalar::GetDeclarationAlignment() const +{ + switch (scalarType) + { + case ZScalarType::ZSCALAR_S64: + case ZScalarType::ZSCALAR_U64: + case ZScalarType::ZSCALAR_F64: + return DeclarationAlignment::Align8; + default: + return DeclarationAlignment::Align4; + } +} diff --git a/ZAPDTR/ZAPD/ZScalar.h b/ZAPDTR/ZAPD/ZScalar.h new file mode 100644 index 000000000..8f98f261d --- /dev/null +++ b/ZAPDTR/ZAPD/ZScalar.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include "ZResource.h" +#include "tinyxml2.h" + +enum class ZScalarType +{ + ZSCALAR_NONE, + ZSCALAR_S8, + ZSCALAR_U8, + ZSCALAR_X8, + ZSCALAR_S16, + ZSCALAR_U16, + ZSCALAR_X16, + ZSCALAR_S32, + ZSCALAR_U32, + ZSCALAR_X32, + ZSCALAR_S64, + ZSCALAR_U64, + ZSCALAR_X64, + ZSCALAR_F32, + ZSCALAR_F64 +}; + +typedef union ZScalarData +{ + uint8_t u8; + int8_t s8; + uint16_t u16; + int16_t s16; + uint32_t u32; + int32_t s32; + uint64_t u64; + int64_t s64; + float f32; + double f64; +} ZScalarData; + +class ZScalar : public ZResource +{ + friend class ZVector; + +public: + ZScalarData scalarData; + ZScalarType scalarType; + + ZScalar(ZFile* nParent); + + void ExtractFromBinary(uint32_t nRawDataIndex, ZScalarType nScalarType); + + void ParseRawData() override; + void ParseXML(tinyxml2::XMLElement* reader) override; + std::string GetBodySourceCode() const override; + + bool DoesSupportArray() const override; + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; + DeclarationAlignment GetDeclarationAlignment() const override; + + static size_t MapTypeToSize(const ZScalarType scalarType); + static ZScalarType MapOutputTypeToScalarType(const std::string& type); + static std::string MapScalarTypeToOutputType(const ZScalarType scalarType); +}; diff --git a/ZAPDTR/ZAPD/ZSkeleton.cpp b/ZAPDTR/ZAPD/ZSkeleton.cpp new file mode 100644 index 000000000..bab1f9111 --- /dev/null +++ b/ZAPDTR/ZAPD/ZSkeleton.cpp @@ -0,0 +1,287 @@ +#include "ZSkeleton.h" + +#include + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" + +REGISTER_ZFILENODE(Skeleton, ZSkeleton); +REGISTER_ZFILENODE(LimbTable, ZLimbTable); + +ZSkeleton::ZSkeleton(ZFile* nParent) : ZResource(nParent), limbsTable(nParent) +{ + RegisterRequiredAttribute("Type"); + RegisterRequiredAttribute("LimbType"); + + genOTRDef = true; +} + +void ZSkeleton::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + std::string skelTypeXml = registeredAttributes.at("Type").value; + + if (skelTypeXml == "Flex") + type = ZSkeletonType::Flex; + else if (skelTypeXml == "Curve") + type = ZSkeletonType::Curve; + else if (skelTypeXml != "Normal") + { + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'Type' attribute", ""); + } + + std::string limbTypeXml = registeredAttributes.at("LimbType").value; + limbType = ZLimb::GetTypeByAttributeName(limbTypeXml); + if (limbType == ZLimbType::Invalid) + { + HANDLE_ERROR_RESOURCE( + WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("invalid value '%s' found for 'LimbType' attribute", + limbTypeXml.c_str()), + "Defaulting to 'Standard'."); + } +} + +void ZSkeleton::ParseRawData() +{ + ZResource::ParseRawData(); + + const auto& rawData = parent->GetRawData(); + limbsArrayAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex); + limbCount = BitConverter::ToUInt8BE(rawData, rawDataIndex + 4); + + if (type == ZSkeletonType::Flex) + { + dListCount = BitConverter::ToUInt8BE(rawData, rawDataIndex + 8); + } + + if (limbsArrayAddress != 0 && GETSEGNUM(limbsArrayAddress) == parent->segment) + { + uint32_t ptr = Seg2Filespace(limbsArrayAddress, parent->baseAddress); + limbsTable.ExtractFromBinary(ptr, limbType, limbCount); + } +} + +void ZSkeleton::DeclareReferences(const std::string& prefix) +{ + std::string defaultPrefix = name; + if (defaultPrefix == "") + defaultPrefix = prefix; + + ZResource::DeclareReferences(defaultPrefix); + + if (limbsArrayAddress != 0 && GETSEGNUM(limbsArrayAddress) == parent->segment) + { + uint32_t ptr = Seg2Filespace(limbsArrayAddress, parent->baseAddress); + if (!parent->HasDeclaration(ptr)) + { + limbsTable.SetName(StringHelper::Sprintf("%sLimbs", defaultPrefix.c_str())); + limbsTable.DeclareReferences(prefix); + limbsTable.GetSourceOutputCode(prefix); + } + } +} + +std::string ZSkeleton::GetBodySourceCode() const +{ + std::string limbArrayName; + Globals::Instance->GetSegmentedPtrName(limbsArrayAddress, parent, "", limbArrayName); + + switch (type) + { + case ZSkeletonType::Normal: + case ZSkeletonType::Curve: + return StringHelper::Sprintf("\n\t%s, %i\n", limbArrayName.c_str(), limbCount); + + case ZSkeletonType::Flex: + return StringHelper::Sprintf("\n\t{ %s, %i }, %i\n", limbArrayName.c_str(), limbCount, + dListCount); + } + + // TODO: Throw exception? + return "ERROR"; +} + +size_t ZSkeleton::GetRawDataSize() const +{ + switch (type) + { + case ZSkeletonType::Flex: + return 0xC; + case ZSkeletonType::Normal: + case ZSkeletonType::Curve: + default: + return 0x8; + } +} + +std::string ZSkeleton::GetSourceTypeName() const +{ + switch (type) + { + case ZSkeletonType::Normal: + return "SkeletonHeader"; + case ZSkeletonType::Flex: + return "FlexSkeletonHeader"; + case ZSkeletonType::Curve: + return "SkelCurveLimbList"; + } + + return "SkeletonHeader"; +} + +ZResourceType ZSkeleton::GetResourceType() const +{ + return ZResourceType::Skeleton; +} + +DeclarationAlignment ZSkeleton::GetDeclarationAlignment() const +{ + return DeclarationAlignment::Align4; +} + +uint8_t ZSkeleton::GetLimbCount() +{ + return limbCount; +} + +/* ZLimbTable */ + +ZLimbTable::ZLimbTable(ZFile* nParent) : ZResource(nParent) +{ + RegisterRequiredAttribute("LimbType"); + RegisterRequiredAttribute("Count"); +} + +void ZLimbTable::ExtractFromBinary(uint32_t nRawDataIndex, ZLimbType nLimbType, size_t nCount) +{ + rawDataIndex = nRawDataIndex; + limbType = nLimbType; + count = nCount; + + ParseRawData(); +} + +void ZLimbTable::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + std::string limbTypeXml = registeredAttributes.at("LimbType").value; + limbType = ZLimb::GetTypeByAttributeName(limbTypeXml); + if (limbType == ZLimbType::Invalid) + { + HANDLE_WARNING_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'LimbType' attribute.", + "Defaulting to 'Standard'."); + limbType = ZLimbType::Standard; + } + + count = StringHelper::StrToL(registeredAttributes.at("Count").value); +} + +void ZLimbTable::ParseRawData() +{ + ZResource::ParseRawData(); + + const auto& rawData = parent->GetRawData(); + uint32_t ptr = rawDataIndex; + for (size_t i = 0; i < count; i++) + { + limbsAddresses.push_back(BitConverter::ToUInt32BE(rawData, ptr)); + ptr += 4; + } +} + +void ZLimbTable::DeclareReferences(const std::string& prefix) +{ + std::string varPrefix = name; + if (varPrefix == "") + varPrefix = prefix; + + ZResource::DeclareReferences(varPrefix); + + for (size_t i = 0; i < count; i++) + { + segptr_t limbAddress = limbsAddresses[i]; + + if (limbAddress != 0 && GETSEGNUM(limbAddress) == parent->segment) + { + uint32_t limbOffset = Seg2Filespace(limbAddress, parent->baseAddress); + if (!parent->HasDeclaration(limbOffset)) + { + ZLimb* limb = new ZLimb(parent); + limb->ExtractFromBinary(limbOffset, limbType); + limb->SetName(limb->GetDefaultName(varPrefix)); + limb->DeclareVar(varPrefix, ""); + limb->DeclareReferences(varPrefix); + parent->AddResource(limb); + } + } + } +} + +Declaration* ZLimbTable::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(), auxName, limbsAddresses.size(), bodyStr); + decl->staticConf = staticConf; + return decl; +} + +std::string ZLimbTable::GetBodySourceCode() const +{ + std::string body; + + for (size_t i = 0; i < count; i++) + { + std::string limbName; + Globals::Instance->GetSegmentedPtrName(limbsAddresses[i], parent, "", limbName); + body += StringHelper::Sprintf("\t%s,", limbName.c_str()); + + if (i + 1 < count) + body += "\n"; + } + + return body; +} + +std::string ZLimbTable::GetSourceTypeName() const +{ + switch (limbType) + { + case ZLimbType::Standard: + case ZLimbType::LOD: + case ZLimbType::Skin: + return "void*"; + + case ZLimbType::Curve: + case ZLimbType::Legacy: + return StringHelper::Sprintf("%s*", ZLimb::GetSourceTypeName(limbType)); + + case ZLimbType::Invalid: + // TODO: Proper error message or something. + assert("Invalid limb type.\n"); + } + + return "ERROR"; +} + +ZResourceType ZLimbTable::GetResourceType() const +{ + return ZResourceType::LimbTable; +} + +size_t ZLimbTable::GetRawDataSize() const +{ + return 4 * limbsAddresses.size(); +} diff --git a/ZAPDTR/ZAPD/ZSkeleton.h b/ZAPDTR/ZAPD/ZSkeleton.h new file mode 100644 index 000000000..b1598c6d2 --- /dev/null +++ b/ZAPDTR/ZAPD/ZSkeleton.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include + +#include "ZDisplayList.h" +#include "ZFile.h" +#include "ZLimb.h" + +enum class ZSkeletonType +{ + Normal, + Flex, + Curve, +}; + +class ZLimbTable : public ZResource +{ +public: + ZLimbType limbType = ZLimbType::Standard; + size_t count = 0; + std::vector limbsAddresses; + + ZLimbTable(ZFile* nParent); + + void ExtractFromBinary(uint32_t nRawDataIndex, ZLimbType nLimbType, size_t nCount); + + 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; +}; + +class ZSkeleton : public ZResource +{ +public: + ZSkeletonType type = ZSkeletonType::Normal; + ZLimbType limbType = ZLimbType::Standard; + segptr_t limbsArrayAddress; + uint8_t limbCount = 0; + uint8_t dListCount = 0; // FLEX SKELETON ONLY + ZLimbTable limbsTable; + + ZSkeleton(ZFile* nParent); + + 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; + DeclarationAlignment GetDeclarationAlignment() const override; + + uint8_t GetLimbCount(); +}; diff --git a/ZAPDTR/ZAPD/ZString.cpp b/ZAPDTR/ZAPD/ZString.cpp new file mode 100644 index 000000000..965d4d636 --- /dev/null +++ b/ZAPDTR/ZAPD/ZString.cpp @@ -0,0 +1,69 @@ +#include "ZString.h" + +#include "Utils/File.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(String, ZString); + +ZString::ZString(ZFile* nParent) : ZResource(nParent) +{ +} + +void ZString::ParseRawData() +{ + size_t size = 0; + const auto& rawData = parent->GetRawData(); + const auto& rawDataArr = rawData.data(); + size_t rawDataSize = rawData.size(); + for (size_t i = rawDataIndex; i < rawDataSize; ++i) + { + ++size; + if (rawDataArr[i] == '\0') + { + break; + } + } + + auto dataStart = rawData.begin() + rawDataIndex; + strData.assign(dataStart, dataStart + size); +} + +Declaration* ZString::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(), auxName, 0, bodyStr); + decl->staticConf = staticConf; + return decl; +} + +std::string ZString::GetBodySourceCode() const +{ + return StringHelper::Sprintf("\t\"%s\"", strData.data()); +} + +std::string ZString::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix) +{ + return StringHelper::Sprintf("#define %s_macro \"%s\"", name.c_str(), strData.data()); +} + +std::string ZString::GetSourceTypeName() const +{ + return "char"; +} + +ZResourceType ZString::GetResourceType() const +{ + return ZResourceType::String; +} + +size_t ZString::GetRawDataSize() const +{ + return strData.size(); +} diff --git a/ZAPDTR/ZAPD/ZString.h b/ZAPDTR/ZAPD/ZString.h new file mode 100644 index 000000000..6c58ebdcb --- /dev/null +++ b/ZAPDTR/ZAPD/ZString.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ZResource.h" +#include "tinyxml2.h" + +class ZString : public ZResource +{ +public: + ZString(ZFile* nParent); + + void ParseRawData() override; + + Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) 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; + +protected: + std::vector strData; +}; diff --git a/ZAPDTR/ZAPD/ZSymbol.cpp b/ZAPDTR/ZAPD/ZSymbol.cpp new file mode 100644 index 000000000..eabfc2faa --- /dev/null +++ b/ZAPDTR/ZAPD/ZSymbol.cpp @@ -0,0 +1,98 @@ +#include "ZSymbol.h" + +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Symbol, ZSymbol); + +ZSymbol::ZSymbol(ZFile* nParent) : ZResource(nParent) +{ + RegisterOptionalAttribute("Type"); + RegisterOptionalAttribute("TypeSize"); + RegisterOptionalAttribute("Count"); +} + +void ZSymbol::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + std::string typeXml = registeredAttributes.at("Type").value; + + if (typeXml == "") + { + HANDLE_WARNING_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + "missing 'Type' attribute in ", "Defaulting to 'void*'."); + type = "void*"; + } + else + { + type = typeXml; + } + + std::string typeSizeXml = registeredAttributes.at("TypeSize").value; + if (typeSizeXml == "") + { + HANDLE_WARNING_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + "missing 'TypeSize' attribute in ", "Defaulting to '4'."); + typeSize = 4; // Size of a word. + } + else + { + typeSize = StringHelper::StrToL(typeSizeXml, 0); + } + + if (registeredAttributes.at("Count").wasSet) + { + isArray = true; + + std::string countXml = registeredAttributes.at("Count").value; + if (countXml != "") + count = StringHelper::StrToL(countXml, 0); + } + + if (registeredAttributes.at("Static").value == "On") + { + HANDLE_WARNING_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "a cannot be marked as static", + "Disabling static for this resource."); + } + staticConf = StaticConfig::Off; +} + +Declaration* ZSymbol::DeclareVar([[maybe_unused]] const std::string& prefix, + [[maybe_unused]] const std::string& bodyStr) +{ + return nullptr; +} + +size_t ZSymbol::GetRawDataSize() const +{ + if (isArray) + return count * typeSize; + + return typeSize; +} + +std::string ZSymbol::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix) +{ + if (isArray) + { + if (count == 0) + return StringHelper::Sprintf("extern %s %s[];\n", type.c_str(), name.c_str()); + else + return StringHelper::Sprintf("extern %s %s[%i];\n", type.c_str(), name.c_str(), count); + } + + return StringHelper::Sprintf("extern %s %s;\n", type.c_str(), name.c_str()); +} + +std::string ZSymbol::GetSourceTypeName() const +{ + return type; +} + +ZResourceType ZSymbol::GetResourceType() const +{ + return ZResourceType::Symbol; +} diff --git a/ZAPDTR/ZAPD/ZSymbol.h b/ZAPDTR/ZAPD/ZSymbol.h new file mode 100644 index 000000000..7cb14aa9b --- /dev/null +++ b/ZAPDTR/ZAPD/ZSymbol.h @@ -0,0 +1,27 @@ +#pragma once + +#include "ZResource.h" +#include "tinyxml2.h" + +class ZSymbol : public ZResource +{ +protected: + std::string type; + size_t typeSize; + bool isArray = false; + uint32_t count = 0; + +public: + ZSymbol(ZFile* nParent); + + void ParseXML(tinyxml2::XMLElement* reader) override; + + Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override; + + std::string GetSourceOutputHeader(const std::string& prefix) override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; +}; diff --git a/ZAPDTR/ZAPD/ZText.cpp b/ZAPDTR/ZAPD/ZText.cpp new file mode 100644 index 000000000..926761784 --- /dev/null +++ b/ZAPDTR/ZAPD/ZText.cpp @@ -0,0 +1,102 @@ +#include "ZText.h" + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/File.h" +#include "Utils/Path.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Text, ZText); + +ZText::ZText(ZFile* nParent) : ZResource(nParent) +{ + RegisterRequiredAttribute("CodeOffset"); +} + +void ZText::ParseRawData() +{ + ZResource::ParseRawData(); + + const auto& rawData = parent->GetRawData(); + uint32_t currentPtr = StringHelper::StrToL(registeredAttributes.at("CodeOffset").value, 16); + + std::vector codeData = File::ReadAllBytes(Globals::Instance->baseRomPath.string() + "\\code"); + + // In some cases with the multi-process extractor it seems that it fails to read the code file if something else is reading from it at the same time. + while (codeData.size() == 0) + codeData = File::ReadAllBytes(Globals::Instance->baseRomPath.string() + "\\code"); + + while (true) + { + MessageEntry msgEntry; + msgEntry.id = BitConverter::ToInt16BE(codeData, currentPtr + 0); + msgEntry.textboxType = (codeData[currentPtr + 2] & 0xF0) >> 4; + msgEntry.textboxYPos = (codeData[currentPtr + 2] & 0x0F); + msgEntry.segmentId = (codeData[currentPtr + 4]); + msgEntry.msgOffset = BitConverter::ToInt32BE(codeData, currentPtr + 4) & 0x00FFFFFF; + uint32_t msgPtr = msgEntry.msgOffset; + + unsigned char c = rawData[msgPtr]; + unsigned int extra = 0; + bool stop = false; + + while ((c != '\0' && !stop) || extra > 0) + { + msgEntry.msg += c; + msgPtr++; + + if (extra == 0) + { + if (c == 0x05 || c == 0x13 || c == 0x0E || c == 0x0C || c == 0x1E || c == 0x06 || + c == 0x14) + { + extra = 1; + } + else if (c == 0x07) + { + extra = 2; + stop = true; + } + else if (c == 0x12 || c == 0x11) + { + extra = 2; + } + else if (c == 0x15) + { + extra = 3; + } + } + else + { + extra--; + } + + c = rawData[msgPtr]; + } + + messages.push_back(msgEntry); + + if (msgEntry.id == 0xFFFC || msgEntry.id == 0xFFFF) + break; + + currentPtr += 8; + } + + int bp2 = 0; +} + +std::string ZText::GetSourceTypeName() const +{ + return "u8"; +} + +size_t ZText::GetRawDataSize() const +{ + return 1; +} + +ZResourceType ZText::GetResourceType() const +{ + return ZResourceType::Text; +} diff --git a/ZAPDTR/ZAPD/ZText.h b/ZAPDTR/ZAPD/ZText.h new file mode 100644 index 000000000..37b9c66a9 --- /dev/null +++ b/ZAPDTR/ZAPD/ZText.h @@ -0,0 +1,30 @@ +#pragma once + +#include "ZResource.h" +#include "tinyxml2.h" + +class MessageEntry +{ +public: + uint16_t id; + uint8_t textboxType; + uint8_t textboxYPos; + uint32_t segmentId; + uint32_t msgOffset; + std::string msg; +}; + +class ZText : public ZResource +{ +public: + std::vector messages; + + ZText(ZFile* nParent); + + void ParseRawData() override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + + size_t GetRawDataSize() const override; +}; diff --git a/ZAPDTR/ZAPD/ZTexture.cpp b/ZAPDTR/ZAPD/ZTexture.cpp new file mode 100644 index 000000000..46d7ce334 --- /dev/null +++ b/ZAPDTR/ZAPD/ZTexture.cpp @@ -0,0 +1,950 @@ +#include "ZTexture.h" + +#include + +#include "CRC32.h" +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/Directory.h" +#include "Utils/File.h" +#include "Utils/Path.h" +#include "WarningHandler.h" + +REGISTER_ZFILENODE(Texture, ZTexture); + +ZTexture::ZTexture(ZFile* nParent) : ZResource(nParent) +{ + width = 0; + height = 0; + dWordAligned = true; + genOTRDef = true; + + RegisterRequiredAttribute("Width"); + RegisterRequiredAttribute("Height"); + RegisterRequiredAttribute("Format"); + RegisterOptionalAttribute("TlutOffset"); +} + +void ZTexture::ExtractFromBinary(uint32_t nRawDataIndex, int32_t nWidth, int32_t nHeight, + TextureType nType, bool nIsPalette) +{ + width = nWidth; + height = nHeight; + format = nType; + rawDataIndex = nRawDataIndex; + isPalette = nIsPalette; + name = GetDefaultName(parent->GetName()); + outName = name; + + // Don't parse raw data of external files + if (parent->GetMode() == ZFileMode::ExternalFile) + return; + + ParseRawData(); + CalcHash(); +} + +void ZTexture::FromPNG(const fs::path& pngFilePath, TextureType texType) +{ + format = texType; + name = StringHelper::Split(Path::GetFileNameWithoutExtension(pngFilePath.string()), ".")[0]; + PrepareRawDataFromFile(pngFilePath); +} + +void ZTexture::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + std::string widthXml = registeredAttributes.at("Width").value; + std::string heightXml = registeredAttributes.at("Height").value; + + if (!StringHelper::HasOnlyDigits(widthXml)) + { + std::string errorHeader = StringHelper::Sprintf( + "value of 'Width' attribute has non-decimal digits: '%s'", widthXml.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + errorHeader, ""); + } + if (!StringHelper::HasOnlyDigits(heightXml)) + { + std::string errorHeader = StringHelper::Sprintf( + "value of 'Height' attribute has non-decimal digits: '%s'", heightXml.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + errorHeader, ""); + } + + width = StringHelper::StrToL(widthXml); + height = StringHelper::StrToL(heightXml); + + std::string formatStr = registeredAttributes.at("Format").value; + format = GetTextureTypeFromString(formatStr); + + if (format == TextureType::Error) + { + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'Format' attribute", ""); + } + + const auto& tlutOffsetAttr = registeredAttributes.at("TlutOffset"); + if (tlutOffsetAttr.wasSet) + { + switch (format) + { + case TextureType::Palette4bpp: + case TextureType::Palette8bpp: + tlutOffset = StringHelper::StrToL(tlutOffsetAttr.value, 16); + break; + + default: + HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, + "'TlutOffset' declared in non color-indexed (ci4 or ci8) texture", + ""); + break; + } + } +} + +void ZTexture::ParseRawData() +{ + if (rawDataIndex % 8 != 0) + dWordAligned = false; + + switch (format) + { + case TextureType::RGBA16bpp: + PrepareBitmapRGBA16(); + break; + case TextureType::RGBA32bpp: + PrepareBitmapRGBA32(); + break; + case TextureType::Grayscale4bpp: + PrepareBitmapGrayscale4(); + break; + case TextureType::Grayscale8bpp: + PrepareBitmapGrayscale8(); + break; + case TextureType::GrayscaleAlpha4bpp: + PrepareBitmapGrayscaleAlpha4(); + break; + case TextureType::GrayscaleAlpha8bpp: + PrepareBitmapGrayscaleAlpha8(); + break; + case TextureType::GrayscaleAlpha16bpp: + PrepareBitmapGrayscaleAlpha16(); + break; + case TextureType::Palette4bpp: + PrepareBitmapPalette4(); + break; + case TextureType::Palette8bpp: + PrepareBitmapPalette8(); + break; + case TextureType::Error: + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("Invalid texture format", format), ""); + assert(!"TODO"); + break; + } +} + +void ZTexture::PrepareBitmapRGBA16() +{ + textureData.InitEmptyRGBImage(width, height, true); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + int32_t pos = rawDataIndex + ((y * width) + x) * 2; + uint16_t data = parentRawData.at(pos + 1) | (parentRawData.at(pos) << 8); + uint8_t r = (data & 0xF800) >> 11; + uint8_t g = (data & 0x07C0) >> 6; + uint8_t b = (data & 0x003E) >> 1; + uint8_t alpha = data & 0x01; + + textureData.SetRGBPixel(y, x, r * 8, g * 8, b * 8, alpha * 255); + } + } +} + +void ZTexture::PrepareBitmapRGBA32() +{ + textureData.InitEmptyRGBImage(width, height, true); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + size_t pos = rawDataIndex + ((y * width) + x) * 4; + uint8_t r = parentRawData.at(pos + 0); + uint8_t g = parentRawData.at(pos + 1); + uint8_t b = parentRawData.at(pos + 2); + uint8_t alpha = parentRawData.at(pos + 3); + + textureData.SetRGBPixel(y, x, r, g, b, alpha); + } + } +} + +void ZTexture::PrepareBitmapGrayscale4() +{ + textureData.InitEmptyRGBImage(width, height, false); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x += 2) + { + for (uint8_t i = 0; i < 2; i++) + { + size_t pos = rawDataIndex + ((y * width) + x) / 2; + uint8_t grayscale = 0; + + if (i == 0) + grayscale = parentRawData.at(pos) & 0xF0; + else + grayscale = (parentRawData.at(pos) & 0x0F) << 4; + + textureData.SetGrayscalePixel(y, x + i, grayscale); + } + } + } +} + +void ZTexture::PrepareBitmapGrayscale8() +{ + textureData.InitEmptyRGBImage(width, height, false); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + size_t pos = rawDataIndex + ((y * width) + x) * 1; + + textureData.SetGrayscalePixel(y, x, parentRawData.at(pos)); + } + } +} + +void ZTexture::PrepareBitmapGrayscaleAlpha4() +{ + textureData.InitEmptyRGBImage(width, height, true); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x += 2) + { + for (uint16_t i = 0; i < 2; i++) + { + size_t pos = rawDataIndex + ((y * width) + x) / 2; + uint8_t data = 0; + + if (i == 0) + data = (parentRawData.at(pos) & 0xF0) >> 4; + else + data = parentRawData.at(pos) & 0x0F; + + uint8_t grayscale = ((data & 0x0E) >> 1) * 32; + uint8_t alpha = (data & 0x01) * 255; + + textureData.SetGrayscalePixel(y, x + i, grayscale, alpha); + } + } + } +} + +void ZTexture::PrepareBitmapGrayscaleAlpha8() +{ + textureData.InitEmptyRGBImage(width, height, true); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + size_t pos = rawDataIndex + ((y * width) + x) * 1; + uint8_t grayscale = parentRawData.at(pos) & 0xF0; + uint8_t alpha = (parentRawData.at(pos) & 0x0F) << 4; + + textureData.SetGrayscalePixel(y, x, grayscale, alpha); + } + } +} + +void ZTexture::PrepareBitmapGrayscaleAlpha16() +{ + textureData.InitEmptyRGBImage(width, height, true); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + size_t pos = rawDataIndex + ((y * width) + x) * 2; + uint8_t grayscale = parentRawData.at(pos + 0); + uint8_t alpha = parentRawData.at(pos + 1); + + textureData.SetGrayscalePixel(y, x, grayscale, alpha); + } + } +} + +void ZTexture::PrepareBitmapPalette4() +{ + textureData.InitEmptyPaletteImage(width, height); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x += 2) + { + for (uint16_t i = 0; i < 2; i++) + { + size_t pos = rawDataIndex + ((y * width) + x) / 2; + uint8_t paletteIndex = 0; + + if (i == 0) + paletteIndex = (parentRawData.at(pos) & 0xF0) >> 4; + else + paletteIndex = (parentRawData.at(pos) & 0x0F); + + textureData.SetIndexedPixel(y, x + i, paletteIndex, paletteIndex * 16); + } + } + } +} + +void ZTexture::PrepareBitmapPalette8() +{ + textureData.InitEmptyPaletteImage(width, height); + auto parentRawData = parent->GetRawData(); + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + size_t pos = rawDataIndex + ((y * width) + x) * 1; + uint8_t grayscale = parentRawData.at(pos); + + textureData.SetIndexedPixel(y, x, grayscale, grayscale); + } + } +} + +void ZTexture::DeclareReferences([[maybe_unused]] const std::string& prefix) +{ + if (tlutOffset != static_cast(-1)) + { + tlut = parent->GetTextureResource(tlutOffset); + if (tlut == nullptr) + { + int32_t tlutDim = 16; + if (format == TextureType::Palette4bpp) + tlutDim = 4; + + tlut = new ZTexture(parent); + tlut->ExtractFromBinary(tlutOffset, tlutDim, tlutDim, TextureType::RGBA16bpp, true); + parent->AddTextureResource(tlutOffset, tlut); + tlut->DeclareVar(prefix, ""); + } + else + { + tlut->isPalette = true; + } + SetTlut(tlut); + } +} + +void ZTexture::PrepareRawDataFromFile(const fs::path& pngFilePath) +{ + switch (format) + { + case TextureType::RGBA16bpp: + PrepareRawDataRGBA16(pngFilePath); + break; + case TextureType::RGBA32bpp: + PrepareRawDataRGBA32(pngFilePath); + break; + case TextureType::Grayscale4bpp: + PrepareRawDataGrayscale4(pngFilePath); + break; + case TextureType::Grayscale8bpp: + PrepareRawDataGrayscale8(pngFilePath); + break; + case TextureType::GrayscaleAlpha4bpp: + PrepareRawDataGrayscaleAlpha4(pngFilePath); + break; + case TextureType::GrayscaleAlpha8bpp: + PrepareRawDataGrayscaleAlpha8(pngFilePath); + break; + case TextureType::GrayscaleAlpha16bpp: + PrepareRawDataGrayscaleAlpha16(pngFilePath); + break; + case TextureType::Palette4bpp: + PrepareRawDataPalette4(pngFilePath); + break; + case TextureType::Palette8bpp: + PrepareRawDataPalette8(pngFilePath); + break; + case TextureType::Error: + HANDLE_ERROR_PROCESS(WarningType::InvalidPNG, "Input PNG file has invalid format type", ""); + break; + } +} + +void ZTexture::PrepareRawDataRGBA16(const fs::path& rgbaPath) +{ + textureData.ReadPng(rgbaPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x++) + { + size_t pos = ((y * width) + x) * 2; + RGBAPixel pixel = textureData.GetPixel(y, x); + + uint8_t r = pixel.r / 8; + uint8_t g = pixel.g / 8; + uint8_t b = pixel.b / 8; + + uint8_t alphaBit = pixel.a != 0; + + uint16_t data = (r << 11) + (g << 6) + (b << 1) + alphaBit; + + textureDataRaw[pos + 0] = (data & 0xFF00) >> 8; + textureDataRaw[pos + 1] = (data & 0x00FF); + } + } +} + +void ZTexture::PrepareRawDataRGBA32(const fs::path& rgbaPath) +{ + textureData.ReadPng(rgbaPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x++) + { + size_t pos = ((y * width) + x) * 4; + RGBAPixel pixel = textureData.GetPixel(y, x); + + textureDataRaw[pos + 0] = pixel.r; + textureDataRaw[pos + 1] = pixel.g; + textureDataRaw[pos + 2] = pixel.b; + textureDataRaw[pos + 3] = pixel.a; + } + } +} + +void ZTexture::PrepareRawDataGrayscale4(const fs::path& grayPath) +{ + textureData.ReadPng(grayPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x += 2) + { + size_t pos = ((y * width) + x) / 2; + uint8_t r1 = textureData.GetPixel(y, x).r; + uint8_t r2 = textureData.GetPixel(y, x + 1).r; + + textureDataRaw[pos] = (uint8_t)(((r1 / 16) << 4) + (r2 / 16)); + } + } +} + +void ZTexture::PrepareRawDataGrayscale8(const fs::path& grayPath) +{ + textureData.ReadPng(grayPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x++) + { + size_t pos = (y * width) + x; + RGBAPixel pixel = textureData.GetPixel(y, x); + textureDataRaw[pos] = pixel.r; + } + } +} + +void ZTexture::PrepareRawDataGrayscaleAlpha4(const fs::path& grayAlphaPath) +{ + textureData.ReadPng(grayAlphaPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x += 2) + { + size_t pos = ((y * width) + x) / 2; + uint8_t data = 0; + + for (uint16_t i = 0; i < 2; i++) + { + RGBAPixel pixel = textureData.GetPixel(y, x + i); + uint8_t cR = pixel.r; + uint8_t alphaBit = pixel.a != 0; + + if (i == 0) + data |= (((cR / 32) << 1) + alphaBit) << 4; + else + data |= ((cR / 32) << 1) + alphaBit; + } + + textureDataRaw[pos] = data; + } + } +} + +void ZTexture::PrepareRawDataGrayscaleAlpha8(const fs::path& grayAlphaPath) +{ + textureData.ReadPng(grayAlphaPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x++) + { + size_t pos = ((y * width) + x) * 1; + RGBAPixel pixel = textureData.GetPixel(y, x); + + uint8_t r = pixel.r; + uint8_t a = pixel.a; + + textureDataRaw[pos] = ((r / 16) << 4) + (a / 16); + } + } +} + +void ZTexture::PrepareRawDataGrayscaleAlpha16(const fs::path& grayAlphaPath) +{ + textureData.ReadPng(grayAlphaPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x++) + { + size_t pos = ((y * width) + x) * 2; + RGBAPixel pixel = textureData.GetPixel(y, x); + + uint8_t cR = pixel.r; + uint8_t aR = pixel.a; + + textureDataRaw[pos + 0] = cR; + textureDataRaw[pos + 1] = aR; + } + } +} + +void ZTexture::PrepareRawDataPalette4(const fs::path& palPath) +{ + textureData.ReadPng(palPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x += 2) + { + size_t pos = ((y * width) + x) / 2; + + uint8_t cR1 = textureData.GetIndexedPixel(y, x); + uint8_t cR2 = textureData.GetIndexedPixel(y, x + 1); + + textureDataRaw[pos] = (cR1 << 4) | (cR2); + } + } +} + +void ZTexture::PrepareRawDataPalette8(const fs::path& palPath) +{ + textureData.ReadPng(palPath); + + width = textureData.GetWidth(); + height = textureData.GetHeight(); + + textureDataRaw.clear(); + textureDataRaw.resize(GetRawDataSize()); + for (uint16_t y = 0; y < height; y++) + { + for (uint16_t x = 0; x < width; x++) + { + size_t pos = ((y * width) + x); + uint8_t cR = textureData.GetIndexedPixel(y, x); + + textureDataRaw[pos] = cR; + } + } +} + +float ZTexture::GetPixelMultiplyer() const +{ + switch (format) + { + case TextureType::Grayscale4bpp: + case TextureType::GrayscaleAlpha4bpp: + case TextureType::Palette4bpp: + return 0.5f; + case TextureType::Grayscale8bpp: + case TextureType::GrayscaleAlpha8bpp: + case TextureType::Palette8bpp: + return 1; + case TextureType::GrayscaleAlpha16bpp: + case TextureType::RGBA16bpp: + return 2; + case TextureType::RGBA32bpp: + return 4; + default: + return -1; + } +} + +size_t ZTexture::GetRawDataSize() const +{ + return (width * height * GetPixelMultiplyer()); +} + +std::string ZTexture::GetIMFmtFromType() +{ + switch (format) + { + case TextureType::RGBA32bpp: + case TextureType::RGBA16bpp: + return "G_IM_FMT_RGBA"; + case TextureType::Grayscale4bpp: + case TextureType::Grayscale8bpp: + return "G_IM_FMT_I"; + case TextureType::Palette4bpp: + case TextureType::Palette8bpp: + return "G_IM_FMT_CI"; + case TextureType::GrayscaleAlpha4bpp: + case TextureType::GrayscaleAlpha8bpp: + case TextureType::GrayscaleAlpha16bpp: + return "G_IM_FMT_IA"; + default: + return "ERROR"; + } +} + +std::string ZTexture::GetIMSizFromType() +{ + switch (format) + { + case TextureType::Grayscale4bpp: + case TextureType::Palette4bpp: + case TextureType::GrayscaleAlpha4bpp: + return "G_IM_SIZ_4b"; + case TextureType::Palette8bpp: + case TextureType::Grayscale8bpp: + return "G_IM_SIZ_8b"; + case TextureType::GrayscaleAlpha16bpp: + case TextureType::RGBA16bpp: + return "G_IM_SIZ_16b"; + case TextureType::RGBA32bpp: + return "G_IM_SIZ_32b"; + default: + return "ERROR"; + } +} + +std::string ZTexture::GetDefaultName(const std::string& prefix) const +{ + const char* suffix = "Tex"; + if (isPalette) + suffix = "TLUT"; + return StringHelper::Sprintf("%s%s_%06X", prefix.c_str(), suffix, rawDataIndex); +} + +uint32_t ZTexture::GetWidth() const +{ + return width; +} + +uint32_t ZTexture::GetHeight() const +{ + return height; +} + +void ZTexture::SetDimensions(uint32_t nWidth, uint32_t nHeight) +{ + width = nWidth; + height = nHeight; + ParseRawData(); +} + +TextureType ZTexture::GetTextureType() const +{ + return format; +} + + +void ZTexture::Save(const fs::path& outFolder) +{ + // Optionally generate text file containing CRC information. This is going to be a one time + // process for generating the Texture Pool XML. + if (Globals::Instance->outputCrc) + { + File::WriteAllText((Globals::Instance->outputPath / (outName + ".txt")).string(), + StringHelper::Sprintf("%08lX", hash)); + } + + // Do not save png files if we're making an OTR file. They're not needed... + if (Globals::Instance->otrMode) + return; + + auto outPath = GetPoolOutPath(outFolder); + + if (!Directory::Exists(outPath.string())) + Directory::CreateDirectory(outPath.string()); + +//#ifdef _MSC_VER + fs::path outFileName; +//#else + //std::filesystem::__cxx11::path outFileName; +//#endif + + if (!dWordAligned) + outFileName = outPath / (outName + ".u32" + "." + GetExternalExtension() + ".png"); + else + outFileName = outPath / (outName + +"." + GetExternalExtension() + ".png"); + +#ifdef TEXTURE_DEBUG + printf("Saving PNG: %s\n", outFileName.c_str()); + printf("\t Var name: %s\n", name.c_str()); + if (tlut != nullptr) + printf("\t TLUT name: %s\n", tlut->name.c_str()); +#endif + + textureData.WritePng(outFileName); + +#ifdef TEXTURE_DEBUG + printf("\n"); +#endif +} + +Declaration* ZTexture::DeclareVar(const std::string& prefix, + [[maybe_unused]] const std::string& bodyStr) +{ + std::string auxName = name; + std::string auxOutName = outName; + std::string incStr; + + //if (Globals::Instance->otrMode) + //return nullptr; + + if (auxName == "") + auxName = GetDefaultName(prefix); + + if (auxOutName == "") + auxOutName = GetDefaultName(prefix); + + auto filepath = Globals::Instance->outputPath / fs::path(auxOutName).stem(); + + if (dWordAligned) + incStr = + StringHelper::Sprintf("%s.%s.inc.c", filepath.c_str(), GetExternalExtension().c_str()); + else + incStr = StringHelper::Sprintf("%s.u32.%s.inc.c", filepath.c_str(), + GetExternalExtension().c_str()); + + if (!Globals::Instance->cfg.texturePool.empty()) + { + CalcHash(); + + // TEXTURE POOL CHECK + const auto& poolEntry = Globals::Instance->cfg.texturePool.find(hash); + if (poolEntry != Globals::Instance->cfg.texturePool.end()) + { + if (dWordAligned) + incStr = StringHelper::Sprintf("%s.%s.inc.c", poolEntry->second.path.c_str(), + GetExternalExtension().c_str()); + else + incStr = + StringHelper::Sprintf("%s.u32.%s.inc.c", poolEntry->second.path.c_str(), + GetExternalExtension().c_str()); + } + } + size_t texSizeDivisor = (dWordAligned) ? 8 : 4; + + Declaration* decl = parent->AddDeclarationIncludeArray(rawDataIndex, incStr, GetRawDataSize(), + GetSourceTypeName(), auxName, + GetRawDataSize() / texSizeDivisor); + decl->staticConf = staticConf; + return decl; +} + +std::string ZTexture::GetBodySourceCode() const +{ + std::string sourceOutput; + size_t texSizeInc = (dWordAligned) ? 8 : 4; + for (size_t i = 0; i < textureDataRaw.size(); i += texSizeInc) + { + if (i % 32 == 0) + sourceOutput += " "; + if (dWordAligned) + sourceOutput += + StringHelper::Sprintf("0x%016llX, ", BitConverter::ToUInt64BE(textureDataRaw, i)); + else + sourceOutput += + StringHelper::Sprintf("0x%08llX, ", BitConverter::ToUInt32BE(textureDataRaw, i)); + if (i % 32 == 24) + sourceOutput += StringHelper::Sprintf(" // 0x%06X \n", rawDataIndex + ((i / 32) * 32)); + } + + // 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; +} + +bool ZTexture::IsExternalResource() const +{ + return true; +} + +ZResourceType ZTexture::GetResourceType() const +{ + return ZResourceType::Texture; +} + +std::string ZTexture::GetSourceTypeName() const +{ + return dWordAligned ? "u64" : "u32"; +} + +void ZTexture::CalcHash() +{ + auto parentRawData = parent->GetRawData(); + hash = CRC32B(parentRawData.data() + rawDataIndex, GetRawDataSize()); +} + +std::string ZTexture::GetExternalExtension() const +{ + switch (format) + { + case TextureType::RGBA32bpp: + return "rgba32"; + case TextureType::RGBA16bpp: + return "rgba16"; + case TextureType::Grayscale4bpp: + return "i4"; + case TextureType::Grayscale8bpp: + return "i8"; + case TextureType::GrayscaleAlpha4bpp: + return "ia4"; + case TextureType::GrayscaleAlpha8bpp: + return "ia8"; + case TextureType::GrayscaleAlpha16bpp: + return "ia16"; + case TextureType::Palette4bpp: + return "ci4"; + case TextureType::Palette8bpp: + return "ci8"; + default: + return "ERROR"; + } +} + +fs::path ZTexture::GetPoolOutPath(const fs::path& defaultValue) +{ + if (Globals::Instance->cfg.texturePool.find(hash) != Globals::Instance->cfg.texturePool.end()) + return Path::GetDirectoryName(Globals::Instance->cfg.texturePool[hash].path.string()); + + return defaultValue; +} + +TextureType ZTexture::GetTextureTypeFromString(const std::string& str) +{ + TextureType texType = TextureType::Error; + + if (str == "rgba32") + texType = TextureType::RGBA32bpp; + else if (str == "rgba16") + texType = TextureType::RGBA16bpp; + else if (str == "rgb5a1") + { + texType = TextureType::RGBA16bpp; + HANDLE_WARNING(WarningType::Deprecated, + "the texture format 'rgb5a1' is currently deprecated", + "It will be removed in a future version. Use the format 'rgba16' instead."); + } + else if (str == "i4") + texType = TextureType::Grayscale4bpp; + else if (str == "i8") + texType = TextureType::Grayscale8bpp; + else if (str == "ia4") + texType = TextureType::GrayscaleAlpha4bpp; + else if (str == "ia8") + texType = TextureType::GrayscaleAlpha8bpp; + else if (str == "ia16") + texType = TextureType::GrayscaleAlpha16bpp; + else if (str == "ci4") + texType = TextureType::Palette4bpp; + else if (str == "ci8") + texType = TextureType::Palette8bpp; + else + // TODO: handle this case in a more coherent way + HANDLE_WARNING(WarningType::InvalidAttributeValue, + "invalid value found for 'Type' attribute", "Defaulting to ''."); + return texType; +} + +bool ZTexture::IsColorIndexed() const +{ + switch (format) + { + case TextureType::Palette4bpp: + case TextureType::Palette8bpp: + return true; + + default: + return false; + } +} + +void ZTexture::SetTlut(ZTexture* nTlut) +{ + assert(IsColorIndexed()); + assert(nTlut->isPalette); + tlut = nTlut; + + textureData.SetPalette(tlut->textureData); +} + +bool ZTexture::HasTlut() const +{ + return tlut != nullptr; +} diff --git a/ZAPDTR/ZAPD/ZTexture.h b/ZAPDTR/ZAPD/ZTexture.h new file mode 100644 index 000000000..29c3fbc0a --- /dev/null +++ b/ZAPDTR/ZAPD/ZTexture.h @@ -0,0 +1,91 @@ +#pragma once + +#include "ImageBackend.h" +#include "ZResource.h" +#include "tinyxml2.h" + +enum class TextureType +{ + Error, + RGBA32bpp, + RGBA16bpp, + Palette4bpp, + Palette8bpp, + Grayscale4bpp, + Grayscale8bpp, + GrayscaleAlpha4bpp, + GrayscaleAlpha8bpp, + GrayscaleAlpha16bpp, +}; + +class ZTexture : public ZResource +{ +protected: + TextureType format = TextureType::Error; + uint32_t width, height; + + ImageBackend textureData; + std::vector textureDataRaw; // When reading from a PNG file. + uint32_t tlutOffset = static_cast(-1); + ZTexture* tlut = nullptr; + + void PrepareBitmapRGBA16(); + void PrepareBitmapRGBA32(); + void PrepareBitmapGrayscale8(); + void PrepareBitmapGrayscaleAlpha8(); + void PrepareBitmapGrayscale4(); + void PrepareBitmapGrayscaleAlpha4(); + void PrepareBitmapGrayscaleAlpha16(); + void PrepareBitmapPalette4(); + void PrepareBitmapPalette8(); + + void PrepareRawDataFromFile(const fs::path& inFolder); + void PrepareRawDataRGBA16(const fs::path& rgbaPath); + void PrepareRawDataRGBA32(const fs::path& rgbaPath); + void PrepareRawDataGrayscale4(const fs::path& grayPath); + void PrepareRawDataGrayscale8(const fs::path& grayPath); + void PrepareRawDataGrayscaleAlpha4(const fs::path& grayAlphaPath); + void PrepareRawDataGrayscaleAlpha8(const fs::path& grayAlphaPath); + void PrepareRawDataGrayscaleAlpha16(const fs::path& grayAlphaPath); + void PrepareRawDataPalette4(const fs::path& palPath); + void PrepareRawDataPalette8(const fs::path& palPath); + +public: + ZTexture(ZFile* nParent); + + bool isPalette = false; + bool dWordAligned = true; + + void ExtractFromBinary(uint32_t nRawDataIndex, int32_t nWidth, int32_t nHeight, + TextureType nType, bool nIsPalette); + void FromPNG(const fs::path& pngFilePath, TextureType texType); + static TextureType GetTextureTypeFromString(const std::string& str); + + 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; + void CalcHash() 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; + std::string GetIMFmtFromType(); + std::string GetIMSizFromType(); + std::string GetDefaultName(const std::string& prefix) const override; + uint32_t GetWidth() const; + uint32_t GetHeight() const; + void SetDimensions(uint32_t nWidth, uint32_t nHeight); + float GetPixelMultiplyer() const; + TextureType GetTextureType() const; + fs::path GetPoolOutPath(const fs::path& defaultValue); + bool IsColorIndexed() const; + void SetTlut(ZTexture* nTlut); + bool HasTlut() const; +}; diff --git a/ZAPDTR/ZAPD/ZTextureAnimation.cpp b/ZAPDTR/ZAPD/ZTextureAnimation.cpp new file mode 100644 index 000000000..698054fa8 --- /dev/null +++ b/ZAPDTR/ZAPD/ZTextureAnimation.cpp @@ -0,0 +1,664 @@ +/** + * File: ZTextureAnimation.cpp + * ZResources defined: ZTextureAnimation, ZTextureAnimationParams (XML declaration not supported for + * the latter) + * Purpose: extracting texture animating structures from asset files + * Note: data type is exclusive to Majora's Mask + * + * Structure of data: + * A texture animation consists of a main array of data of the form + * `SS 00 00 0T PPPPPPPP`, + * where `S` is the segment that the functionality is sent to (and read by DLists), `T` is the + * "type" (see below), and `P` is a pointer to the type's subsidiary information, which is + * invariably just above this main array. Details of this subsidiary data are given below. + * + * Segment + * === + * The segment starts at 1 and is incremented in each entry; the final one is negated, which is used + * as the indication to stop reading. The actual segment the game will use to draw is S + 7. + * + * Types + * === + * There are 7 values that `T` can take: + * `0`: A single texture scroll (Implemented by Gfx_TexScroll): subsidiary params are given as + * an array with one entry, a struct `XX YY WW HH` containing xStep, yStep, width, height + * (all u8). + * + * `1`: A dual texture scroll (Implementated by Gfx_TwoTexScroll): same as type `0`, but with + * two entries in the params array. + * + * `2`: Color changing: Changes the primColor (with a LOD factor) and envColor + * `KKKK LLLL PPPPPPPP QQQQQQQQ RRRRRRRR` + * - `K` (u16) is the total length of the animation (and in this case, the total number of + * colors) + * - `L` (u16) is seemingly always 0 for this type, and not used in the code + * - `P` segmented pointer to array of augmented primColors + * - `Q` segmented pointer to array of envColors, and can be NULL + * - `R` segmented pointer to array of frameData (u8), which is also seemingly always NULL + * for this type. + * + * envColors take the form `RR GG BB AA` as usual, while primColors have an extra LODFrac + * element: RR GG BB AA LL + * + * `3`: Color changing (LERP): similar to type `2`, but uses linear interpolation. The structure + * is similar to `2`, but + * - `K` is now just the animation length, while + * - `L` is the total number of colors, and + * - the frameData is used to determine which colors to interpolate. + * + * `4`: Color changing (Lagrange interpolation): For extraction purposes identical to type 3. + * Uses a nonlinear interpolation formula to change the colours more smoothly. + * + * `5`: Texture cycle: functions like a gif. Subsidiary params: + * `FFFF 0000 PPPPPPPP QQQQQQQQ` + * where + * - `F` (u16) time between changes in frames + * - `P` pointer to array of segmented pointers to textures to cycle through + * - `Q` array of indices, indicating which texture to use next when a change frame is + * reached. The maximum indicates the number of textures in the texture array. + * + * `6`: This is used to indicate an empty/unimplemented params set. It is ignored by the game's + * function provided that the segment is 0. A generic empty one takes the form + * `00 00 00 06 00000000`, + * and has no extra data. + * + * Implementation + * === + * - ZTextureAnimation requires a declaration in the XML to extract anything. It handles the main + * array. It uses a POD struct for each entry, and declares references to the params structs. + * + * - ZTextureAnimationParams is not (currently) declarable in an XML. It is a parent class for the + * three classes that handle the various cases: + * - TextureScrollingParams for types `0` and `1` + * - TextureColorChangingParams for types `2`,`3`,`4` + * - TextureCyclingParams for type `5` + * Each of these will declare all its subsidiary arrays, using POD structs. + */ +#include "ZTextureAnimation.h" + +#include +#include +#include + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "WarningHandler.h" +#include "ZFile.h" +#include "ZResource.h" +#include "tinyxml2.h" + +REGISTER_ZFILENODE(TextureAnimation, ZTextureAnimation); + +/* Constructors */ +ZTextureAnimationParams::ZTextureAnimationParams(ZFile* parent) : ZResource::ZResource(parent) +{ +} +TextureScrollingParams::TextureScrollingParams(ZFile* parent) + : ZTextureAnimationParams::ZTextureAnimationParams(parent) +{ +} +TextureColorChangingParams::TextureColorChangingParams(ZFile* parent) + : ZTextureAnimationParams::ZTextureAnimationParams(parent) +{ +} +TextureCyclingParams::TextureCyclingParams(ZFile* parent) + : ZTextureAnimationParams::ZTextureAnimationParams(parent) +{ +} + +/* TextureAnimationParams */ +/* This class only implements the functions common to all or most its inheritors */ + +void ZTextureAnimationParams::ExtractFromBinary(uint32_t nRawDataIndex) +{ + rawDataIndex = nRawDataIndex; + + ParseRawData(); +} + +// Implemented by TextureScrollingParams only +void ZTextureAnimationParams::ExtractFromBinary([[maybe_unused]] uint32_t nRawDataIndex, + [[maybe_unused]] int count) +{ +} + +std::string +ZTextureAnimationParams::GetDefaultName([[maybe_unused]] const std::string& prefix) const +{ + return "ShouldNotBeVIsible"; +} + +ZResourceType ZTextureAnimationParams::GetResourceType() const +{ + return ZResourceType::TextureAnimationParams; +} + +/* TextureScrollingParams */ + +void TextureScrollingParams::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + for (int i = 0; i < count; i++) + { + rows[i].xStep = BitConverter::ToUInt8BE(rawData, rawDataIndex + 4 * i); + rows[i].yStep = BitConverter::ToUInt8BE(rawData, rawDataIndex + 4 * i + 1); + rows[i].width = BitConverter::ToUInt8BE(rawData, rawDataIndex + 4 * i + 2); + rows[i].height = BitConverter::ToUInt8BE(rawData, rawDataIndex + 4 * i + 3); + } +} + +void TextureScrollingParams::ExtractFromBinary(uint32_t nRawDataIndex, int nCount) +{ + rawDataIndex = nRawDataIndex; + count = nCount; + + ParseRawData(); +} + +std::string TextureScrollingParams::GetSourceTypeName() const +{ + return "AnimatedMatTexScrollParams"; // TODO: Better name +} + +std::string TextureScrollingParams::GetDefaultName(const std::string& prefix) const +{ + return StringHelper::Sprintf("%sTexScrollParams_%06X", prefix.c_str(), rawDataIndex); +} + +size_t TextureScrollingParams::GetRawDataSize() const +{ + return 4 * count; +} + +/** + * Overrides the parent version to declare an array of the params rather than just one entry. + */ +Declaration* TextureScrollingParams::DeclareVar(const std::string& prefix, + const std::string& bodyStr) +{ + std::string auxName = name; + + if (name == "") + auxName = GetDefaultName(prefix); + + return parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(), + GetSourceTypeName(), auxName, count, bodyStr); +} + +std::string TextureScrollingParams::GetBodySourceCode() const +{ + std::string bodyStr; + + for (int i = 0; i < count; i++) + { + bodyStr += StringHelper::Sprintf("\t{ %d, %d, 0x%02X, 0x%02X },\n", rows[i].xStep, + rows[i].yStep, rows[i].width, rows[i].height); + } + + bodyStr.pop_back(); + + return bodyStr; +} + +/* TextureColorChangingParams */ + +/** + * Also parses the color and frameData arrays + */ +void TextureColorChangingParams::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + animLength = BitConverter::ToUInt16BE(rawData, rawDataIndex); + colorListCount = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2); + + // Handle type 2 separately + uint16_t listLength = + ((type == TextureAnimationParamsType::ColorChange) ? animLength : colorListCount); + + if (listLength == 0) + HANDLE_ERROR_RESOURCE(WarningType::Always, parent, this, rawDataIndex, + "color list length cannot be 0", ""); + + primColorListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4); + envColorListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8); + frameDataListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0xC); + + uint32_t primColorListOffset = Seg2Filespace(primColorListAddress, parent->baseAddress); + uint32_t envColorListOffset = Seg2Filespace(envColorListAddress, parent->baseAddress); + uint32_t frameDataListOffset = Seg2Filespace(frameDataListAddress, parent->baseAddress); + + uint32_t currentPtr; + + F3DPrimColor currentPrimColor; + + for (currentPtr = primColorListOffset; currentPtr < primColorListOffset + 5 * listLength; + currentPtr += 5) + { + currentPrimColor = {BitConverter::ToUInt8BE(rawData, currentPtr), + BitConverter::ToUInt8BE(rawData, currentPtr + 1), + BitConverter::ToUInt8BE(rawData, currentPtr + 2), + BitConverter::ToUInt8BE(rawData, currentPtr + 3), + BitConverter::ToUInt8BE(rawData, currentPtr + 4)}; + primColorList.push_back(currentPrimColor); + } + + F3DEnvColor currentEnvColor; + + for (currentPtr = envColorListOffset; currentPtr < envColorListOffset + 4 * listLength; + currentPtr += 4) + { + currentEnvColor = {BitConverter::ToUInt8BE(rawData, currentPtr), + BitConverter::ToUInt8BE(rawData, currentPtr + 1), + BitConverter::ToUInt8BE(rawData, currentPtr + 2), + BitConverter::ToUInt8BE(rawData, currentPtr + 3)}; + envColorList.push_back(currentEnvColor); + } + + uint16_t currentFrameData; + + for (currentPtr = frameDataListOffset; currentPtr < frameDataListOffset + 2 * listLength; + currentPtr += 2) + { + currentFrameData = BitConverter::ToUInt16BE(rawData, currentPtr); + frameDataList.push_back(currentFrameData); + } +} + +std::string TextureColorChangingParams::GetSourceTypeName() const +{ + return "AnimatedMatColorParams"; // TODO: Better name +} + +std::string TextureColorChangingParams::GetDefaultName(const std::string& prefix) const +{ + return StringHelper::Sprintf("%sColorParams_%06X", prefix.c_str(), rawDataIndex); +} + +size_t TextureColorChangingParams::GetRawDataSize() const +{ + return 0x10; +} + +void TextureColorChangingParams::DeclareReferences([[maybe_unused]] const std::string& prefix) +{ + if (primColorListAddress != 0) // NULL + { + std::string primColorBodyStr; + + for (const auto& color : primColorList) + { + primColorBodyStr += StringHelper::Sprintf("\t{ %d, %d, %d, %d, %d },\n", color.r, + color.g, color.b, color.a, color.lodFrac); + } + + primColorBodyStr.pop_back(); + + parent->AddDeclarationArray( + Seg2Filespace(primColorListAddress, parent->baseAddress), DeclarationAlignment::Align4, + primColorList.size() * 5, "F3DPrimColor", + StringHelper::Sprintf("%sTexColorChangingPrimColors_%06X", parent->GetName().c_str(), + Seg2Filespace(primColorListAddress, parent->baseAddress)), + primColorList.size(), primColorBodyStr); + } + + if (envColorListAddress != 0) // NULL + { + std::string envColorBodyStr; + + for (const auto& color : envColorList) + { + envColorBodyStr += StringHelper::Sprintf("\t{ %d, %d, %d, %d },\n", color.r, color.g, + color.b, color.a); + } + + envColorBodyStr.pop_back(); + + parent->AddDeclarationArray( + Seg2Filespace(envColorListAddress, parent->baseAddress), DeclarationAlignment::Align4, + envColorList.size() * 4, "F3DEnvColor", + StringHelper::Sprintf("%sTexColorChangingEnvColors_%06X", parent->GetName().c_str(), + Seg2Filespace(envColorListAddress, parent->baseAddress)), + envColorList.size(), envColorBodyStr); + } + + if (frameDataListAddress != 0) // NULL + { + std::string frameDataBodyStr = "\t"; + + for (const auto& frame : frameDataList) + { + frameDataBodyStr += StringHelper::Sprintf("%d, ", frame); + } + + frameDataBodyStr.pop_back(); + + parent->AddDeclarationArray( + Seg2Filespace(frameDataListAddress, parent->baseAddress), DeclarationAlignment::Align4, + frameDataList.size() * 2, "u16", + StringHelper::Sprintf("%sTexColorChangingFrameData_%06X", parent->GetName().c_str(), + Seg2Filespace(frameDataListAddress, parent->baseAddress)), + frameDataList.size(), frameDataBodyStr); + } +} + +std::string TextureColorChangingParams::GetBodySourceCode() const +{ + std::string primColorListName; + std::string envColorListName; + std::string frameDataListName; + + Globals::Instance->GetSegmentedPtrName(primColorListAddress, parent, "", primColorListName); + Globals::Instance->GetSegmentedPtrName(envColorListAddress, parent, "", envColorListName); + Globals::Instance->GetSegmentedPtrName(frameDataListAddress, parent, "", frameDataListName); + + std::string bodyStr = StringHelper::Sprintf( + "\n %d, %d, %s, %s, %s,\n", animLength, colorListCount, primColorListName.c_str(), + envColorListName.c_str(), frameDataListName.c_str()); + + return bodyStr; +} + +/* TextureCyclingParams */ + +void TextureCyclingParams::ParseRawData() +{ + const auto& rawData = parent->GetRawData(); + + cycleLength = BitConverter::ToUInt16BE(rawData, rawDataIndex); + if (cycleLength == 0) + HANDLE_ERROR_RESOURCE(WarningType::Always, parent, this, rawDataIndex, + "cycle length cannot be 0", ""); + + textureListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4); + textureIndexListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8); + + uint32_t textureListOffset = Seg2Filespace(textureListAddress, parent->baseAddress); + uint32_t textureIndexListOffset = Seg2Filespace(textureIndexListAddress, parent->baseAddress); + + uint32_t currentPtr; + + uint8_t currentIndex; + uint8_t maxIndex = 0; // To find the length of the texture list + + for (currentPtr = textureIndexListOffset; currentPtr < textureIndexListOffset + cycleLength; + currentPtr++) + { + currentIndex = BitConverter::ToUInt8BE(rawData, currentPtr); + textureIndexList.push_back(currentIndex); + if (currentIndex > maxIndex) + maxIndex = currentIndex; + } + + for (currentPtr = textureListOffset; currentPtr <= textureListOffset + 4 * maxIndex; + currentPtr += 4) + { + textureList.push_back(BitConverter::ToUInt32BE(rawData, currentPtr)); + } +} + +std::string TextureCyclingParams::GetSourceTypeName() const +{ + return "AnimatedMatTexCycleParams"; // TODO: Better name +} + +std::string TextureCyclingParams::GetDefaultName(const std::string& prefix) const +{ + return StringHelper::Sprintf("%sTexCycleParams_%06X", prefix.c_str(), rawDataIndex); +} + +size_t TextureCyclingParams::GetRawDataSize() const +{ + return 0xC; +} + +void TextureCyclingParams::DeclareReferences([[maybe_unused]] const std::string& prefix) +{ + if (textureListAddress != 0) // NULL + { + std::string texturesBodyStr; + std::string texName; + std::string comment; + + for (const auto& tex : textureList) + { + bool texFound = Globals::Instance->GetSegmentedPtrName(tex, parent, "", texName); + + // texName is a raw segmented pointer. This occurs if the texture is not declared + // separately since we cannot read the format. In theory we could scan DLists for the + // format on the appropriate segments. + if (!texFound) + { + comment = " // Raw pointer, declare texture in XML to use proper symbol"; + + auto msgHeader = StringHelper::Sprintf( + "TexCycle texture array declared here points to unknown texture at address %s", + texName.c_str()); + HANDLE_WARNING_RESOURCE( + WarningType::HardcodedPointer, parent, this, rawDataIndex, msgHeader, + "Please declare the texture in the XML to use the proper symbol."); + } + texturesBodyStr += StringHelper::Sprintf("\t%s,%s\n", texName.c_str(), comment.c_str()); + } + + texturesBodyStr.pop_back(); + + parent->AddDeclarationArray( + Seg2Filespace(textureListAddress, parent->baseAddress), DeclarationAlignment::Align4, + textureList.size() * 4, "TexturePtr", + StringHelper::Sprintf("%sTexCycleTexPtrs_%06X", parent->GetName().c_str(), + Seg2Filespace(textureListAddress, parent->baseAddress)), + textureList.size(), texturesBodyStr); + } + + if (textureIndexListAddress != 0) // NULL + { + std::string indicesBodyStr = "\t"; + + for (uint8_t index : textureIndexList) + { + indicesBodyStr += StringHelper::Sprintf("%d, ", index); + } + + indicesBodyStr.pop_back(); + + parent->AddDeclarationArray( + Seg2Filespace(textureIndexListAddress, parent->baseAddress), + DeclarationAlignment::Align4, textureIndexList.size(), "u8", + StringHelper::Sprintf("%sTexCycleTexIndices_%06X", parent->GetName().c_str(), + Seg2Filespace(textureIndexListAddress, parent->baseAddress)), + textureIndexList.size(), indicesBodyStr); + } +} + +std::string TextureCyclingParams::GetBodySourceCode() const +{ + std::string textureListName; + std::string textureIndexListName; + + Globals::Instance->GetSegmentedPtrName(textureListAddress, parent, "", textureListName); + Globals::Instance->GetSegmentedPtrName(textureIndexListAddress, parent, "", + textureIndexListName); + + std::string bodyStr = StringHelper::Sprintf( + "\n %d, %s, %s,\n", cycleLength, textureListName.c_str(), textureIndexListName.c_str()); + + return bodyStr; +} + +/* ZTextureAnimation */ + +ZTextureAnimation::ZTextureAnimation(ZFile* nParent) : ZResource(nParent) +{ +} + +/** + * Builds the array of params + */ +void ZTextureAnimation::ParseRawData() +{ + ZResource::ParseRawData(); + + TextureAnimationEntry currentEntry; + auto rawData = parent->GetRawData(); + int16_t type; + + for (uint32_t currentPtr = rawDataIndex;; currentPtr += 8) + { + type = BitConverter::ToInt16BE(rawData, currentPtr + 2); + + currentEntry.segment = BitConverter::ToInt8BE(rawData, currentPtr); + currentEntry.type = (TextureAnimationParamsType)type; + currentEntry.paramsPtr = BitConverter::ToUInt32BE(rawData, currentPtr + 4); + entries.push_back(currentEntry); + + if ((type < 0) || (type > 6)) + { + HANDLE_ERROR_RESOURCE( + WarningType::Always, parent, this, rawDataIndex, + StringHelper::Sprintf( + "unknown TextureAnimationParams type 0x%02X in TextureAnimation", type), + StringHelper::Sprintf( + "Entry reads { 0x%02X, 0x%02X, 0x%08X } , but type should be " + "between 0x00 and 0x06 inclusive.", + currentEntry.segment, type, currentEntry.paramsPtr)); + } + + if (currentEntry.segment <= 0) + break; + } +} + +#include +/** + * For each params entry, + */ +void ZTextureAnimation::DeclareReferences(const std::string& prefix) +{ + std::string varPrefix = name; + if (varPrefix == "") + varPrefix = prefix; + + ZResource::DeclareReferences(varPrefix); + + for (const auto& entry : entries) + { + if (entry.paramsPtr != 0 && GETSEGNUM(entry.paramsPtr) == parent->segment) + { + uint32_t paramsOffset = Seg2Filespace(entry.paramsPtr, parent->baseAddress); + if (!parent->HasDeclaration(paramsOffset)) + { + ZTextureAnimationParams* params; + int count; + switch (entry.type) + { + case TextureAnimationParamsType::SingleScroll: + if (true) + { + count = 1; + // The else now allows SingleScroll to fall through to params = ... without + // touching the code in the else block + } + else + { + // The contents of this block can only be run by jumping into it with the + // case label + [[fallthrough]]; + case TextureAnimationParamsType::DualScroll: + count = 2; + } + params = new TextureScrollingParams(parent); + params->ExtractFromBinary(paramsOffset, count); + break; + + case TextureAnimationParamsType::ColorChange: + case TextureAnimationParamsType::ColorChangeLERP: + case TextureAnimationParamsType::ColorChangeLagrange: + params = new TextureColorChangingParams(parent); + params->type = entry.type; + params->ExtractFromBinary(paramsOffset); + break; + + case TextureAnimationParamsType::TextureCycle: + params = new TextureCyclingParams(parent); + params->ExtractFromBinary(paramsOffset); + break; + + case TextureAnimationParamsType::Empty: + HANDLE_WARNING_RESOURCE( + WarningType::InvalidExtractedData, parent, this, rawDataIndex, + "TextureAnimationParams entry has empty type (6), but params pointer is " + "not NULL", + StringHelper::Sprintf("Params read { 0x%02X, 0x%02X, 0x%08X } .", + entry.segment, (int)entry.type, entry.paramsPtr)); + return; + default: + // Because GCC is worried this could happen + assert(entry.type < TextureAnimationParamsType::SingleScroll || + entry.type > TextureAnimationParamsType::Empty); + return; + } + + params->SetName(params->GetDefaultName(varPrefix)); + params->DeclareVar(varPrefix, ""); + parent->AddResource(params); + } + } + } +} + +std::string ZTextureAnimation::GetSourceTypeName() const +{ + return "AnimatedMaterial"; // TODO: Better name +} + +ZResourceType ZTextureAnimation::GetResourceType() const +{ + return ZResourceType::TextureAnimation; +} + +/** + * The size of the main array + */ +size_t ZTextureAnimation::GetRawDataSize() const +{ + return entries.size() * 8; +} + +std::string ZTextureAnimation::GetDefaultName(const std::string& prefix) const +{ + return StringHelper::Sprintf("%sTexAnim_%06X", prefix.c_str(), rawDataIndex); +} + +Declaration* ZTextureAnimation::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(), auxName, entries.size(), bodyStr); + decl->staticConf = staticConf; + return decl; +} + +std::string ZTextureAnimation::GetBodySourceCode() const +{ + std::string bodyStr; + + for (const auto& entry : entries) + { + std::string paramName; + Globals::Instance->GetSegmentedPtrName(entry.paramsPtr, parent, "", paramName); + + bodyStr += StringHelper::Sprintf("\t{ %d, %d, %s },\n", entry.segment, entry.type, + paramName.c_str()); + } + + bodyStr.pop_back(); + + return bodyStr; +} diff --git a/ZAPDTR/ZAPD/ZTextureAnimation.h b/ZAPDTR/ZAPD/ZTextureAnimation.h new file mode 100644 index 000000000..6b03eb7cf --- /dev/null +++ b/ZAPDTR/ZAPD/ZTextureAnimation.h @@ -0,0 +1,151 @@ +#pragma once + +#include +#include +#include +#include + +#include "ZResource.h" + +enum class TextureAnimationParamsType +{ + /* 0 */ SingleScroll, + /* 1 */ DualScroll, + /* 2 */ ColorChange, + /* 3 */ ColorChangeLERP, + /* 4 */ ColorChangeLagrange, + /* 5 */ TextureCycle, + /* 6 */ Empty // An empty TextureAnimation has the form 00 00 00 06 00000000 +}; + +class ZTextureAnimationParams : public ZResource +{ +public: + ZTextureAnimationParams(ZFile* parent); + + void ExtractFromBinary(uint32_t nRawDataIndex); + virtual void ExtractFromBinary(uint32_t nRawDataIndex, int count); + + virtual std::string GetDefaultName(const std::string& prefix) const; + ZResourceType GetResourceType() const; + + TextureAnimationParamsType type; +}; + +struct TextureScrollingParamsEntry +{ + int8_t xStep; + int8_t yStep; + uint8_t width; + uint8_t height; +}; + +class TextureScrollingParams : public ZTextureAnimationParams +{ +public: + TextureScrollingParams(ZFile* parent); + + void ParseRawData() override; + void ExtractFromBinary(uint32_t nRawDataIndex, int count) override; + + std::string GetSourceTypeName() const override; + std::string GetDefaultName(const std::string& prefix) const override; + size_t GetRawDataSize() const override; + + Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override; + std::string GetBodySourceCode() const override; + + int count; // 1 for Single, 2 for Dual + TextureScrollingParamsEntry rows[2]; // Too small to make a vector worth it +}; + +struct F3DPrimColor +{ + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + uint8_t lodFrac; +}; + +struct F3DEnvColor +{ + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +class TextureColorChangingParams : public ZTextureAnimationParams +{ +public: + TextureColorChangingParams(ZFile* parent); + + void ParseRawData() override; + + std::string GetSourceTypeName() const override; + std::string GetDefaultName(const std::string& prefix) const override; + size_t GetRawDataSize() const override; + + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + uint16_t animLength; // size of list for type 2 + uint16_t colorListCount; + segptr_t primColorListAddress; + segptr_t envColorListAddress; + segptr_t frameDataListAddress; + std::vector primColorList; + std::vector envColorList; + std::vector frameDataList; +}; + +class TextureCyclingParams : public ZTextureAnimationParams +{ +public: + TextureCyclingParams(ZFile* parent); + + void ParseRawData() override; + + std::string GetSourceTypeName() const override; + std::string GetDefaultName(const std::string& prefix) const override; + size_t GetRawDataSize() const override; + + void DeclareReferences(const std::string& prefix) override; + + std::string GetBodySourceCode() const override; + + uint16_t cycleLength; + segptr_t textureListAddress; + segptr_t textureIndexListAddress; + std::vector textureList; + std::vector textureIndexList; +}; + +struct TextureAnimationEntry +{ + int8_t segment; + TextureAnimationParamsType type; + segptr_t paramsPtr; +}; + +class ZTextureAnimation : public ZResource +{ +public: + ZTextureAnimation(ZFile* nParent); + + void ParseRawData() override; + void DeclareReferences(const std::string& prefix) override; + + std::string GetSourceTypeName() const override; + ZResourceType GetResourceType() const override; + size_t GetRawDataSize() const override; + std::string GetDefaultName(const std::string& prefix) const override; + + Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override; + std::string GetBodySourceCode() const override; + +private: + std::vector entries; +}; diff --git a/ZAPDTR/ZAPD/ZVector.cpp b/ZAPDTR/ZAPD/ZVector.cpp new file mode 100644 index 000000000..a5a059e35 --- /dev/null +++ b/ZAPDTR/ZAPD/ZVector.cpp @@ -0,0 +1,126 @@ +#include "ZVector.h" + +#include + +#include "Globals.h" +#include "Utils/BitConverter.h" +#include "Utils/File.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Vector, ZVector); + +ZVector::ZVector(ZFile* nParent) : ZResource(nParent) +{ + scalarType = ZScalarType::ZSCALAR_NONE; + dimensions = 0; + + RegisterRequiredAttribute("Type"); + RegisterRequiredAttribute("Dimensions"); +} + +void ZVector::ExtractFromBinary(uint32_t nRawDataIndex, ZScalarType nScalarType, + uint32_t nDimensions) +{ + rawDataIndex = nRawDataIndex; + scalarType = nScalarType; + dimensions = nDimensions; + + // Don't parse raw data of external files + if (parent->GetMode() == ZFileMode::ExternalFile) + return; + + ParseRawData(); +} + +void ZVector::ParseXML(tinyxml2::XMLElement* reader) +{ + ZResource::ParseXML(reader); + + this->scalarType = ZScalar::MapOutputTypeToScalarType(registeredAttributes.at("Type").value); + + this->dimensions = StringHelper::StrToL(registeredAttributes.at("Dimensions").value, 16); +} + +void ZVector::ParseRawData() +{ + int32_t currentRawDataIndex = rawDataIndex; + // TODO: this shouldn't be necessary. + scalars.clear(); + + for (uint32_t i = 0; i < dimensions; i++) + { + ZScalar scalar(parent); + scalar.ExtractFromBinary(currentRawDataIndex, scalarType); + currentRawDataIndex += scalar.GetRawDataSize(); + + scalars.push_back(scalar); + } + + // Ensure the scalars vector has the same number of elements as the vector dimension. + assert(scalars.size() == dimensions); +} + +size_t ZVector::GetRawDataSize() const +{ + size_t size = 0; + + for (size_t i = 0; i < this->scalars.size(); i++) + size += this->scalars[i].GetRawDataSize(); + + return size; +} + +bool ZVector::DoesSupportArray() const +{ + return true; +} + +std::string ZVector::GetSourceTypeName() const +{ + if (dimensions == 3 && scalarType == ZScalarType::ZSCALAR_F32) + return "Vec3f"; + else if (dimensions == 3 && scalarType == ZScalarType::ZSCALAR_S16) + return "Vec3s"; + else if (dimensions == 3 && scalarType == ZScalarType::ZSCALAR_S32) + return "Vec3i"; + else + { + std::string msgHeader = StringHelper::Sprintf( + "encountered unsupported vector type: %d dimensions, %s type", dimensions, + ZScalar::MapScalarTypeToOutputType(scalarType).c_str()); + + HANDLE_ERROR_RESOURCE(WarningType::NotImplemented, parent, this, rawDataIndex, msgHeader, + ""); + } +} + +std::string ZVector::GetBodySourceCode() const +{ + std::string body = ""; + + for (size_t i = 0; i < scalars.size(); i++) + { + body += StringHelper::Sprintf("%6s", scalars[i].GetBodySourceCode().c_str()); + + if (i + 1 < scalars.size()) + body += ", "; + } + + return body; +} + +ZResourceType ZVector::GetResourceType() const +{ + return ZResourceType::Vector; +} + +DeclarationAlignment ZVector::GetDeclarationAlignment() const +{ + if (scalars.size() == 0) + { + return DeclarationAlignment::Align4; + } + return scalars.at(0).GetDeclarationAlignment(); +} diff --git a/ZAPDTR/ZAPD/ZVector.h b/ZAPDTR/ZAPD/ZVector.h new file mode 100644 index 000000000..a50d3e808 --- /dev/null +++ b/ZAPDTR/ZAPD/ZVector.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include "ZResource.h" +#include "ZScalar.h" +#include "tinyxml2.h" + +class ZVector : public ZResource +{ +public: + std::vector scalars; + ZScalarType scalarType; + uint32_t dimensions; + + ZVector(ZFile* nParent); + + void ExtractFromBinary(uint32_t nRawDataIndex, ZScalarType nScalarType, uint32_t nDimensions); + + 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; + DeclarationAlignment GetDeclarationAlignment() const override; +}; diff --git a/ZAPDTR/ZAPD/ZVtx.cpp b/ZAPDTR/ZAPD/ZVtx.cpp new file mode 100644 index 000000000..e4b3d9796 --- /dev/null +++ b/ZAPDTR/ZAPD/ZVtx.cpp @@ -0,0 +1,86 @@ +#include "ZVtx.h" + +#include "Utils/BitConverter.h" +#include "Utils/StringHelper.h" +#include "ZFile.h" + +REGISTER_ZFILENODE(Vtx, ZVtx); + +ZVtx::ZVtx(ZFile* nParent) : ZResource(nParent) +{ + x = 0; + y = 0; + z = 0; + flag = 0; + s = 0; + t = 0; + r = 0; + g = 0; + b = 0; + a = 0; +} + +void ZVtx::ParseRawData() +{ + ZResource::ParseRawData(); + + const auto& rawData = parent->GetRawData(); + x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0); + y = BitConverter::ToInt16BE(rawData, rawDataIndex + 2); + z = BitConverter::ToInt16BE(rawData, rawDataIndex + 4); + flag = BitConverter::ToInt16BE(rawData, rawDataIndex + 6); + s = BitConverter::ToInt16BE(rawData, rawDataIndex + 8); + t = BitConverter::ToInt16BE(rawData, rawDataIndex + 10); + r = rawData[rawDataIndex + 12]; + g = rawData[rawDataIndex + 13]; + b = rawData[rawDataIndex + 14]; + a = rawData[rawDataIndex + 15]; +} + +Declaration* ZVtx::DeclareVar(const std::string& prefix, const std::string& bodyStr) +{ + Declaration* decl = ZResource::DeclareVar(prefix, bodyStr); + decl->isExternal = true; + return decl; +} + +std::string ZVtx::GetBodySourceCode() const +{ + return StringHelper::Sprintf("VTX(%i, %i, %i, %i, %i, %i, %i, %i, %i)", x, y, z, s, t, r, g, b, + a); +} + +size_t ZVtx::GetRawDataSize() const +{ + return 16; +} + +bool ZVtx::DoesSupportArray() const +{ + return true; +} + +ZResourceType ZVtx::GetResourceType() const +{ + return ZResourceType::Vertex; +} + +bool ZVtx::IsExternalResource() const +{ + return true; +} + +std::string ZVtx::GetSourceTypeName() const +{ + return "Vtx"; +} + +std::string ZVtx::GetExternalExtension() const +{ + return "vtx"; +} + +DeclarationAlignment ZVtx::GetDeclarationAlignment() const +{ + return DeclarationAlignment::Align8; +} diff --git a/ZAPDTR/ZAPD/ZVtx.h b/ZAPDTR/ZAPD/ZVtx.h new file mode 100644 index 000000000..511048791 --- /dev/null +++ b/ZAPDTR/ZAPD/ZVtx.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include "ZResource.h" +#include "ZScalar.h" +#include "tinyxml2.h" + +class ZVtx : public ZResource +{ +public: + int16_t x, y, z; + uint16_t flag; + int16_t s, t; + uint8_t r, g, b, a; + + ZVtx(ZFile* nParent); + + void ParseRawData() override; + + Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override; + std::string GetBodySourceCode() const override; + + bool IsExternalResource() const override; + bool DoesSupportArray() 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; +}; diff --git a/ZAPDTR/ZAPD/any/any/zlib.static.txt b/ZAPDTR/ZAPD/any/any/zlib.static.txt new file mode 100644 index 000000000..e69de29bb diff --git a/ZAPDTR/ZAPD/genbuildinfo.py b/ZAPDTR/ZAPD/genbuildinfo.py new file mode 100644 index 000000000..91a567d31 --- /dev/null +++ b/ZAPDTR/ZAPD/genbuildinfo.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import argparse +from datetime import datetime +import getpass +import subprocess + +parser = argparse.ArgumentParser() +parser.add_argument("--devel", action="store_true") +args = parser.parse_args() + +with open("build/ZAPD/BuildInfo.cpp", "w+") as buildFile: + label = subprocess.check_output(["git", "describe", "--always"]).strip().decode("utf-8") + now = datetime.now() + if args.devel: + label += " ~ Development version" + buildFile.write("extern const char gBuildHash[] = \"" + label + "\";\n") + #buildFile.write("extern const char gBuildDate[] = \"" + now.strftime("%Y-%m-%d %H:%M:%S") + "\";\n") diff --git a/ZAPDTR/ZAPD/packages.config b/ZAPDTR/ZAPD/packages.config new file mode 100644 index 000000000..c387aaed7 --- /dev/null +++ b/ZAPDTR/ZAPD/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/ZAPDTR/ZAPDTR.sln b/ZAPDTR/ZAPDTR.sln new file mode 100644 index 000000000..82538dd9f --- /dev/null +++ b/ZAPDTR/ZAPDTR.sln @@ -0,0 +1,82 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30320.27 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZAPD", "ZAPD\ZAPD.vcxproj", "{B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExporterExample", "ExporterTest\ExporterTest.vcxproj", "{65608EB0-1A47-45AD-AB66-192FB64C762C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZAPDUtils", "ZAPDUtils\ZAPDUtils.vcxproj", "{A2E01C3E-D647-45D1-9788-043DEBC1A908}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + MinSizeRel|x64 = MinSizeRel|x64 + MinSizeRel|x86 = MinSizeRel|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + RelWithDebInfo|x64 = RelWithDebInfo|x64 + RelWithDebInfo|x86 = RelWithDebInfo|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Debug|x64.ActiveCfg = Debug|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Debug|x64.Build.0 = Debug|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Debug|x86.ActiveCfg = Debug|Win32 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Debug|x86.Build.0 = Debug|Win32 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.MinSizeRel|x64.ActiveCfg = Release|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.MinSizeRel|x64.Build.0 = Release|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.MinSizeRel|x86.ActiveCfg = Release|Win32 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.MinSizeRel|x86.Build.0 = Release|Win32 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Release|x64.ActiveCfg = Release|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Release|x64.Build.0 = Release|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Release|x86.ActiveCfg = Release|Win32 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.Release|x86.Build.0 = Release|Win32 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.RelWithDebInfo|x64.Build.0 = Release|x64 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {B53F9E5B-0A58-4BAE-9AFE-856C8CBB8D36}.RelWithDebInfo|x86.Build.0 = Release|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Debug|x64.ActiveCfg = Debug|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Debug|x64.Build.0 = Debug|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Debug|x86.ActiveCfg = Debug|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Debug|x86.Build.0 = Debug|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.MinSizeRel|x64.ActiveCfg = Debug|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.MinSizeRel|x64.Build.0 = Debug|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.MinSizeRel|x86.ActiveCfg = Debug|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.MinSizeRel|x86.Build.0 = Debug|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Release|x64.ActiveCfg = Release|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Release|x64.Build.0 = Release|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Release|x86.ActiveCfg = Release|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.Release|x86.Build.0 = Release|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.RelWithDebInfo|x64.Build.0 = Release|x64 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {65608EB0-1A47-45AD-AB66-192FB64C762C}.RelWithDebInfo|x86.Build.0 = Release|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Debug|x64.ActiveCfg = Debug|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Debug|x64.Build.0 = Debug|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Debug|x86.ActiveCfg = Debug|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Debug|x86.Build.0 = Debug|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.MinSizeRel|x64.ActiveCfg = Debug|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.MinSizeRel|x64.Build.0 = Debug|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.MinSizeRel|x86.ActiveCfg = Debug|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.MinSizeRel|x86.Build.0 = Debug|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Release|x64.ActiveCfg = Release|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Release|x64.Build.0 = Release|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Release|x86.ActiveCfg = Release|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.Release|x86.Build.0 = Release|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.RelWithDebInfo|x64.Build.0 = Release|x64 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {A2E01C3E-D647-45D1-9788-043DEBC1A908}.RelWithDebInfo|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C2E1CC72-7A50-3249-AFD5-DFF6FE25CDCA} + EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection +EndGlobal diff --git a/ZAPDTR/ZAPDUtils/Color3b.h b/ZAPDTR/ZAPDUtils/Color3b.h new file mode 100644 index 000000000..507c099f5 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Color3b.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +struct Color3b +{ + uint8_t r, g, b; + + Color3b() + { + r = 0; + g = 0; + b = 0; + }; + Color3b(uint8_t nR, uint8_t nG, uint8_t nB) + { + r = nR; + g = nG; + b = nB; + }; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Makefile b/ZAPDTR/ZAPDUtils/Makefile new file mode 100644 index 000000000..aef678031 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Makefile @@ -0,0 +1,28 @@ +# Only used for standalone compilation, usually inherits these from the main makefile +CXXFLAGS ?= -Wall -Wextra -O2 -g -std=c++17 + +SRC_DIRS := $(shell find -type d -not -path "*build*") +CPP_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp)) +H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h)) + +O_FILES := $(foreach f,$(CPP_FILES:.cpp=.o),build/$f) +LIB := ZAPDUtils.a + +# create build directories +$(shell mkdir -p $(foreach dir,$(SRC_DIRS),build/$(dir))) + +all: $(LIB) + +clean: + rm -rf build $(LIB) + +format: + clang-format-11 -i $(CPP_FILES) $(H_FILES) + +.PHONY: all clean format + +build/%.o: %.cpp + $(CXX) $(CXXFLAGS) $(OPTFLAGS) -c $(OUTPUT_OPTION) $< + +$(LIB): $(O_FILES) + $(AR) rcs $@ $^ diff --git a/ZAPDTR/ZAPDUtils/StrHash.h b/ZAPDTR/ZAPDUtils/StrHash.h new file mode 100644 index 000000000..c611bddda --- /dev/null +++ b/ZAPDTR/ZAPDUtils/StrHash.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include + +typedef uint32_t strhash; + +[[maybe_unused]] static strhash CRC32B(unsigned char* message, int32_t size) +{ + int32_t byte = 0, crc = 0; + int32_t mask = 0; + + 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); +} + +[[maybe_unused]] constexpr static strhash CRC32BCT(const char* message, int32_t size) +{ + int32_t byte = 0, crc = 0; + int32_t mask = 0; + + 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); +} \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryReader.cpp b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.cpp new file mode 100644 index 000000000..94ca98a01 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.cpp @@ -0,0 +1,148 @@ +#include "BinaryReader.h" +#include +#include +#include "Stream.h" + +BinaryReader::BinaryReader(Stream* nStream) +{ + stream.reset(nStream); +} + +BinaryReader::BinaryReader(std::shared_ptr nStream) +{ + stream = nStream; +} + +void BinaryReader::Close() +{ + stream->Close(); +} + +void BinaryReader::Seek(uint32_t offset, SeekOffsetType seekType) +{ + stream->Seek(offset, seekType); +} + +uint32_t BinaryReader::GetBaseAddress() +{ + return stream->GetBaseAddress(); +} + +void BinaryReader::Read([[maybe_unused]] char* buffer, int32_t length) +{ + stream->Read(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)); + return result; +} + +int32_t BinaryReader::ReadInt32() +{ + int32_t result = 0; + + stream->Read((char*)&result, sizeof(int32_t)); + return result; +} + +uint16_t BinaryReader::ReadUInt16() +{ + uint16_t result = 0; + + stream->Read((char*)&result, sizeof(uint16_t)); + return result; +} + +uint32_t BinaryReader::ReadUInt32() +{ + uint32_t result = 0; + + stream->Read((char*)&result, sizeof(uint32_t)); + return result; +} + +uint64_t BinaryReader::ReadUInt64() +{ + uint64_t result = 0; + + stream->Read((char*)&result, sizeof(uint64_t)); + return result; +} + +float BinaryReader::ReadSingle() +{ + float result = NAN; + + stream->Read((char*)&result, sizeof(float)); + + 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 (std::isnan(result)) + throw std::runtime_error("BinaryReader::ReadDouble(): Error reading stream"); + + return result; +} + +Vec3f BinaryReader::ReadVec3f() +{ + return Vec3f(); +} + +Vec3s BinaryReader::ReadVec3s() +{ + return Vec3s(0, 0, 0); +} + +Vec3s BinaryReader::ReadVec3b() +{ + return Vec3s(0, 0, 0); +} + +Vec2f BinaryReader::ReadVec2f() +{ + return Vec2f(); +} + +Color3b BinaryReader::ReadColor3b() +{ + return Color3b(); +} + +std::string BinaryReader::ReadString() +{ + std::string res; + int numChars = ReadInt32(); + + for (int i = 0; i < numChars; i++) + res += ReadChar(); + + return res; +} \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryReader.h b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.h new file mode 100644 index 000000000..a1994aa4a --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include +#include "../Color3b.h" +#include "../Vec2f.h" +#include "../Vec3f.h" +#include "../Vec3s.h" +#include "Stream.h" + +class BinaryReader +{ +public: + BinaryReader(Stream* nStream); + BinaryReader(std::shared_ptr nStream); + + void Close(); + + void Seek(uint32_t offset, SeekOffsetType seekType); + uint32_t GetBaseAddress(); + + 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(); + Vec3f ReadVec3f(); + Vec3s ReadVec3s(); + Vec3s ReadVec3b(); + Vec2f ReadVec2f(); + Color3b ReadColor3b(); + std::string ReadString(); + +protected: + std::shared_ptr stream; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.cpp b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.cpp new file mode 100644 index 000000000..c456bdeb3 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.cpp @@ -0,0 +1,106 @@ +#include "BinaryWriter.h" + +BinaryWriter::BinaryWriter(Stream* nStream) +{ + stream.reset(nStream); +} + +BinaryWriter::BinaryWriter(std::shared_ptr nStream) +{ + stream = nStream; +} + +void BinaryWriter::Close() +{ + stream->Close(); +} + +std::shared_ptr 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) +{ + stream->Write((char*)&value, sizeof(int16_t)); +} + +void BinaryWriter::Write(uint16_t value) +{ + stream->Write((char*)&value, sizeof(uint16_t)); +} + +void BinaryWriter::Write(int32_t 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) +{ + stream->Write((char*)&value, sizeof(uint32_t)); +} + +void BinaryWriter::Write(int64_t value) +{ + stream->Write((char*)&value, sizeof(int64_t)); +} + +void BinaryWriter::Write(uint64_t value) +{ + stream->Write((char*)&value, sizeof(uint64_t)); +} + +void BinaryWriter::Write(float value) +{ + stream->Write((char*)&value, sizeof(float)); +} + +void BinaryWriter::Write(double value) +{ + stream->Write((char*)&value, sizeof(double)); +} + +void BinaryWriter::Write(const std::string& str) +{ + int strLen = str.size(); + stream->Write((char*)&strLen, sizeof(int)); + + for (char c : str) + stream->WriteByte(c); +} + +void BinaryWriter::Write(char* srcBuffer, size_t length) +{ + stream->Write(srcBuffer, length); +} diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.h b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.h new file mode 100644 index 000000000..e6dd84105 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include +#include "Stream.h" + +class BinaryWriter +{ +public: + BinaryWriter(Stream* nStream); + BinaryWriter(std::shared_ptr nStream); + + std::shared_ptr 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; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/BitConverter.h b/ZAPDTR/ZAPDUtils/Utils/BitConverter.h new file mode 100644 index 000000000..e672b97c2 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/BitConverter.h @@ -0,0 +1,161 @@ +#pragma once + +#include +#include +#include + +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& 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& 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& 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& 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& 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& 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& 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& 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& 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::is_iec559, + "expected IEC559 floats on host machine"); + std::memcpy(&value, &floatData, sizeof(value)); + return value; + } + + static inline double ToDoubleBE(const std::vector& 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::is_iec559, + "expected IEC559 doubles on host machine"); + std::memcpy(&value, &floatData, sizeof(value)); + return value; + } +}; diff --git a/ZAPDTR/ZAPDUtils/Utils/Directory.h b/ZAPDTR/ZAPDUtils/Utils/Directory.h new file mode 100644 index 000000000..d14ec264e --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/Directory.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include + +#if __has_include() +#include +namespace fs = std::filesystem; +#else +#include +namespace fs = std::experimental::filesystem; +#endif + +#include "StringHelper.h" + +#undef GetCurrentDirectory +#undef CreateDirectory + +class Directory +{ +public: + #ifndef PATH_HACK + static std::string GetCurrentDirectory() { return fs::current_path().u8string().c_str(); } + #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) + { + +#ifdef _MSC_VER + std::string splitChar = "\\"; +#else + std::string splitChar = "/"; +#endif + + std::string curPath; + std::vector split = StringHelper::Split(path, splitChar); + + for (std::string s : split) + { + curPath += s + splitChar; + + if (!Exists(curPath)) + fs::create_directory(curPath); + } + + // fs::create_directory(path); + } + + static std::vector ListFiles(const std::string& dir) + { + std::vector lst; + + if (Directory::Exists(dir)) + { + for (auto& p : fs::recursive_directory_iterator(dir)) + { + if (!p.is_directory()) + lst.push_back(p.path().string()); + } + } + + return lst; + } +}; diff --git a/ZAPDTR/ZAPDUtils/Utils/File.h b/ZAPDTR/ZAPDUtils/Utils/File.h new file mode 100644 index 000000000..f3448bd6a --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/File.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "Path.h" +#include "Utils/StringHelper.h" +#include "Utils/Directory.h" + + +class File +{ +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 ReadAllBytes(const fs::path& filePath) + { + std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); + + if (!file) + return std::vector(); + + int32_t fileSize = (int32_t)file.tellg(); + file.seekg(0); + char* data = new char[fileSize]; + file.read(data, fileSize); + std::vector result = std::vector(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 ReadAllLines(const fs::path& filePath) + { + std::string text = ReadAllText(filePath); + std::vector lines = StringHelper::Split(text, "\n"); + + return lines; + }; + + static void WriteAllBytes(const fs::path& filePath, const std::vector& 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& 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) + { + std::ofstream file(filePath, std::ios::out); + file.write(text.c_str(), text.size()); + } +}; diff --git a/ZAPDTR/ZAPDUtils/Utils/MemoryStream.cpp b/ZAPDTR/ZAPDUtils/Utils/MemoryStream.cpp new file mode 100644 index 000000000..1c70c007f --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/MemoryStream.cpp @@ -0,0 +1,97 @@ +#include "MemoryStream.h" +#include + +#ifndef _MSC_VER +#define memcpy_s(dest, destSize, source, sourceSize) memcpy(dest, source, destSize) +#endif + +MemoryStream::MemoryStream() +{ + buffer = std::vector(); + //buffer.reserve(1024 * 16); + bufferSize = 0; + baseAddress = 0; +} + +MemoryStream::MemoryStream(char* nBuffer, size_t nBufferSize) : MemoryStream() +{ + buffer = std::vector(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 MemoryStream::Read(size_t length) +{ + std::unique_ptr result = std::make_unique(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 MemoryStream::ToVector() +{ + return buffer; +} + +void MemoryStream::Flush() +{ +} + +void MemoryStream::Close() +{ +} \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/MemoryStream.h b/ZAPDTR/ZAPDUtils/Utils/MemoryStream.h new file mode 100644 index 000000000..5a17bb0c3 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/MemoryStream.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#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 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 ToVector(); + + void Flush() override; + void Close() override; + +protected: + std::vector buffer; + std::size_t bufferSize; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/Path.h b/ZAPDTR/ZAPDUtils/Utils/Path.h new file mode 100644 index 000000000..0f7ef2743 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/Path.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include "Utils/StringHelper.h" + +#if __has_include() +#include +namespace fs = std::filesystem; +#else +#include +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 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(); }; +}; diff --git a/ZAPDTR/ZAPDUtils/Utils/Stream.h b/ZAPDTR/ZAPDUtils/Utils/Stream.h new file mode 100644 index 000000000..e73a9a70d --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/Stream.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +enum class SeekOffsetType +{ + Start, + Current, + End +}; + +// TODO: Eventually account for endianess in binaryreader and binarywriter +enum class Endianess +{ + Little = 0, + Big = 1, +}; + +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 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; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp b/ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp new file mode 100644 index 000000000..e2b646fd9 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp @@ -0,0 +1,126 @@ +#include "StringHelper.h" + +#pragma optimize("2", on) +#define _CRT_SECURE_NO_WARNINGS + +std::vector StringHelper::Split(std::string s, const std::string& delimiter) +{ + std::vector result; + + size_t pos = 0; + std::string token; + + while ((pos = s.find(delimiter)) != std::string::npos) + { + token = s.substr(0, pos); + result.push_back(token); + s.erase(0, pos + delimiter.length()); + } + + if (s.length() != 0) + result.push_back(s); + + return result; +} + +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) +{ + return s.rfind(input, 0) == 0; +} + +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& 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); +} + +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); }); +} \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/StringHelper.h b/ZAPDTR/ZAPDUtils/Utils/StringHelper.h new file mode 100644 index 000000000..b737a2fe7 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/StringHelper.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +class StringHelper +{ +public: + static std::vector Split(std::string 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& 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 IEquals(const std::string& a, const std::string& b); +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/vt.h b/ZAPDTR/ZAPDUtils/Utils/vt.h new file mode 100644 index 000000000..23f424442 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Utils/vt.h @@ -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 diff --git a/ZAPDTR/ZAPDUtils/Vec2f.h b/ZAPDTR/ZAPDUtils/Vec2f.h new file mode 100644 index 000000000..73e9259a8 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Vec2f.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +struct Vec2f +{ + float x, y; + + Vec2f() + { + x = 0; + y = 0; + }; + Vec2f(float nX, float nY) + { + x = nX; + y = nY; + }; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Vec3f.h b/ZAPDTR/ZAPDUtils/Vec3f.h new file mode 100644 index 000000000..d6e9c5568 --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Vec3f.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +struct Vec3f +{ + float x, y, z; + + Vec3f() + { + x = 0; + y = 0; + z = 0; + }; + Vec3f(float nX, float nY, float nZ) + { + x = nX; + y = nY; + z = nZ; + }; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Vec3s.h b/ZAPDTR/ZAPDUtils/Vec3s.h new file mode 100644 index 000000000..05816eddb --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Vec3s.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +struct Vec3s +{ + int16_t x, y, z; + + Vec3s() + { + x = 0; + y = 0; + z = 0; + }; + Vec3s(int16_t nX, int16_t nY, int16_t nZ) + { + x = nX; + y = nY; + z = nZ; + }; +}; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj b/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj new file mode 100644 index 000000000..dd49779dc --- /dev/null +++ b/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {a2e01c3e-d647-45d1-9788-043debc1a908} + ZAPDUtils + 10.0 + + + + StaticLibrary + false + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + MultiByte + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + MaxSpeed + Speed + Default + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Default + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj.filters b/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj.filters new file mode 100644 index 000000000..218084e6d --- /dev/null +++ b/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj.filters @@ -0,0 +1,87 @@ + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {d8c2c1e7-b065-4b0f-86a2-46ab46eedc0b} + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {e047919d-7186-49ca-b115-e48fbb5c8743} + + + {3de9dd46-0dfd-4d48-9f20-9f24e5b80fe0} + + + + + Header Files\Utils + + + Header Files\Utils + + + Header Files\Utils + + + Header Files\Utils + + + Header Files\Utils + + + Header Files\Utils + + + Header Files\Utils + + + Header Files\Utils + + + Header Files + + + Header Files\Utils + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Header Files\Source Files\Utils + + + Header Files\Source Files\Utils + + + Header Files\Source Files\Utils + + + Header Files\Source Files\Libraries + + + Header Files\Source Files\Utils + + + \ No newline at end of file diff --git a/ZAPDTR/copycheck.py b/ZAPDTR/copycheck.py new file mode 100755 index 000000000..36288f685 --- /dev/null +++ b/ZAPDTR/copycheck.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 + +import os +from shutil import copyfile + +if (os.environ.get('ZAPD_COPYDIR') != None): + print("Copying ZAPD.out to repo...") + #print(os.environ.get('ZAPD_COPYDIR')) + copyfile("ZAPD.out", os.environ.get('ZAPD_COPYDIR') + "/ZAPD.out") diff --git a/ZAPDTR/docs/zapd_extraction_xml_reference.md b/ZAPDTR/docs/zapd_extraction_xml_reference.md new file mode 100644 index 000000000..06b95bb57 --- /dev/null +++ b/ZAPDTR/docs/zapd_extraction_xml_reference.md @@ -0,0 +1,639 @@ +# ZAPD extraction XML reference + +This document aims to be a small reference of how to create a compatible xml file for ZAPD. + +## Table of contents + +- [ZAPD extraction XML reference](#zapd-extraction-xml-reference) + - [Table of contents](#table-of-contents) + - [Basic XML](#basic-xml) + - [Resources types](#resources-types) + - [File](#file) + - [Texture](#texture) + - [Background](#background) + - [Blob](#blob) + - [DList](#dlist) + - [TextureAnimation](#textureanimation) + - [Scene and Room](#scene-and-room) + - [AltHeader](#altheader) + - [Animation](#animation) + - [PlayerAnimation](#playeranimation) + - [CurveAnimation](#curveanimation) + - [LegacyAnimation](#legacyanimation) + - [Skeleton](#skeleton) + - [LimbTable](#limbtable) + - [Limb](#limb) + - [Symbol](#symbol) + - [Collision](#collision) + - [Scalar](#scalar) + - [Vector](#vector) + - [Vtx](#vtx) + - [Mtx](#mtx) + - [Cutscene](#cutscene) + - [Array](#array) + - [Path](#path) + - [PlayerAnimationData](#playeranimationdata) + +## Basic XML + +An example of an object xml: + +```xml + + + + + + + + + + + + + + + + + + + +``` + +Every xml must have a `` tag. It must have at least one `` child. + +## Resources types + +The following is a list of the resources/tags supported by ZAPD, and the attributes needed by each one. + +For most resources inside a `` tag **you should also set an `Offset` attribute**. This is the offset (within the file) of the resource you are exporting. The `Offset` attribute is expected to be in hexadecimal, for example `Offset="0x41F0"`. + +It's worth noting that every tag expects a `Name="gNameOfTheAsset"`. This is will be the name of the extracted variable in the output C code. Every asset must be prefixed with `g` and the suffix should represent the type of the variable. + +Every tag can accept a `Static` attribute to specify if the asset should be marked as `static` or not. +There are 3 valid values (defaults to `Global`): + +- `Global`: Mark static if the flag `--static` was used. +- `On`: Override the global config and **always mark** as `static`. +- `Off`: Override the global config and **don't mark** as `static`. + +This table summarizes if the asset will be marked `static` (✅) or not (❌) +| `Static=""` attribute in XML | Without `--static` flag | With `--static` flag | +| ---------------------------- | ----------------------- | -------------------- | +| `On` | ✅ | ✅ | +| `Global` (default) | ❌ | ✅ | +| `Off` | ❌ | ❌ | + +------------------------- + +### File + +- Example of this tag: + +```xml + +``` + +- Attributes: + + - `Name`: Required. The name of the file in `baserom/` which will be extracted. + - `OutName`: Optional. The output name of the generated C source file. Defaults to the value passed to `Name`. + - `Segment`: Optional. This is the segment number of the current file. Expects a decimal number between 0 and 15 inclusive, usually 6 if it is an object. If not specified, the file will use VRAM instead of segmented addresses. + - `BaseAddress`: Optional. RAM address of the file. Expects a hex number (with `0x` prefix). Default value: `0`. + - `RangeStart`: Optional. File offset where the extraction will begin. Hex. Default value: `0x000000000`. + - `RangeEnd`: Optional. File offset where the extraction will end. Hex. Default value: `0xFFFFFFFF`. + - `Game`: Optional. Valid values: `OOT`, `MM`, `SW97` and `OOTSW97`. Default value: `OOT`. + +------------------------- + +### ExternalFile + +Allows ZAPD to map segmented addresses to variables declared in other files by using its XML. + +It is useful for objects that use variables from `gameplay_keep`, `gameplay_dangeon_keep`, `gameplay_field_keep`, etc. + +This tag can be used in the global `config.xml` file. + +- Example of this tag: + +```xml + +``` + +- Attributes: + + - `XmlPath`: Required. The path of the XML, relative to the value set by `ExternalXMLFolder` in the configuration file. + - `OutPath`: Required. The path were the header for the corresponding external file is. It is used to `#include` it in the generated `.c` file. + +------------------------- + +### Texture + +Textures are extracted as `.png` files. + +- Example: + +```xml + +``` + +Will be defined as: + +```c +u64 gCraterSmokeConeTex[] = { +#include "assets/objects/object_spot17_obj/crater_smoke_cone.ia8.inc.c" +}; +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Tex`, unless it is a palette, in that case it is suffixed by `TLUT`. + - `OutName`: Required. The filename of the extracted `.png` file. + - `Format`: Required. The format of the image. Valid values: `rgba32`, `rgba16`, `i4`, `i8`, `ia4`, `ia8`, `ia16`, `ci4` and `ci8`. + - `Width`: Required. Width in pixels of the image. + - `Height`: Required. Height in pixels of the image. + - `TlutOffset`: Optional. Specifies the tlut's offset used by this texture. This attribute is only valid if `Format` is either `ci4` or `ci8`, otherwise an exception would be thrown. + +The following is a list of the texture formats the Nintendo 64 supports, with their gfxdis names and ZAPD format names. + +| Format name | Typing in `gsDPLoadTextureBlock` | "Format" in xml | +| ----------------------------------------------- | -------------------------------- | --------------- | +| 4-bit intensity (I) | `G_IM_FMT_I, G_IM_SIZ_4b` | `i4` | +| 4-bit intensity with alpha (I/A) (3/1) | `G_IM_FMT_IA, G_IM_SIZ_4b` | `ia4` | +| 4-bit color index (CI) | `G_IM_FMT_CI, G_IM_SIZ_4b` | `ci4` | +| 8-bit I | `G_IM_FMT_I, G_IM_SIZ_8b` | `i8` | +| 8-bit IA (4/4) | `G_IM_FMT_IA, G_IM_SIZ_8b` | `ia8` | +| 8-bit CI | `G_IM_FMT_CI, G_IM_SIZ_8b` | `ci8` | +| 16-bit red, green, blue, alpha (RGBA) (5/5/5/1) | `G_IM_FMT_RGBA, G_IM_SIZ_16b` | `rgba16` | +| 16-bit IA (8/8) | `G_IM_FMT_IA, G_IM_SIZ_16b` | `ia16` | +| 16-bit YUV (Luminance, Blue-Y, Red-Y) | `G_IM_FMT_YUV, G_IM_SIZ_16b` | (not used) | +| 32-bit RGBA (8/8/8/8) | `G_IM_FMT_RGBA, G_IM_SIZ_32b` | `rgba32` | + +If you want to know more about this formats, you can check [`gsDPLoadTextureBlock`](http://n64devkit.square7.ch/n64man/gdp/gDPLoadTextureBlock.htm) for most formats, or [`gDPLoadTextureBlock_4b`](http://n64devkit.square7.ch/n64man/gdp/gDPLoadTextureBlock_4b.htm) for the 4-bit formats. + +------------------------- + +### Background + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Background`. + - `OutName`: Required. The filename of the extracted `.jpg` file. + +※ Explicit use of this tag isn't often necesary because it would probably be extracted automatically by another extracted element. You can use this to name them if you don't like the autogenerated name. + +------------------------- + +### Blob + +Blob are binary data that will be extracted as `.bin` files. + +- Example: + +```xml + +``` + +Will be defined as: + +```c + +u8 gFireTempleBlob_00CCC0[] = { +#include "assets/objects/object_hidan_objects/gFireTempleBlob_00CCC0.bin.inc.c" +}; +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Blob`. + - `Size`: Required. Amount of bytes to extract. Hex. + +※ We usually use blobs when we can't figure out the content's type of chunk of data. + +------------------------- + +### DList + +A.k.a. Display list, or Gfx. + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `DL`. + +------------------------- + +### TextureAnimation + +A data type exclusive to Majora's Mask, that has scrolling, color changing, and texture changing capabilities. Declaring the main array will generate everything else; textures for the TextureCycle type must be declared manually in the XML to use symbols. (If it does reference any undeclared textures, ZAPD will warn and give the their offsets.) + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `TexAnim`. + +------------------------- + +### Scene and Room + +`Scene`s and `Room`s are a bit special, because `Room`s usually needs assets declared in their respective `Scene` (which is in a different file), so they need to be extracted together. + +To accomplish this, the scene and each of their rooms must be declared in the same XML. + +- Example: + +```xml + + + + + + + + + + + + + + +``` + +- Attributes: + + - `HackMode`: Optional. This is a simple non-hardcoded way to handle some edge cases. Valid values: `syotes_room`. + +------------------------- + +### AltHeader + +Like `Scene`s and `Room`s, `AltHeader`s is special too. It should always be declared in the same `File` as a `Scene` or a `Room`. + +- Example: + +```xml + + + + + + + + + + + + + + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `AltHeader`. + +------------------------- + +### Animation + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Anim`. + +------------------------- + +### PlayerAnimation + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Anim`. + +------------------------- + +### CurveAnimation + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Anim`. + - `SkelOffset`: Required. Offset of the `CurveSkeleton` (I.e. a [`Skeleton`](#skeleton) resource with `Type="Curve"`) related to this animation. + +------------------------- + +### LegacyAnimation + +Useful only for the unused `object_human`'s animation data. + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Anim`. + +------------------------- + +### Skeleton + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Skel`. + - `Type`: Required. Valid values: `Normal`, `Flex` and `Curve`. + - `LimbType`: Required. Valid values: `Standard`, `LOD`, `Skin`, `Curve` and `Legacy`. + +※ There are no restrictions in the `Type` and `LimbType` attributes besides the valid values, so any skeleton type can be combined with any limb type. + +------------------------- + +### LimbTable + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Skel`. + - `LimbType`: Required. Valid values: `Standard`, `LOD`, `Skin`, `Curve` and `Legacy`. + - `Count`: Required. Amount of limbs. Integer. + +------------------------- + +### Limb + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Limb`. + - `LimbType`: Required. Valid values: `Standard`, `LOD`, `Skin`, `Curve` and `Legacy`. + +------------------------- + +### Symbol + +A special element that allows declaring a variable without actually extracting it from the current file. Useful when a resource references an element from another file. The symbol will be declared as `extern`. + +- Example: + +```xml + +``` + +Will be declared as: + +```c +extern u8 gJsjutanShadowTex[2048]; +``` + +- Attributes: + + - `Type`: The type of the declared variable. If missing, it will default to `void*`. + - `TypeSize`: The size in bytes of the type. If missing, it will default to `4` (the size of a word and a pointer). Integer or hex value. + - `Count`: Optional. If it is present, the variable will be declared as an array instead of a plain variable. The value of this attribute specifies the length of the array. If `Count` is present but it has no value (`Count=""`), then the length of the array will not be specified either in the declared variable. Integer or hex value. + - `Static`: This attribute can't be enabled on a Symbol node. A warning will be showed in this case. + +------------------------- + +### Collision + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Col`. + +------------------------- + +### Scalar + +Allows the extraction of a single number. + +- Example: + +```xml + +``` + +Will be extracted as: + +```c +u64 pad34F8 = { 0 }; +``` + +- Attributes: + + - `Name`: Required. Suxffixed by ~~`TBD`~~. + - `Type`: Required. Valid values: `s8`, `u8`, `x8`, `s16`, `u16`, `x16`, `s32`, `u32`, `x32`, `s64`, `u64`, `x64`, `f32` and `f64`. + +※ Can be wrapped in an [`Array`](#array) tag. + +------------------------- + +### Vector + +Extracts a vector. + +Current supported types are `Vec3s`, `Vec3i` or `Vec3f`. + +- Example: + +```xml + + + +``` + +Will be extracted as: + +```c +Vec3s D_04002040[24] = { + { -37, 2346, 93 }, + { 0, 11995, 0 }, + { -16385, -305, -16333 }, + { 0, 51, 12 }, + { 3761, 2263, -384 }, + { 0, 0, 3786 }, + { 1594, 1384, -18344 }, + { -2288, -2428, -1562 }, + { 0, 0, 3219 }, + { -2148, -5, -16840 }, + { 15365, -1708, 15611 }, + { 1761, 8365, 17711 }, + { 0, 0, 18859 }, + { 0, 0, 0 }, + { -9392, -9579, 28686 }, + { 0, 0, -7093 }, + { -2748, 685, -14092 }, + { 213, 6553, -32212 }, + { 0, 0, -1877 }, + { 3267, 3309, -16090 }, + { -18101, 25946, -2670 }, + { -104, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 } +}; +``` + +- Attributes: + + - `Name`: Required. Suxffixed by ~~`TBD`~~. + - `Type`: Required. Specifies the vector's type (`Vec3s`, `Vec3i` and `Vec3f`). Valid values: `s16`, `s32` and `f32`. + - `Dimensions`: Required. The amount of dimensions of the vector. Valid values: `3`. + +※ Can be wrapped in an [`Array`](#array) tag. + +------------------------- + +### Vtx + +- Example: + +```xml + + + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Vtx`. + +※ Can be wrapped in an [`Array`](#array) tag. + +------------------------- + +### Mtx + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Mtx`. + +※ Explicit use of this tag isn't often necesary because it would probably be extracted automatically by another extracted element. + +------------------------- + +### Cutscene + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Cs`. + +※ Explicit use of this tag isn't often necesary because it would probably be extracted automatically by another extracted element. + +------------------------- + +### Array + +The `Array` element is special, because it needs an inner element to work. It will declare an array of its inner element. + +Currently, only [`Scalar`](#scalar), [`Vector`](#vector) and [`Vtx`](#vtx) support being wrapped in an array. + +- Example: + +```xml + + + +``` + +- Attributes: + + - `Name`: Required. How the variable will be named. By our convention it should be prefixed by `g`. The sufix is mandated by the element contained. + - `Count`: Required. Amount of elements. Integer. + +------------------------- + +### Path + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `Path`. + - `NumPaths`: Optional. The amount of paths contained in the array. It must be a positive integer. + +------------------------- + +### PlayerAnimationData + +Allows the extraction of the specific data of the player animations which are found in the `link_animetion` file. + +- Example: + +```xml + +``` + +- Attributes: + + - `Name`: Required. Suxffixed by `AnimData`. + - `FrameCount`: Required. The length of the animation in frames. It must be a positive integer. + +------------------------- diff --git a/ZAPDTR/docs/zapd_warning_example.png b/ZAPDTR/docs/zapd_warning_example.png new file mode 100644 index 000000000..a001c64d6 Binary files /dev/null and b/ZAPDTR/docs/zapd_warning_example.png differ diff --git a/ZAPDTR/docs/zapd_xml_spec.md b/ZAPDTR/docs/zapd_xml_spec.md new file mode 100644 index 000000000..9fcc0d4aa --- /dev/null +++ b/ZAPDTR/docs/zapd_xml_spec.md @@ -0,0 +1,55 @@ +# ZAPD XML specification + +ZAPD XMLs use a restrictive subset of the XML standard: any ZAPD XML must be a valid XML (All elements starting with `` ending appropriately with ``, single "empty-element" tags with `/` at the end, etc.). + +Reminder that in + +```xml + + + + + + + + + +``` + +``, ``, `` are *children* of ``, but `` is not. `` is a *descendent* of `` and a child of ``. + +- Every XML's outermost element start/end tag is a single ``. +- The children of a `` must be ``s. +- A `` has *resources* as children. A resource is almost always single empty-element tag, and has one of the types + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + +- A `` cannot descend from a ``. +- All resources must be children of a ``. +- `` is the only paired resource tag enclosing an element; the element must be a single resource tag, one of + - `` + - `` + - `` diff --git a/ZAPDTR/lib/elfio/elfio/elf_types.hpp b/ZAPDTR/lib/elfio/elfio/elf_types.hpp new file mode 100644 index 000000000..63d025a58 --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elf_types.hpp @@ -0,0 +1,851 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFTYPES_H +#define ELFTYPES_H + +#ifndef ELFIO_NO_OWN_TYPES + #if !defined(ELFIO_NO_CSTDINT) && !defined(ELFIO_NO_INTTYPES) + #include + #else + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned short uint16_t; + typedef signed short int16_t; + #ifdef _MSC_VER + typedef unsigned __int32 uint32_t; + typedef signed __int32 int32_t; + typedef unsigned __int64 uint64_t; + typedef signed __int64 int64_t; + #else + typedef unsigned int uint32_t; + typedef signed int int32_t; + typedef unsigned long long uint64_t; + typedef signed long long int64_t; + #endif // _MSC_VER + #endif // ELFIO_NO_CSTDINT +#endif // ELFIO_NO_OWN_TYPES + +namespace ELFIO { + +// Attention! Platform depended definitions. +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef int32_t Elf_Sword; +typedef uint64_t Elf_Xword; +typedef int64_t Elf_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; + +#define Elf32_Half Elf_Half +#define Elf64_Half Elf_Half +#define Elf32_Word Elf_Word +#define Elf64_Word Elf_Word +#define Elf32_Sword Elf_Sword +#define Elf64_Sword Elf_Sword + +/////////////////////// +// ELF Header Constants + +// File type +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOOS 0xFE00 +#define ET_HIOS 0xFEFF +#define ET_LOPROC 0xFF00 +#define ET_HIPROC 0xFFFF + + +#define EM_NONE 0 // No machine +#define EM_M32 1 // AT&T WE 32100 +#define EM_SPARC 2 // SUN SPARC +#define EM_386 3 // Intel 80386 +#define EM_68K 4 // Motorola m68k family +#define EM_88K 5 // Motorola m88k family +#define EM_486 6 // Intel 80486// Reserved for future use +#define EM_860 7 // Intel 80860 +#define EM_MIPS 8 // MIPS R3000 (officially, big-endian only) +#define EM_S370 9 // IBM System/370 +#define EM_MIPS_RS3_LE 10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated +#define EM_res011 11 // Reserved +#define EM_res012 12 // Reserved +#define EM_res013 13 // Reserved +#define EM_res014 14 // Reserved +#define EM_PARISC 15 // HPPA +#define EM_res016 16 // Reserved +#define EM_VPP550 17 // Fujitsu VPP500 +#define EM_SPARC32PLUS 18 // Sun's "v8plus" +#define EM_960 19 // Intel 80960 +#define EM_PPC 20 // PowerPC +#define EM_PPC64 21 // 64-bit PowerPC +#define EM_S390 22 // IBM S/390 +#define EM_SPU 23 // Sony/Toshiba/IBM SPU +#define EM_res024 24 // Reserved +#define EM_res025 25 // Reserved +#define EM_res026 26 // Reserved +#define EM_res027 27 // Reserved +#define EM_res028 28 // Reserved +#define EM_res029 29 // Reserved +#define EM_res030 30 // Reserved +#define EM_res031 31 // Reserved +#define EM_res032 32 // Reserved +#define EM_res033 33 // Reserved +#define EM_res034 34 // Reserved +#define EM_res035 35 // Reserved +#define EM_V800 36 // NEC V800 series +#define EM_FR20 37 // Fujitsu FR20 +#define EM_RH32 38 // TRW RH32 +#define EM_MCORE 39 // Motorola M*Core // May also be taken by Fujitsu MMA +#define EM_RCE 39 // Old name for MCore +#define EM_ARM 40 // ARM +#define EM_OLD_ALPHA 41 // Digital Alpha +#define EM_SH 42 // Renesas (formerly Hitachi) / SuperH SH +#define EM_SPARCV9 43 // SPARC v9 64-bit +#define EM_TRICORE 44 // Siemens Tricore embedded processor +#define EM_ARC 45 // ARC Cores +#define EM_H8_300 46 // Renesas (formerly Hitachi) H8/300 +#define EM_H8_300H 47 // Renesas (formerly Hitachi) H8/300H +#define EM_H8S 48 // Renesas (formerly Hitachi) H8S +#define EM_H8_500 49 // Renesas (formerly Hitachi) H8/500 +#define EM_IA_64 50 // Intel IA-64 Processor +#define EM_MIPS_X 51 // Stanford MIPS-X +#define EM_COLDFIRE 52 // Motorola Coldfire +#define EM_68HC12 53 // Motorola M68HC12 +#define EM_MMA 54 // Fujitsu Multimedia Accelerator +#define EM_PCP 55 // Siemens PCP +#define EM_NCPU 56 // Sony nCPU embedded RISC processor +#define EM_NDR1 57 // Denso NDR1 microprocesspr +#define EM_STARCORE 58 // Motorola Star*Core processor +#define EM_ME16 59 // Toyota ME16 processor +#define EM_ST100 60 // STMicroelectronics ST100 processor +#define EM_TINYJ 61 // Advanced Logic Corp. TinyJ embedded processor +#define EM_X86_64 62 // Advanced Micro Devices X86-64 processor +#define EM_PDSP 63 // Sony DSP Processor +#define EM_PDP10 64 // Digital Equipment Corp. PDP-10 +#define EM_PDP11 65 // Digital Equipment Corp. PDP-11 +#define EM_FX66 66 // Siemens FX66 microcontroller +#define EM_ST9PLUS 67 // STMicroelectronics ST9+ 8/16 bit microcontroller +#define EM_ST7 68 // STMicroelectronics ST7 8-bit microcontroller +#define EM_68HC16 69 // Motorola MC68HC16 Microcontroller +#define EM_68HC11 70 // Motorola MC68HC11 Microcontroller +#define EM_68HC08 71 // Motorola MC68HC08 Microcontroller +#define EM_68HC05 72 // Motorola MC68HC05 Microcontroller +#define EM_SVX 73 // Silicon Graphics SVx +#define EM_ST19 74 // STMicroelectronics ST19 8-bit cpu +#define EM_VAX 75 // Digital VAX +#define EM_CRIS 76 // Axis Communications 32-bit embedded processor +#define EM_JAVELIN 77 // Infineon Technologies 32-bit embedded cpu +#define EM_FIREPATH 78 // Element 14 64-bit DSP processor +#define EM_ZSP 79 // LSI Logic's 16-bit DSP processor +#define EM_MMIX 80 // Donald Knuth's educational 64-bit processor +#define EM_HUANY 81 // Harvard's machine-independent format +#define EM_PRISM 82 // SiTera Prism +#define EM_AVR 83 // Atmel AVR 8-bit microcontroller +#define EM_FR30 84 // Fujitsu FR30 +#define EM_D10V 85 // Mitsubishi D10V +#define EM_D30V 86 // Mitsubishi D30V +#define EM_V850 87 // NEC v850 +#define EM_M32R 88 // Renesas M32R (formerly Mitsubishi M32R) +#define EM_MN10300 89 // Matsushita MN10300 +#define EM_MN10200 90 // Matsushita MN10200 +#define EM_PJ 91 // picoJava +#define EM_OPENRISC 92 // OpenRISC 32-bit embedded processor +#define EM_ARC_A5 93 // ARC Cores Tangent-A5 +#define EM_XTENSA 94 // Tensilica Xtensa Architecture +#define EM_VIDEOCORE 95 // Alphamosaic VideoCore processor +#define EM_TMM_GPP 96 // Thompson Multimedia General Purpose Processor +#define EM_NS32K 97 // National Semiconductor 32000 series +#define EM_TPC 98 // Tenor Network TPC processor +#define EM_SNP1K 99 // Trebia SNP 1000 processor +#define EM_ST200 100 // STMicroelectronics ST200 microcontroller +#define EM_IP2K 101 // Ubicom IP2022 micro controller +#define EM_MAX 102 // MAX Processor +#define EM_CR 103 // National Semiconductor CompactRISC +#define EM_F2MC16 104 // Fujitsu F2MC16 +#define EM_MSP430 105 // TI msp430 micro controller +#define EM_BLACKFIN 106 // ADI Blackfin +#define EM_SE_C33 107 // S1C33 Family of Seiko Epson processors +#define EM_SEP 108 // Sharp embedded microprocessor +#define EM_ARCA 109 // Arca RISC Microprocessor +#define EM_UNICORE 110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University +#define EM_EXCESS 111 // eXcess: 16/32/64-bit configurable embedded CPU +#define EM_DXP 112 // Icera Semiconductor Inc. Deep Execution Processor +#define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor +#define EM_CRX 114 // National Semiconductor CRX +#define EM_XGATE 115 // Motorola XGATE embedded processor +#define EM_C166 116 // Infineon C16x/XC16x processor +#define EM_M16C 117 // Renesas M16C series microprocessors +#define EM_DSPIC30F 118 // Microchip Technology dsPIC30F Digital Signal Controller +#define EM_CE 119 // Freescale Communication Engine RISC core +#define EM_M32C 120 // Renesas M32C series microprocessors +#define EM_res121 121 // Reserved +#define EM_res122 122 // Reserved +#define EM_res123 123 // Reserved +#define EM_res124 124 // Reserved +#define EM_res125 125 // Reserved +#define EM_res126 126 // Reserved +#define EM_res127 127 // Reserved +#define EM_res128 128 // Reserved +#define EM_res129 129 // Reserved +#define EM_res130 130 // Reserved +#define EM_TSK3000 131 // Altium TSK3000 core +#define EM_RS08 132 // Freescale RS08 embedded processor +#define EM_res133 133 // Reserved +#define EM_ECOG2 134 // Cyan Technology eCOG2 microprocessor +#define EM_SCORE 135 // Sunplus Score +#define EM_SCORE7 135 // Sunplus S+core7 RISC processor +#define EM_DSP24 136 // New Japan Radio (NJR) 24-bit DSP Processor +#define EM_VIDEOCORE3 137 // Broadcom VideoCore III processor +#define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture +#define EM_SE_C17 139 // Seiko Epson C17 family +#define EM_TI_C6000 140 // Texas Instruments TMS320C6000 DSP family +#define EM_TI_C2000 141 // Texas Instruments TMS320C2000 DSP family +#define EM_TI_C5500 142 // Texas Instruments TMS320C55x DSP family +#define EM_res143 143 // Reserved +#define EM_res144 144 // Reserved +#define EM_res145 145 // Reserved +#define EM_res146 146 // Reserved +#define EM_res147 147 // Reserved +#define EM_res148 148 // Reserved +#define EM_res149 149 // Reserved +#define EM_res150 150 // Reserved +#define EM_res151 151 // Reserved +#define EM_res152 152 // Reserved +#define EM_res153 153 // Reserved +#define EM_res154 154 // Reserved +#define EM_res155 155 // Reserved +#define EM_res156 156 // Reserved +#define EM_res157 157 // Reserved +#define EM_res158 158 // Reserved +#define EM_res159 159 // Reserved +#define EM_MMDSP_PLUS 160 // STMicroelectronics 64bit VLIW Data Signal Processor +#define EM_CYPRESS_M8C 161 // Cypress M8C microprocessor +#define EM_R32C 162 // Renesas R32C series microprocessors +#define EM_TRIMEDIA 163 // NXP Semiconductors TriMedia architecture family +#define EM_QDSP6 164 // QUALCOMM DSP6 Processor +#define EM_8051 165 // Intel 8051 and variants +#define EM_STXP7X 166 // STMicroelectronics STxP7x family +#define EM_NDS32 167 // Andes Technology compact code size embedded RISC processor family +#define EM_ECOG1 168 // Cyan Technology eCOG1X family +#define EM_ECOG1X 168 // Cyan Technology eCOG1X family +#define EM_MAXQ30 169 // Dallas Semiconductor MAXQ30 Core Micro-controllers +#define EM_XIMO16 170 // New Japan Radio (NJR) 16-bit DSP Processor +#define EM_MANIK 171 // M2000 Reconfigurable RISC Microprocessor +#define EM_CRAYNV2 172 // Cray Inc. NV2 vector architecture +#define EM_RX 173 // Renesas RX family +#define EM_METAG 174 // Imagination Technologies META processor architecture +#define EM_MCST_ELBRUS 175 // MCST Elbrus general purpose hardware architecture +#define EM_ECOG16 176 // Cyan Technology eCOG16 family +#define EM_CR16 177 // National Semiconductor CompactRISC 16-bit processor +#define EM_ETPU 178 // Freescale Extended Time Processing Unit +#define EM_SLE9X 179 // Infineon Technologies SLE9X core +#define EM_L1OM 180 // Intel L1OM +#define EM_INTEL181 181 // Reserved by Intel +#define EM_INTEL182 182 // Reserved by Intel +#define EM_res183 183 // Reserved by ARM +#define EM_res184 184 // Reserved by ARM +#define EM_AVR32 185 // Atmel Corporation 32-bit microprocessor family +#define EM_STM8 186 // STMicroeletronics STM8 8-bit microcontroller +#define EM_TILE64 187 // Tilera TILE64 multicore architecture family +#define EM_TILEPRO 188 // Tilera TILEPro multicore architecture family +#define EM_MICROBLAZE 189 // Xilinx MicroBlaze 32-bit RISC soft processor core +#define EM_CUDA 190 // NVIDIA CUDA architecture +#define EM_TILEGX 191 // Tilera TILE-Gx multicore architecture family +#define EM_CLOUDSHIELD 192 // CloudShield architecture family +#define EM_COREA_1ST 193 // KIPO-KAIST Core-A 1st generation processor family +#define EM_COREA_2ND 194 // KIPO-KAIST Core-A 2nd generation processor family +#define EM_ARC_COMPACT2 195 // Synopsys ARCompact V2 +#define EM_OPEN8 196 // Open8 8-bit RISC soft processor core +#define EM_RL78 197 // Renesas RL78 family +#define EM_VIDEOCORE5 198 // Broadcom VideoCore V processor +#define EM_78KOR 199 // Renesas 78KOR family +#define EM_56800EX 200 // Freescale 56800EX Digital Signal Controller (DSC) +#define EM_BA1 201 // Beyond BA1 CPU architecture +#define EM_BA2 202 // Beyond BA2 CPU architecture +#define EM_XCORE 203 // XMOS xCORE processor family +#define EM_MCHP_PIC 204 // Microchip 8-bit PIC(r) family +#define EM_INTEL205 205 // Reserved by Intel +#define EM_INTEL206 206 // Reserved by Intel +#define EM_INTEL207 207 // Reserved by Intel +#define EM_INTEL208 208 // Reserved by Intel +#define EM_INTEL209 209 // Reserved by Intel +#define EM_KM32 210 // KM211 KM32 32-bit processor +#define EM_KMX32 211 // KM211 KMX32 32-bit processor +#define EM_KMX16 212 // KM211 KMX16 16-bit processor +#define EM_KMX8 213 // KM211 KMX8 8-bit processor +#define EM_KVARC 214 // KM211 KVARC processor +#define EM_CDP 215 // Paneve CDP architecture family +#define EM_COGE 216 // Cognitive Smart Memory Processor +#define EM_COOL 217 // iCelero CoolEngine +#define EM_NORC 218 // Nanoradio Optimized RISC +#define EM_CSR_KALIMBA 219 // CSR Kalimba architecture family +#define EM_Z80 220 // Zilog Z80 +#define EM_VISIUM 221 // Controls and Data Services VISIUMcore processor +#define EM_FT32 222 // FTDI Chip FT32 high performance 32-bit RISC architecture +#define EM_MOXIE 223 // Moxie processor family +#define EM_AMDGPU 224 // AMD GPU architecture +#define EM_RISCV 243 // RISC-V +#define EM_LANAI 244 // Lanai processor +#define EM_CEVA 245 // CEVA Processor Architecture Family +#define EM_CEVA_X2 246 // CEVA X2 Processor Family +#define EM_BPF 247 // Linux BPF – in-kernel virtual machine + +// File version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// Identification index +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +// Magic number +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// File class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// Encoding +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// OS extensions +#define ELFOSABI_NONE 0 // No extensions or unspecified +#define ELFOSABI_HPUX 1 // Hewlett-Packard HP-UX +#define ELFOSABI_NETBSD 2 // NetBSD +#define ELFOSABI_LINUX 3 // Linux +#define ELFOSABI_SOLARIS 6 // Sun Solaris +#define ELFOSABI_AIX 7 // AIX +#define ELFOSABI_IRIX 8 // IRIX +#define ELFOSABI_FREEBSD 9 // FreeBSD +#define ELFOSABI_TRU64 10 // Compaq TRU64 UNIX +#define ELFOSABI_MODESTO 11 // Novell Modesto +#define ELFOSABI_OPENBSD 12 // Open BSD +#define ELFOSABI_OPENVMS 13 // Open VMS +#define ELFOSABI_NSK 14 // Hewlett-Packard Non-Stop Kernel +#define ELFOSABI_AROS 15 // Amiga Research OS +#define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS +// 64-255 Architecture-specific value range +#define ELFOSABI_AMDGPU_HSA 64 // AMDGPU OS for HSA compatible compute + // kernels. +#define ELFOSABI_AMDGPU_PAL 65 // AMDGPU OS for AMD PAL compatible graphics + // shaders and compute kernels. +#define ELFOSABI_AMDGPU_MESA3D 66 // AMDGPU OS for Mesa3D compatible graphics + // shaders and compute kernels. + + +// AMDGPU specific e_flags +#define EF_AMDGPU_MACH 0x0ff // AMDGPU processor selection mask. +#define EF_AMDGPU_XNACK 0x100 // Indicates if the XNACK target feature is + // enabled for all code contained in the ELF. +// AMDGPU processors +#define EF_AMDGPU_MACH_NONE 0x000 // Unspecified processor. +#define EF_AMDGPU_MACH_R600_R600 0x001 +#define EF_AMDGPU_MACH_R600_R630 0x002 +#define EF_AMDGPU_MACH_R600_RS880 0x003 +#define EF_AMDGPU_MACH_R600_RV670 0x004 +#define EF_AMDGPU_MACH_R600_RV710 0x005 +#define EF_AMDGPU_MACH_R600_RV730 0x006 +#define EF_AMDGPU_MACH_R600_RV770 0x007 +#define EF_AMDGPU_MACH_R600_CEDAR 0x008 +#define EF_AMDGPU_MACH_R600_CYPRESS 0x009 +#define EF_AMDGPU_MACH_R600_JUNIPER 0x00a +#define EF_AMDGPU_MACH_R600_REDWOOD 0x00b +#define EF_AMDGPU_MACH_R600_SUMO 0x00c +#define EF_AMDGPU_MACH_R600_BARTS 0x00d +#define EF_AMDGPU_MACH_R600_CAICOS 0x00e +#define EF_AMDGPU_MACH_R600_CAYMAN 0x00f +#define EF_AMDGPU_MACH_R600_TURKS 0x010 +#define EF_AMDGPU_MACH_R600_RESERVED_FIRST 0x011 +#define EF_AMDGPU_MACH_R600_RESERVED_LAST 0x01f +#define EF_AMDGPU_MACH_R600_FIRST EF_AMDGPU_MACH_R600_R600 +#define EF_AMDGPU_MACH_R600_LAST EF_AMDGPU_MACH_R600_TURKS +#define EF_AMDGPU_MACH_AMDGCN_GFX600 0x020 +#define EF_AMDGPU_MACH_AMDGCN_GFX601 0x021 +#define EF_AMDGPU_MACH_AMDGCN_GFX700 0x022 +#define EF_AMDGPU_MACH_AMDGCN_GFX701 0x023 +#define EF_AMDGPU_MACH_AMDGCN_GFX702 0x024 +#define EF_AMDGPU_MACH_AMDGCN_GFX703 0x025 +#define EF_AMDGPU_MACH_AMDGCN_GFX704 0x026 +#define EF_AMDGPU_MACH_AMDGCN_GFX801 0x028 +#define EF_AMDGPU_MACH_AMDGCN_GFX802 0x029 +#define EF_AMDGPU_MACH_AMDGCN_GFX803 0x02a +#define EF_AMDGPU_MACH_AMDGCN_GFX810 0x02b +#define EF_AMDGPU_MACH_AMDGCN_GFX900 0x02c +#define EF_AMDGPU_MACH_AMDGCN_GFX902 0x02d +#define EF_AMDGPU_MACH_AMDGCN_GFX904 0x02e +#define EF_AMDGPU_MACH_AMDGCN_GFX906 0x02f +#define EF_AMDGPU_MACH_AMDGCN_RESERVED0 0x027 +#define EF_AMDGPU_MACH_AMDGCN_RESERVED1 0x030 +#define EF_AMDGPU_MACH_AMDGCN_FIRST EF_AMDGPU_MACH_AMDGCN_GFX600 +#define EF_AMDGPU_MACH_AMDGCN_LAST EF_AMDGPU_MACH_AMDGCN_GFX906 + +///////////////////// +// Sections constants + +// Section indexes +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_LOOS 0xFF20 +#define SHN_HIOS 0xFF3F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_XINDEX 0xFFFF +#define SHN_HIRESERVE 0xFFFF + +// Section types +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xFFFFFFFF + +// Section attribute flags +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MERGE 0x10 +#define SHF_STRINGS 0x20 +#define SHF_INFO_LINK 0x40 +#define SHF_LINK_ORDER 0x80 +#define SHF_OS_NONCONFORMING 0x100 +#define SHF_GROUP 0x200 +#define SHF_TLS 0x400 +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xF0000000 + +// Section group flags +#define GRP_COMDAT 0x1 +#define GRP_MASKOS 0x0ff00000 +#define GRP_MASKPROC 0xf0000000 + +// Symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOOS 10 +#define STB_HIOS 12 +#define STB_MULTIDEF 13 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// Note types +#define NT_AMDGPU_METADATA 1 +#define NT_AMD_AMDGPU_HSA_METADATA 10 +#define NT_AMD_AMDGPU_ISA 11 +#define NT_AMD_AMDGPU_PAL_METADATA 12 + +// Symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_LOOS 10 +#define STT_AMDGPU_HSA_KERNEL 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +// Symbol visibility +#define STV_DEFAULT 0 +#define STV_INTERNAL 1 +#define STV_HIDDEN 2 +#define STV_PROTECTED 3 + +// Undefined name +#define STN_UNDEF 0 + +// Relocation types +#define R_386_NONE 0 +#define R_X86_64_NONE 0 +#define R_AMDGPU_NONE 0 +#define R_386_32 1 +#define R_X86_64_64 1 +#define R_AMDGPU_ABS32_LO 1 +#define R_386_PC32 2 +#define R_X86_64_PC32 2 +#define R_AMDGPU_ABS32_HI 2 +#define R_386_GOT32 3 +#define R_X86_64_GOT32 3 +#define R_AMDGPU_ABS64 3 +#define R_386_PLT32 4 +#define R_X86_64_PLT32 4 +#define R_AMDGPU_REL32 4 +#define R_386_COPY 5 +#define R_X86_64_COPY 5 +#define R_AMDGPU_REL64 5 +#define R_386_GLOB_DAT 6 +#define R_X86_64_GLOB_DAT 6 +#define R_AMDGPU_ABS32 6 +#define R_386_JMP_SLOT 7 +#define R_X86_64_JUMP_SLOT 7 +#define R_AMDGPU_GOTPCREL 7 +#define R_386_RELATIVE 8 +#define R_X86_64_RELATIVE 8 +#define R_AMDGPU_GOTPCREL32_LO 8 +#define R_386_GOTOFF 9 +#define R_X86_64_GOTPCREL 9 +#define R_AMDGPU_GOTPCREL32_HI 9 +#define R_386_GOTPC 10 +#define R_X86_64_32 10 +#define R_AMDGPU_REL32_LO 10 +#define R_386_32PLT 11 +#define R_X86_64_32S 11 +#define R_AMDGPU_REL32_HI 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_AMDGPU_RELATIVE64 13 +#define R_386_TLS_TPOFF 14 +#define R_X86_64_8 14 +#define R_386_TLS_IE 15 +#define R_X86_64_PC8 15 +#define R_386_TLS_GOTIE 16 +#define R_X86_64_DTPMOD64 16 +#define R_386_TLS_LE 17 +#define R_X86_64_DTPOFF64 17 +#define R_386_TLS_GD 18 +#define R_X86_64_TPOFF64 18 +#define R_386_TLS_LDM 19 +#define R_X86_64_TLSGD 19 +#define R_386_16 20 +#define R_X86_64_TLSLD 20 +#define R_386_PC16 21 +#define R_X86_64_DTPOFF32 21 +#define R_386_8 22 +#define R_X86_64_GOTTPOFF 22 +#define R_386_PC8 23 +#define R_X86_64_TPOFF32 23 +#define R_386_TLS_GD_32 24 +#define R_X86_64_PC64 24 +#define R_386_TLS_GD_PUSH 25 +#define R_X86_64_GOTOFF64 25 +#define R_386_TLS_GD_CALL 26 +#define R_X86_64_GOTPC32 26 +#define R_386_TLS_GD_POP 27 +#define R_X86_64_GOT64 27 +#define R_386_TLS_LDM_32 28 +#define R_X86_64_GOTPCREL64 28 +#define R_386_TLS_LDM_PUSH 29 +#define R_X86_64_GOTPC64 29 +#define R_386_TLS_LDM_CALL 30 +#define R_X86_64_GOTPLT64 30 +#define R_386_TLS_LDM_POP 31 +#define R_X86_64_PLTOFF64 31 +#define R_386_TLS_LDO_32 32 +#define R_386_TLS_IE_32 33 +#define R_386_TLS_LE_32 34 +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_386_TLS_DTPMOD32 35 +#define R_X86_64_TLSDESC_CALL 35 +#define R_386_TLS_DTPOFF32 36 +#define R_X86_64_TLSDESC 36 +#define R_386_TLS_TPOFF32 37 +#define R_X86_64_IRELATIVE 37 +#define R_386_SIZE32 38 +#define R_386_TLS_GOTDESC 39 +#define R_386_TLS_DESC_CALL 40 +#define R_386_TLS_DESC 41 +#define R_386_IRELATIVE 42 +#define R_386_GOT32X 43 +#define R_X86_64_GNU_VTINHERIT 250 +#define R_X86_64_GNU_VTENTRY 251 + +// Segment types +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +// Segment flags +#define PF_X 1 // Execute +#define PF_W 2 // Write +#define PF_R 4 // Read +#define PF_MASKOS 0x0ff00000 // Unspecified +#define PF_MASKPROC 0xf0000000 // Unspecified + +// Dynamic Array Tags +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_MAXPOSTAGS 34 +#define DT_LOOS 0x6000000D +#define DT_HIOS 0x6ffff000 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +// DT_FLAGS values +#define DF_ORIGIN 0x1 +#define DF_SYMBOLIC 0x2 +#define DF_TEXTREL 0x4 +#define DF_BIND_NOW 0x8 +#define DF_STATIC_TLS 0x10 + + +// ELF file header +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + +struct Elf64_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + + +// Section header +struct Elf32_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf_Word sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Word sh_addralign; + Elf_Word sh_entsize; +}; + +struct Elf64_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf_Xword sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Xword sh_addralign; + Elf_Xword sh_entsize; +}; + + +// Segment header +struct Elf32_Phdr { + Elf_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf_Word p_filesz; + Elf_Word p_memsz; + Elf_Word p_flags; + Elf_Word p_align; +}; + +struct Elf64_Phdr { + Elf_Word p_type; + Elf_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf_Xword p_filesz; + Elf_Xword p_memsz; + Elf_Xword p_align; +}; + + +// Symbol table entry +struct Elf32_Sym { + Elf_Word st_name; + Elf32_Addr st_value; + Elf_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; +}; + +struct Elf64_Sym { + Elf_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; + Elf64_Addr st_value; + Elf_Xword st_size; +}; + + +#define ELF_ST_BIND(i) ((i)>>4) +#define ELF_ST_TYPE(i) ((i)&0xf) +#define ELF_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +#define ELF_ST_VISIBILITY(o) ((o)&0x3) + + +// Relocation entries +struct Elf32_Rel { + Elf32_Addr r_offset; + Elf_Word r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf_Word r_info; + Elf_Sword r_addend; +}; + +struct Elf64_Rel { + Elf64_Addr r_offset; + Elf_Xword r_info; +}; + +struct Elf64_Rela { + Elf64_Addr r_offset; + Elf_Xword r_info; + Elf_Sxword r_addend; +}; + + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) + +#define ELF64_R_SYM(i) ((i)>>32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) +#define ELF64_R_INFO(s,t) ((((int64_t)(s))<<32)+((t)&0xffffffffL)) + +// Dynamic structure +struct Elf32_Dyn { + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +struct Elf64_Dyn { + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +}; + +} // namespace ELFIO + +#endif // ELFTYPES_H diff --git a/ZAPDTR/lib/elfio/elfio/elfio.hpp b/ZAPDTR/lib/elfio/elfio/elfio.hpp new file mode 100644 index 000000000..f997b5dfc --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio.hpp @@ -0,0 +1,955 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_HPP +#define ELFIO_HPP + +#ifdef _MSC_VER +#pragma warning ( push ) +#pragma warning(disable:4996) +#pragma warning(disable:4355) +#pragma warning(disable:4244) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header? header->get_##FNAME() : 0; \ +} + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header? header->get_##FNAME() : 0; \ +} \ +void \ +set_##FNAME( TYPE val ) \ +{ \ + if (header) { \ + header->set_##FNAME( val ); \ + } \ +} \ + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class elfio +{ + public: +//------------------------------------------------------------------------------ + elfio() : sections( this ), segments( this ) + { + header = 0; + current_file_pos = 0; + create( ELFCLASS32, ELFDATA2LSB ); + } + +//------------------------------------------------------------------------------ + ~elfio() + { + clean(); + } + +//------------------------------------------------------------------------------ + void create( unsigned char file_class, unsigned char encoding ) + { + clean(); + convertor.setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + +//------------------------------------------------------------------------------ + bool load( const std::string& file_name ) + { + std::ifstream stream; + stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !stream ) { + return false; + } + + return load(stream); + } + +//------------------------------------------------------------------------------ + bool load( std::istream &stream ) + { + clean(); + + unsigned char e_ident[EI_NIDENT]; + // Read ELF file signature + stream.read( reinterpret_cast( &e_ident ), sizeof( e_ident ) ); + + // Is it ELF file? + if ( stream.gcount() != sizeof( e_ident ) || + e_ident[EI_MAG0] != ELFMAG0 || + e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || + e_ident[EI_MAG3] != ELFMAG3 ) { + return false; + } + + if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && + ( e_ident[EI_CLASS] != ELFCLASS32 )) { + return false; + } + + convertor.setup( e_ident[EI_DATA] ); + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( 0 == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream ); + bool is_still_good = load_segments( stream ); + return is_still_good; + } + +//------------------------------------------------------------------------------ + bool save( const std::string& file_name ) + { + std::ofstream stream; + stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); + if ( !stream ) { + return false; + } + + return save(stream); + } + +//------------------------------------------------------------------------------ + bool save( std::ostream &stream ) + { + if ( !stream || !header) { + return false; + } + + bool is_still_good = true; + // Define layout specific header fields + // The position of the segment table is fixed after the header. + // The position of the section table is variable and needs to be fixed + // before saving. + header->set_segments_num( segments.size() ); + header->set_segments_offset( segments.size() ? header->get_header_size() : 0 ); + header->set_sections_num( sections.size() ); + header->set_sections_offset( 0 ); + + // Layout the first section right after the segment table + current_file_pos = header->get_header_size() + + header->get_segment_entry_size() * header->get_segments_num(); + + calc_segment_alignment(); + + is_still_good = layout_segments_and_their_sections(); + is_still_good = is_still_good && layout_sections_without_segments(); + is_still_good = is_still_good && layout_section_table(); + + is_still_good = is_still_good && save_header( stream ); + is_still_good = is_still_good && save_sections( stream ); + is_still_good = is_still_good && save_segments( stream ); + + return is_still_good; + } + +//------------------------------------------------------------------------------ + // ELF header access functions + ELFIO_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + +//------------------------------------------------------------------------------ + const endianess_convertor& get_convertor() const + { + return convertor; + } + +//------------------------------------------------------------------------------ + Elf_Xword get_default_entry_size( Elf_Word section_type ) const + { + switch( section_type ) { + case SHT_RELA: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rela ); + } + else { + return sizeof( Elf32_Rela ); + } + case SHT_REL: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rel ); + } + else { + return sizeof( Elf32_Rel ); + } + case SHT_SYMTAB: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Sym ); + } + else { + return sizeof( Elf32_Sym ); + } + case SHT_DYNAMIC: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Dyn ); + } + else { + return sizeof( Elf32_Dyn ); + } + default: + return 0; + } + } + +//------------------------------------------------------------------------------ + private: + bool is_offset_in_section( Elf64_Off offset, const section* sec ) const { + return offset >= sec->get_offset() && offset < sec->get_offset()+sec->get_size(); + } + +//------------------------------------------------------------------------------ + public: + + //! returns an empty string if no problems are detected, + //! or a string containing an error message if problems are found + std::string validate() const { + + // check for overlapping sections in the file + for ( int i = 0; i < sections.size(); ++i) { + for ( int j = i+1; j < sections.size(); ++j ) { + const section* a = sections[i]; + const section* b = sections[j]; + if ( !(a->get_type() & SHT_NOBITS) + && !(b->get_type() & SHT_NOBITS) + && (a->get_size() > 0) + && (b->get_size() > 0) + && (a->get_offset() > 0) + && (b->get_offset() > 0)) { + if ( is_offset_in_section( a->get_offset(), b ) + || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) + || is_offset_in_section( b->get_offset(), a ) + || is_offset_in_section( b->get_offset()+b->get_size()-1, a )) { + return "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file"; + } + } + } + } + + // more checks to be added here... + + return ""; + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void clean() + { + delete header; + header = 0; + + std::vector::const_iterator it; + for ( it = sections_.begin(); it != sections_.end(); ++it ) { + delete *it; + } + sections_.clear(); + + std::vector::const_iterator it1; + for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) { + delete *it1; + } + segments_.clear(); + } + +//------------------------------------------------------------------------------ + elf_header* create_header( unsigned char file_class, unsigned char encoding ) + { + elf_header* new_header = 0; + + if ( file_class == ELFCLASS64 ) { + new_header = new elf_header_impl< Elf64_Ehdr >( &convertor, + encoding ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = new elf_header_impl< Elf32_Ehdr >( &convertor, + encoding ); + } + else { + return 0; + } + + return new_header; + } + +//------------------------------------------------------------------------------ + section* create_section() + { + section* new_section; + unsigned char file_class = get_class(); + + if ( file_class == ELFCLASS64 ) { + new_section = new section_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_section = new section_impl( &convertor ); + } + else { + return 0; + } + + new_section->set_index( (Elf_Half)sections_.size() ); + sections_.push_back( new_section ); + + return new_section; + } + + +//------------------------------------------------------------------------------ + segment* create_segment() + { + segment* new_segment; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + new_segment = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_segment = new segment_impl( &convertor ); + } + else { + return 0; + } + + new_segment->set_index( (Elf_Half)segments_.size() ); + segments_.push_back( new_segment ); + + return new_segment; + } + +//------------------------------------------------------------------------------ + void create_mandatory_sections() + { + // Create null section without calling to 'add_section' as no string + // section containing section names exists yet + section* sec0 = create_section(); + sec0->set_index( 0 ); + sec0->set_name( "" ); + sec0->set_name_string_offset( 0 ); + + set_section_name_str_index( 1 ); + section* shstrtab = sections.add( ".shstrtab" ); + shstrtab->set_type( SHT_STRTAB ); + shstrtab->set_addr_align( 1 ); + } + +//------------------------------------------------------------------------------ + Elf_Half load_sections( std::istream& stream ) + { + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + sec->load( stream, (std::streamoff)offset + i * entry_size ); + sec->set_index( i ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + Elf_Half shstrndx = get_section_name_str_index(); + + if ( SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word section_offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( section_offset ); + if ( p != 0 ) { + sections[i]->set_name( p ); + } + } + } + + return num; + } + +//------------------------------------------------------------------------------ + //! Checks whether the addresses of the section entirely fall within the given segment. + //! It doesn't matter if the addresses are memory addresses, or file offsets, + //! they just need to be in the same address space + bool is_sect_in_seg ( Elf64_Off sect_begin, Elf_Xword sect_size, Elf64_Off seg_begin, Elf64_Off seg_end ) { + return seg_begin <= sect_begin + && sect_begin + sect_size <= seg_end + && sect_begin < seg_end; // this is important criteria when sect_size == 0 + // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) + // sect_begin=12, sect_size=0 -> shall return false! + } + +//------------------------------------------------------------------------------ + bool load_segments( std::istream& stream ) + { + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + segment* seg; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + seg = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + seg = new segment_impl( &convertor ); + } + else { + return false; + } + + seg->load( stream, (std::streamoff)offset + i * entry_size ); + seg->set_index( i ); + + // Add sections to the segments (similar to readelfs algorithm) + Elf64_Off segBaseOffset = seg->get_offset(); + Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); + Elf64_Off segVBaseAddr = seg->get_virtual_address(); + Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); + for( Elf_Half j = 0; j < sections.size(); ++j ) { + const section* psec = sections[j]; + + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if( psec->get_flags() & SHF_ALLOC + ? is_sect_in_seg( psec->get_address(), psec->get_size(), segVBaseAddr, segVEndAddr ) + : is_sect_in_seg( psec->get_offset(), psec->get_size(), segBaseOffset, segEndOffset )) { + // Alignment of segment shall not be updated, to preserve original value + // It will be re-calculated on saving. + seg->add_section_index( psec->get_index(), 0 ); + } + } + + // Add section into the segments' container + segments_.push_back( seg ); + } + + return true; + } + +//------------------------------------------------------------------------------ + bool save_header( std::ostream& stream ) + { + return header->save( stream ); + } + +//------------------------------------------------------------------------------ + bool save_sections( std::ostream& stream ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + section *sec = sections_.at(i); + + std::streampos headerPosition = + (std::streamoff)header->get_sections_offset() + + header->get_section_entry_size() * sec->get_index(); + + sec->save(stream,headerPosition,sec->get_offset()); + } + return true; + } + +//------------------------------------------------------------------------------ + bool save_segments( std::ostream& stream ) + { + for ( unsigned int i = 0; i < segments_.size(); ++i ) { + segment *seg = segments_.at(i); + + std::streampos headerPosition = header->get_segments_offset() + + header->get_segment_entry_size()*seg->get_index(); + + seg->save( stream, headerPosition, seg->get_offset() ); + } + return true; + } + +//------------------------------------------------------------------------------ + bool is_section_without_segment( unsigned int section_index ) + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( unsigned int k = 0; + !found && ( k < segments[j]->get_sections_num() ); + ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + +//------------------------------------------------------------------------------ + bool is_subsequence_of( segment* seg1, segment* seg2 ) + { + // Return 'true' if sections of seg1 are a subset of sections in seg2 + const std::vector& sections1 = seg1->get_sections(); + const std::vector& sections2 = seg2->get_sections(); + + bool found = false; + if ( sections1.size() < sections2.size() ) { + found = std::includes( sections2.begin(), sections2.end(), + sections1.begin(), sections1.end() ); + } + + return found; + } + +//------------------------------------------------------------------------------ + std::vector get_ordered_segments( ) + { + std::vector res; + std::deque worklist; + + res.reserve(segments.size()); + std::copy( segments_.begin(), segments_.end(), + std::back_inserter( worklist )) ; + + // Bring the segments which start at address 0 to the front + size_t nextSlot = 0; + for( size_t i = 0; i < worklist.size(); ++i ) { + if( i != nextSlot && worklist[i]->is_offset_initialized() + && worklist[i]->get_offset() == 0 ) { + if (worklist[nextSlot]->get_offset() == 0) { + ++nextSlot; + } + std::swap(worklist[i],worklist[nextSlot]); + ++nextSlot; + } + } + + while ( !worklist.empty() ) { + segment *seg = worklist.front(); + worklist.pop_front(); + + size_t i = 0; + for ( ; i < worklist.size(); ++i ) { + if ( is_subsequence_of( seg, worklist[i] ) ) { + break; + } + } + + if ( i < worklist.size() ) + worklist.push_back(seg); + else + res.push_back(seg); + } + + return res; + } + + +//------------------------------------------------------------------------------ + bool layout_sections_without_segments( ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + section *sec = sections_[i]; + + Elf_Xword section_align = sec->get_addr_align(); + if ( section_align > 1 && current_file_pos % section_align != 0 ) { + current_file_pos += section_align - + current_file_pos % section_align; + } + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + } + } + + return true; + } + + +//------------------------------------------------------------------------------ + void calc_segment_alignment( ) + { + for( std::vector::iterator s = segments_.begin(); s != segments_.end(); ++s ) { + segment* seg = *s; + for ( int i = 0; i < seg->get_sections_num(); ++i ) { + section* sect = sections_[ seg->get_section_index_at(i) ]; + if ( sect->get_addr_align() > seg->get_align() ) { + seg->set_align( sect->get_addr_align() ); + } + } + } + } + +//------------------------------------------------------------------------------ + bool layout_segments_and_their_sections( ) + { + std::vector worklist; + std::vector section_generated(sections.size(),false); + + // Get segments in a order in where segments which contain a + // sub sequence of other segments are located at the end + worklist = get_ordered_segments(); + + for ( unsigned int i = 0; i < worklist.size(); ++i ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + segment* seg = worklist[i]; + + // Special case: PHDR segment + // This segment contains the program headers but no sections + if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { + seg_start_pos = header->get_segments_offset(); + segment_memory = segment_filesize = + header->get_segment_entry_size() * header->get_segments_num(); + } + // Special case: + // Segments which start with the NULL section and have further sections + else if ( seg->get_sections_num() > 1 + && sections[seg->get_section_index_at( 0 )]->get_type() == SHT_NULL ) { + seg_start_pos = 0; + if ( seg->get_sections_num() ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() + && !section_generated[seg->get_section_index_at( 0 )] ) { + Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; + Elf64_Off cur_page_alignment = current_file_pos % align; + Elf64_Off req_page_alignment = seg->get_virtual_address() % align; + Elf64_Off error = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + error ) % align; + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() ) { + seg_start_pos = sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[ index ]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type()) { + section_generated[index] = true; + continue; + } + + Elf_Xword secAlign = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() + && SHT_NOBITS != sec->get_type() + && SHT_NULL != sec->get_type() + && 0 != sec->get_size() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + if ( req_offset < cur_offset) { + // something has gone awfully wrong, abort! + // secAlign would turn out negative, seeking backwards and overwriting previous data + return false; + } + secAlign = req_offset - cur_offset; + } + else if (!section_generated[index] && !sec->is_address_initialized() ) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if (align == 0) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + secAlign = ( align - error ) % align; + } + else if (section_generated[index] ) { + // Alignment for already generated sections + secAlign = sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( (sec->get_flags() & SHF_ALLOC) + && !( (sec->get_flags() & SHF_TLS) && (seg->get_type() != PT_TLS) + && ( SHT_NOBITS == sec->get_type())) ) + segment_memory += sec->get_size() + secAlign; + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + segment_filesize += sec->get_size() + secAlign; + + // Nothing to be done when generating nested segments + if(section_generated[index]) { + continue; + } + + current_file_pos += secAlign; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos); + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + current_file_pos += sec->get_size(); + section_generated[index] = true; + } + + seg->set_file_size( segment_filesize ); + + // If we already have a memory size from loading an elf file (value > 0), + // it must not shrink! + // Memory size may be bigger than file size and it is the loader's job to do something + // with the surplus bytes in memory, like initializing them with a defined value. + if ( seg->get_memory_size() < segment_memory ) { + seg->set_memory_size( segment_memory ); + } + + seg->set_offset(seg_start_pos); + } + + return true; + } + +//------------------------------------------------------------------------------ + bool layout_section_table() + { + // Simply place the section table at the end for now + Elf64_Off alignmentError = current_file_pos % 4; + current_file_pos += ( 4 - alignmentError ) % 4; + header->set_sections_offset(current_file_pos); + return true; + } + + +//------------------------------------------------------------------------------ + public: + friend class Sections; + class Sections { + public: +//------------------------------------------------------------------------------ + Sections( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->sections_.size(); + } + +//------------------------------------------------------------------------------ + section* operator[]( unsigned int index ) const + { + section* sec = 0; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index]; + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* operator[]( const std::string& name ) const + { + section* sec = 0; + + std::vector::const_iterator it; + for ( it = parent->sections_.begin(); + it != parent->sections_.end(); + ++it ) { + if ( (*it)->get_name() == name ) { + sec = *it; + break; + } + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* add( const std::string& name ) + { + section* new_section = parent->create_section(); + new_section->set_name( name ); + + Elf_Half str_index = parent->get_section_name_str_index(); + section* string_table( parent->sections_[str_index] ); + string_section_accessor str_writer( string_table ); + Elf_Word pos = str_writer.add_string( name ); + new_section->set_name_string_offset( pos ); + + return new_section; + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->sections_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->sections_.end(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator begin() const { + return parent->sections_.cbegin(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator end() const { + return parent->sections_.cend(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } sections; + +//------------------------------------------------------------------------------ + public: + friend class Segments; + class Segments { + public: +//------------------------------------------------------------------------------ + Segments( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->segments_.size(); + } + +//------------------------------------------------------------------------------ + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index]; + } + + +//------------------------------------------------------------------------------ + segment* add() + { + return parent->create_segment(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->segments_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->segments_.end(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator begin() const { + return parent->segments_.cbegin(); + } + +//------------------------------------------------------------------------------ + std::vector::const_iterator end() const { + return parent->segments_.cend(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } segments; + +//------------------------------------------------------------------------------ + private: + elf_header* header; + std::vector sections_; + std::vector segments_; + endianess_convertor convertor; + + Elf_Xword current_file_pos; +}; + +} // namespace ELFIO + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // ELFIO_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_dump.hpp b/ZAPDTR/lib/elfio/elfio/elfio_dump.hpp new file mode 100644 index 000000000..4ace66514 --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_dump.hpp @@ -0,0 +1,976 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_DUMP_HPP +#define ELFIO_DUMP_HPP + +#include +#include +#include +#include +#include +#include + +namespace ELFIO { + + +static struct class_table_t { + const char key; + const char* str; +} class_table [] = +{ + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + + +static struct endian_table_t { + const char key; + const char* str; +} endian_table [] = +{ + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + + +static struct version_table_t { + const Elf64_Word key; + const char* str; +} version_table [] = +{ + { EV_NONE , "None" }, + { EV_CURRENT, "Current" }, +}; + + +static struct type_table_t { + const Elf32_Half key; + const char* str; +} type_table [] = +{ + { ET_NONE, "No file type" }, + { ET_REL , "Relocatable file" }, + { ET_EXEC, "Executable file" }, + { ET_DYN , "Shared object file" }, + { ET_CORE, "Core file" }, +}; + + +static struct machine_table_t { + const Elf64_Half key; + const char* str; +} machine_table [] = +{ + { EM_NONE , "No machine" }, + { EM_M32 , "AT&T WE 32100" }, + { EM_SPARC , "SUN SPARC" }, + { EM_386 , "Intel 80386" }, + { EM_68K , "Motorola m68k family" }, + { EM_88K , "Motorola m88k family" }, + { EM_486 , "Intel 80486// Reserved for future use" }, + { EM_860 , "Intel 80860" }, + { EM_MIPS , "MIPS R3000 (officially, big-endian only)" }, + { EM_S370 , "IBM System/370" }, + { EM_MIPS_RS3_LE , "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, + { EM_res011 , "Reserved" }, + { EM_res012 , "Reserved" }, + { EM_res013 , "Reserved" }, + { EM_res014 , "Reserved" }, + { EM_PARISC , "HPPA" }, + { EM_res016 , "Reserved" }, + { EM_VPP550 , "Fujitsu VPP500" }, + { EM_SPARC32PLUS , "Sun's v8plus" }, + { EM_960 , "Intel 80960" }, + { EM_PPC , "PowerPC" }, + { EM_PPC64 , "64-bit PowerPC" }, + { EM_S390 , "IBM S/390" }, + { EM_SPU , "Sony/Toshiba/IBM SPU" }, + { EM_res024 , "Reserved" }, + { EM_res025 , "Reserved" }, + { EM_res026 , "Reserved" }, + { EM_res027 , "Reserved" }, + { EM_res028 , "Reserved" }, + { EM_res029 , "Reserved" }, + { EM_res030 , "Reserved" }, + { EM_res031 , "Reserved" }, + { EM_res032 , "Reserved" }, + { EM_res033 , "Reserved" }, + { EM_res034 , "Reserved" }, + { EM_res035 , "Reserved" }, + { EM_V800 , "NEC V800 series" }, + { EM_FR20 , "Fujitsu FR20" }, + { EM_RH32 , "TRW RH32" }, + { EM_MCORE , "Motorola M*Core // May also be taken by Fujitsu MMA" }, + { EM_RCE , "Old name for MCore" }, + { EM_ARM , "ARM" }, + { EM_OLD_ALPHA , "Digital Alpha" }, + { EM_SH , "Renesas (formerly Hitachi) / SuperH SH" }, + { EM_SPARCV9 , "SPARC v9 64-bit" }, + { EM_TRICORE , "Siemens Tricore embedded processor" }, + { EM_ARC , "ARC Cores" }, + { EM_H8_300 , "Renesas (formerly Hitachi) H8/300" }, + { EM_H8_300H , "Renesas (formerly Hitachi) H8/300H" }, + { EM_H8S , "Renesas (formerly Hitachi) H8S" }, + { EM_H8_500 , "Renesas (formerly Hitachi) H8/500" }, + { EM_IA_64 , "Intel IA-64 Processor" }, + { EM_MIPS_X , "Stanford MIPS-X" }, + { EM_COLDFIRE , "Motorola Coldfire" }, + { EM_68HC12 , "Motorola M68HC12" }, + { EM_MMA , "Fujitsu Multimedia Accelerator" }, + { EM_PCP , "Siemens PCP" }, + { EM_NCPU , "Sony nCPU embedded RISC processor" }, + { EM_NDR1 , "Denso NDR1 microprocesspr" }, + { EM_STARCORE , "Motorola Star*Core processor" }, + { EM_ME16 , "Toyota ME16 processor" }, + { EM_ST100 , "STMicroelectronics ST100 processor" }, + { EM_TINYJ , "Advanced Logic Corp. TinyJ embedded processor" }, + { EM_X86_64 , "Advanced Micro Devices X86-64 processor" }, + { EM_PDSP , "Sony DSP Processor" }, + { EM_PDP10 , "Digital Equipment Corp. PDP-10" }, + { EM_PDP11 , "Digital Equipment Corp. PDP-11" }, + { EM_FX66 , "Siemens FX66 microcontroller" }, + { EM_ST9PLUS , "STMicroelectronics ST9+ 8/16 bit microcontroller" }, + { EM_ST7 , "STMicroelectronics ST7 8-bit microcontroller" }, + { EM_68HC16 , "Motorola MC68HC16 Microcontroller" }, + { EM_68HC11 , "Motorola MC68HC11 Microcontroller" }, + { EM_68HC08 , "Motorola MC68HC08 Microcontroller" }, + { EM_68HC05 , "Motorola MC68HC05 Microcontroller" }, + { EM_SVX , "Silicon Graphics SVx" }, + { EM_ST19 , "STMicroelectronics ST19 8-bit cpu" }, + { EM_VAX , "Digital VAX" }, + { EM_CRIS , "Axis Communications 32-bit embedded processor" }, + { EM_JAVELIN , "Infineon Technologies 32-bit embedded cpu" }, + { EM_FIREPATH , "Element 14 64-bit DSP processor" }, + { EM_ZSP , "LSI Logic's 16-bit DSP processor" }, + { EM_MMIX , "Donald Knuth's educational 64-bit processor" }, + { EM_HUANY , "Harvard's machine-independent format" }, + { EM_PRISM , "SiTera Prism" }, + { EM_AVR , "Atmel AVR 8-bit microcontroller" }, + { EM_FR30 , "Fujitsu FR30" }, + { EM_D10V , "Mitsubishi D10V" }, + { EM_D30V , "Mitsubishi D30V" }, + { EM_V850 , "NEC v850" }, + { EM_M32R , "Renesas M32R (formerly Mitsubishi M32R)" }, + { EM_MN10300 , "Matsushita MN10300" }, + { EM_MN10200 , "Matsushita MN10200" }, + { EM_PJ , "picoJava" }, + { EM_OPENRISC , "OpenRISC 32-bit embedded processor" }, + { EM_ARC_A5 , "ARC Cores Tangent-A5" }, + { EM_XTENSA , "Tensilica Xtensa Architecture" }, + { EM_VIDEOCORE , "Alphamosaic VideoCore processor" }, + { EM_TMM_GPP , "Thompson Multimedia General Purpose Processor" }, + { EM_NS32K , "National Semiconductor 32000 series" }, + { EM_TPC , "Tenor Network TPC processor" }, + { EM_SNP1K , "Trebia SNP 1000 processor" }, + { EM_ST200 , "STMicroelectronics ST200 microcontroller" }, + { EM_IP2K , "Ubicom IP2022 micro controller" }, + { EM_MAX , "MAX Processor" }, + { EM_CR , "National Semiconductor CompactRISC" }, + { EM_F2MC16 , "Fujitsu F2MC16" }, + { EM_MSP430 , "TI msp430 micro controller" }, + { EM_BLACKFIN , "ADI Blackfin" }, + { EM_SE_C33 , "S1C33 Family of Seiko Epson processors" }, + { EM_SEP , "Sharp embedded microprocessor" }, + { EM_ARCA , "Arca RISC Microprocessor" }, + { EM_UNICORE , "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University" }, + { EM_EXCESS , "eXcess: 16/32/64-bit configurable embedded CPU" }, + { EM_DXP , "Icera Semiconductor Inc. Deep Execution Processor" }, + { EM_ALTERA_NIOS2 , "Altera Nios II soft-core processor" }, + { EM_CRX , "National Semiconductor CRX" }, + { EM_XGATE , "Motorola XGATE embedded processor" }, + { EM_C166 , "Infineon C16x/XC16x processor" }, + { EM_M16C , "Renesas M16C series microprocessors" }, + { EM_DSPIC30F , "Microchip Technology dsPIC30F Digital Signal Controller" }, + { EM_CE , "Freescale Communication Engine RISC core" }, + { EM_M32C , "Renesas M32C series microprocessors" }, + { EM_res121 , "Reserved" }, + { EM_res122 , "Reserved" }, + { EM_res123 , "Reserved" }, + { EM_res124 , "Reserved" }, + { EM_res125 , "Reserved" }, + { EM_res126 , "Reserved" }, + { EM_res127 , "Reserved" }, + { EM_res128 , "Reserved" }, + { EM_res129 , "Reserved" }, + { EM_res130 , "Reserved" }, + { EM_TSK3000 , "Altium TSK3000 core" }, + { EM_RS08 , "Freescale RS08 embedded processor" }, + { EM_res133 , "Reserved" }, + { EM_ECOG2 , "Cyan Technology eCOG2 microprocessor" }, + { EM_SCORE , "Sunplus Score" }, + { EM_SCORE7 , "Sunplus S+core7 RISC processor" }, + { EM_DSP24 , "New Japan Radio (NJR) 24-bit DSP Processor" }, + { EM_VIDEOCORE3 , "Broadcom VideoCore III processor" }, + { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, + { EM_SE_C17 , "Seiko Epson C17 family" }, + { EM_TI_C6000 , "Texas Instruments TMS320C6000 DSP family" }, + { EM_TI_C2000 , "Texas Instruments TMS320C2000 DSP family" }, + { EM_TI_C5500 , "Texas Instruments TMS320C55x DSP family" }, + { EM_res143 , "Reserved" }, + { EM_res144 , "Reserved" }, + { EM_res145 , "Reserved" }, + { EM_res146 , "Reserved" }, + { EM_res147 , "Reserved" }, + { EM_res148 , "Reserved" }, + { EM_res149 , "Reserved" }, + { EM_res150 , "Reserved" }, + { EM_res151 , "Reserved" }, + { EM_res152 , "Reserved" }, + { EM_res153 , "Reserved" }, + { EM_res154 , "Reserved" }, + { EM_res155 , "Reserved" }, + { EM_res156 , "Reserved" }, + { EM_res157 , "Reserved" }, + { EM_res158 , "Reserved" }, + { EM_res159 , "Reserved" }, + { EM_MMDSP_PLUS , "STMicroelectronics 64bit VLIW Data Signal Processor" }, + { EM_CYPRESS_M8C , "Cypress M8C microprocessor" }, + { EM_R32C , "Renesas R32C series microprocessors" }, + { EM_TRIMEDIA , "NXP Semiconductors TriMedia architecture family" }, + { EM_QDSP6 , "QUALCOMM DSP6 Processor" }, + { EM_8051 , "Intel 8051 and variants" }, + { EM_STXP7X , "STMicroelectronics STxP7x family" }, + { EM_NDS32 , "Andes Technology compact code size embedded RISC processor family" }, + { EM_ECOG1 , "Cyan Technology eCOG1X family" }, + { EM_ECOG1X , "Cyan Technology eCOG1X family" }, + { EM_MAXQ30 , "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, + { EM_XIMO16 , "New Japan Radio (NJR) 16-bit DSP Processor" }, + { EM_MANIK , "M2000 Reconfigurable RISC Microprocessor" }, + { EM_CRAYNV2 , "Cray Inc. NV2 vector architecture" }, + { EM_RX , "Renesas RX family" }, + { EM_METAG , "Imagination Technologies META processor architecture" }, + { EM_MCST_ELBRUS , "MCST Elbrus general purpose hardware architecture" }, + { EM_ECOG16 , "Cyan Technology eCOG16 family" }, + { EM_CR16 , "National Semiconductor CompactRISC 16-bit processor" }, + { EM_ETPU , "Freescale Extended Time Processing Unit" }, + { EM_SLE9X , "Infineon Technologies SLE9X core" }, + { EM_L1OM , "Intel L1OM" }, + { EM_INTEL181 , "Reserved by Intel" }, + { EM_INTEL182 , "Reserved by Intel" }, + { EM_res183 , "Reserved by ARM" }, + { EM_res184 , "Reserved by ARM" }, + { EM_AVR32 , "Atmel Corporation 32-bit microprocessor family" }, + { EM_STM8 , "STMicroeletronics STM8 8-bit microcontroller" }, + { EM_TILE64 , "Tilera TILE64 multicore architecture family" }, + { EM_TILEPRO , "Tilera TILEPro multicore architecture family" }, + { EM_MICROBLAZE , "Xilinx MicroBlaze 32-bit RISC soft processor core" }, + { EM_CUDA , "NVIDIA CUDA architecture " }, +}; + + +static struct section_type_table_t { + const Elf64_Half key; + const char* str; +} section_type_table [] = +{ + { SHT_NULL , "NULL" }, + { SHT_PROGBITS , "PROGBITS" }, + { SHT_SYMTAB , "SYMTAB" }, + { SHT_STRTAB , "STRTAB" }, + { SHT_RELA , "RELA" }, + { SHT_HASH , "HASH" }, + { SHT_DYNAMIC , "DYNAMIC" }, + { SHT_NOTE , "NOTE" }, + { SHT_NOBITS , "NOBITS" }, + { SHT_REL , "REL" }, + { SHT_SHLIB , "SHLIB" }, + { SHT_DYNSYM , "DYNSYM" }, + { SHT_INIT_ARRAY , "INIT_ARRAY" }, + { SHT_FINI_ARRAY , "FINI_ARRAY" }, + { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { SHT_GROUP , "GROUP" }, + { SHT_SYMTAB_SHNDX , "SYMTAB_SHNDX " }, +}; + + +static struct segment_type_table_t { + const Elf_Word key; + const char* str; +} segment_type_table [] = +{ + { PT_NULL , "NULL" }, + { PT_LOAD , "LOAD" }, + { PT_DYNAMIC, "DYNAMIC" }, + { PT_INTERP , "INTERP" }, + { PT_NOTE , "NOTE" }, + { PT_SHLIB , "SHLIB" }, + { PT_PHDR , "PHDR" }, + { PT_TLS , "TLS" }, +}; + + +static struct segment_flag_table_t { + const Elf_Word key; + const char* str; +} segment_flag_table [] = +{ + { 0, "" }, + { 1, "X" }, + { 2, "W" }, + { 3, "WX" }, + { 4, "R" }, + { 5, "RX" }, + { 6, "RW" }, + { 7, "RWX" }, +}; + + +static struct symbol_bind_t { + const Elf_Word key; + const char* str; +} symbol_bind_table [] = +{ + { STB_LOCAL , "LOCAL" }, + { STB_GLOBAL , "GLOBAL" }, + { STB_WEAK , "WEAK" }, + { STB_LOOS , "LOOS" }, + { STB_HIOS , "HIOS" }, + { STB_MULTIDEF, "MULTIDEF" }, + { STB_LOPROC , "LOPROC" }, + { STB_HIPROC , "HIPROC" }, +}; + + +static struct symbol_type_t { + const Elf_Word key; + const char* str; +} symbol_type_table [] = +{ + { STT_NOTYPE , "NOTYPE" }, + { STT_OBJECT , "OBJECT" }, + { STT_FUNC , "FUNC" }, + { STT_SECTION, "SECTION" }, + { STT_FILE , "FILE" }, + { STT_COMMON , "COMMON" }, + { STT_TLS , "TLS" }, + { STT_LOOS , "LOOS" }, + { STT_HIOS , "HIOS" }, + { STT_LOPROC , "LOPROC" }, + { STT_HIPROC , "HIPROC" }, +}; + + +static struct dynamic_tag_t { + const Elf_Word key; + const char* str; +} dynamic_tag_table [] = +{ + { DT_NULL , "NULL" }, + { DT_NEEDED , "NEEDED" }, + { DT_PLTRELSZ , "PLTRELSZ" }, + { DT_PLTGOT , "PLTGOT" }, + { DT_HASH , "HASH" }, + { DT_STRTAB , "STRTAB" }, + { DT_SYMTAB , "SYMTAB" }, + { DT_RELA , "RELA" }, + { DT_RELASZ , "RELASZ" }, + { DT_RELAENT , "RELAENT" }, + { DT_STRSZ , "STRSZ" }, + { DT_SYMENT , "SYMENT" }, + { DT_INIT , "INIT" }, + { DT_FINI , "FINI" }, + { DT_SONAME , "SONAME" }, + { DT_RPATH , "RPATH" }, + { DT_SYMBOLIC , "SYMBOLIC" }, + { DT_REL , "REL" }, + { DT_RELSZ , "RELSZ" }, + { DT_RELENT , "RELENT" }, + { DT_PLTREL , "PLTREL" }, + { DT_DEBUG , "DEBUG" }, + { DT_TEXTREL , "TEXTREL" }, + { DT_JMPREL , "JMPREL" }, + { DT_BIND_NOW , "BIND_NOW" }, + { DT_INIT_ARRAY , "INIT_ARRAY" }, + { DT_FINI_ARRAY , "FINI_ARRAY" }, + { DT_INIT_ARRAYSZ , "INIT_ARRAYSZ" }, + { DT_FINI_ARRAYSZ , "FINI_ARRAYSZ" }, + { DT_RUNPATH , "RUNPATH" }, + { DT_FLAGS , "FLAGS" }, + { DT_ENCODING , "ENCODING" }, + { DT_PREINIT_ARRAY , "PREINIT_ARRAY" }, + { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, + { DT_MAXPOSTAGS , "MAXPOSTAGS" }, +}; + +static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; + +//------------------------------------------------------------------------------ +class dump +{ +#define DUMP_DEC_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::dec << std::right +#define DUMP_HEX_FORMAT( width ) std::setw(width) << std::setfill( '0' ) << \ + std::hex << std::right +#define DUMP_STR_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::hex << std::left + + public: +//------------------------------------------------------------------------------ + static void + header( std::ostream& out, const elfio& reader ) + { + if (!reader.get_header_size()) + { + return; + } + out << "ELF Header" << std::endl << std::endl + << " Class: " << str_class( reader.get_class() ) << std::endl + << " Encoding: " << str_endian( reader.get_encoding() ) << std::endl + << " ELFVersion: " << str_version( reader.get_elf_version() ) << std::endl + << " Type: " << str_type( reader.get_type() ) << std::endl + << " Machine: " << str_machine( reader.get_machine() ) << std::endl + << " Version: " << str_version( reader.get_version() ) << std::endl + << " Entry: " << "0x" << std::hex << reader.get_entry() << std::endl + << " Flags: " << "0x" << std::hex << reader.get_flags() << std::endl + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type Addr Size ES Flg Lk Inf Al Name" << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Addr Size ES Flg" << std::endl + << " Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute)\n\n" + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_header( std::ostream& out, Elf_Half no, const section* sec, + unsigned char elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + + out.flags(original_flags); + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + if ( n == 0 ) { + return; + } + + out << "Segment headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type VirtAddr PhysAddr FileSize Mem.Size Flags Align" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type VirtAddr PhysAddr Flags" << std::endl + << " FileSize Mem.Size Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + segment* seg = reader.segments[i]; + segment_header( out, i, seg, reader.get_class() ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_header( std::ostream& out, Elf_Half no, const segment* seg, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_align() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address() << " " + << DUMP_STR_FORMAT( 16 ) << str_segment_flag( seg->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_align() << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + symbol_tables( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) { + symbol_section_accessor symbols( reader, sec ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no > 0 ) { + out << "Symbol table (" << sec->get_name() << ")" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Value Size Type Bind Sect Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Value Size Type Bind Sect" << std::endl + << " Name" + << std::endl; + } + for ( Elf_Half i = 0; i < sym_no; ++i ) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, section, other ); + symbol_table( out, i, name, value, size, bind, type, section, reader.get_class() ); + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + symbol_table( std::ostream& out, + Elf_Half no, + std::string& name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + Elf_Half section, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << value << " " + << DUMP_HEX_FORMAT( 8 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 16 ) << value << " " + << DUMP_HEX_FORMAT( 16 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << std::endl + << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + notes( std::ostream& out, const elfio& reader ) + { + Elf_Half no = reader.sections.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec ); + int no_notes = notes.get_notes_num(); + if ( no > 0 ) { + out << "Note section (" << sec->get_name() << ")" << std::endl + << " No Type Name" + << std::endl; + for ( int j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + void* desc; + Elf_Word descsz; + + if ( notes.get_note(j, type, name, desc, descsz) ) { + // 'name' usually contains \0 at the end. Try to fix it + name = name.c_str(); + note( out, j, type, name ); + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name ) + { + out << " [" + << DUMP_DEC_FORMAT( 2 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << type << " " + << DUMP_STR_FORMAT( 1 ) << name + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + dynamic_tags( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no > 0 ) { + out << "Dynamic section (" << sec->get_name() << ")" << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + for ( Elf_Xword i = 0; i < dyn_no; ++i ) { + Elf_Xword tag = 0; + Elf_Xword value = 0; + std::string str; + dynamic.get_entry( i, tag, value, str ); + dynamic_tag( out, i, tag, value, str, reader.get_class() ); + if ( DT_NULL == tag ) { + break; + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + dynamic_tag( std::ostream& out, + Elf_Xword no, + Elf_Xword tag, + Elf_Xword value, + std::string str, + unsigned int /*elf_class*/ ) + { + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; + if ( str.empty() ) { + out << DUMP_HEX_FORMAT( 16 ) << value << " "; + } + else { + out << DUMP_STR_FORMAT( 32 ) << str << " "; + } + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_data( std::ostream& out, const section* sec ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << sec->get_name() << std::endl; + const char* pdata = sec->get_data(); + if ( pdata ){ + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + section_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Data:" << std::endl; + + for ( Elf_Half i = 1; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( sec->get_type() == SHT_NOBITS ) { + continue; + } + section_data( out, sec ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_data( std::ostream& out, Elf_Half no, const segment* seg ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << "Segment # " << no << std::endl; + const char* pdata = seg->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + + if ( n == 0 ) { + return; + } + + out << "Segment Data:" << std::endl; + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + + private: +//------------------------------------------------------------------------------ + template< typename T, typename K > + std::string + static + find_value_in_table( const T& table, const K& key ) + { + std::string res = "?"; + for ( unsigned int i = 0; i < sizeof( table )/sizeof( table[0] ); ++i ) { + if ( table[i].key == key ) { + res = table[i].str; + break; + } + } + + return res; + } + + +//------------------------------------------------------------------------------ + template< typename T, typename K > + static + std::string + format_assoc( const T& table, const K& key ) + { + std::string str = find_value_in_table( table, key ); + if ( str == "?" ) { + std::ostringstream oss; + oss << str << " (0x" << std::hex << key << ")"; + str = oss.str(); + } + + return str; + } + + +//------------------------------------------------------------------------------ + template< typename T > + static + std::string + format_assoc( const T& table, const char key ) + { + return format_assoc( table, (const int)key ); + } + + +//------------------------------------------------------------------------------ + static + std::string + section_flags( Elf_Xword flags ) + { + std::string ret = ""; + if ( flags & SHF_WRITE ) { + ret += "W"; + } + if ( flags & SHF_ALLOC ) { + ret += "A"; + } + if ( flags & SHF_EXECINSTR ) { + ret += "X"; + } + + return ret; + } + + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template< typename T > \ + static \ + std::string \ + str_##name( const T key ) \ + { \ + return format_assoc( name##_table, key ); \ + } + + STR_FUNC_TABLE( class ) + STR_FUNC_TABLE( endian ) + STR_FUNC_TABLE( version ) + STR_FUNC_TABLE( type ) + STR_FUNC_TABLE( machine ) + STR_FUNC_TABLE( section_type ) + STR_FUNC_TABLE( segment_type ) + STR_FUNC_TABLE( segment_flag ) + STR_FUNC_TABLE( symbol_bind ) + STR_FUNC_TABLE( symbol_type ) + STR_FUNC_TABLE( dynamic_tag ) + +#undef STR_FUNC_TABLE +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump + + +}; // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_dynamic.hpp b/ZAPDTR/lib/elfio/elfio/elfio_dynamic.hpp new file mode 100644 index 000000000..42f26805b --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_dynamic.hpp @@ -0,0 +1,257 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_DYNAMIC_HPP +#define ELFIO_DYNAMIC_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template< class S > +class dynamic_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + dynamic_section_accessor_template( const elfio& elf_file_, S* section_ ) : + elf_file( elf_file_ ), + dynamic_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != dynamic_section->get_entry_size() ) { + nRet = dynamic_section->get_size() / dynamic_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value, + std::string& str ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_get_entry_dyn< Elf32_Dyn >( index, tag, value ); + } + else { + generic_get_entry_dyn< Elf64_Dyn >( index, tag, value ); + } + + // If the tag may have a string table reference, prepare the string + if ( tag == DT_NEEDED || + tag == DT_SONAME || + tag == DT_RPATH || + tag == DT_RUNPATH ) { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + const char* result = strsec.get_string( value ); + if ( 0 == result ) { + str.clear(); + return false; + } + str = result; + } + else { + str.clear(); + } + + return true; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword tag, + Elf_Xword value ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Dyn >( tag, value ); + } + else { + generic_add_entry< Elf64_Dyn >( tag, value ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword tag, + const std::string& str ) + { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + Elf_Xword value = strsec.add_string( str ); + add_entry( tag, value ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)dynamic_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_dyn( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + // Check unusual case when dynamic section has no data + if( dynamic_section->get_data() == 0 || + ( index + 1 ) * dynamic_section->get_entry_size() > dynamic_section->get_size() ) { + tag = DT_NULL; + value = 0; + return; + } + + const T* pEntry = reinterpret_cast( + dynamic_section->get_data() + + index * dynamic_section->get_entry_size() ); + tag = convertor( pEntry->d_tag ); + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + value = convertor( pEntry->d_un.d_val ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + value = convertor( pEntry->d_un.d_ptr ); + break; + } + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf_Xword tag, Elf_Xword value ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + entry.d_un.d_val = convertor( value ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + entry.d_un.d_ptr = convertor( value ); + break; + } + + entry.d_tag = convertor( tag ); + + dynamic_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* dynamic_section; +}; + +using dynamic_section_accessor = dynamic_section_accessor_template
; +using const_dynamic_section_accessor = dynamic_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_header.hpp b/ZAPDTR/lib/elfio/elfio/elfio_header.hpp new file mode 100644 index 000000000..6f8da0285 --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_header.hpp @@ -0,0 +1,145 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELF_HEADER_HPP +#define ELF_HEADER_HPP + +#include + +namespace ELFIO { + +class elf_header +{ + public: + virtual ~elf_header() {}; + virtual bool load( std::istream& stream ) = 0; + virtual bool save( std::ostream& stream ) const = 0; + + // ELF header functions + ELFIO_GET_ACCESS_DECL( unsigned char, class ); + ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); + ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); + ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); + + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); +}; + + +template< class T > struct elf_header_impl_types; +template<> struct elf_header_impl_types { + typedef Elf32_Phdr Phdr_type; + typedef Elf32_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS32; +}; +template<> struct elf_header_impl_types { + typedef Elf64_Phdr Phdr_type; + typedef Elf64_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS64; +}; + +template< class T > class elf_header_impl : public elf_header +{ + public: + elf_header_impl( endianess_convertor* convertor_, + unsigned char encoding ) + { + convertor = convertor_; + + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; + header.e_ident[EI_DATA] = encoding; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_version = (*convertor)( (Elf_Word)EV_CURRENT ); + header.e_ehsize = ( sizeof( header ) ); + header.e_ehsize = (*convertor)( header.e_ehsize ); + header.e_shstrndx = (*convertor)( (Elf_Half)1 ); + header.e_phentsize = sizeof( typename elf_header_impl_types::Phdr_type ); + header.e_shentsize = sizeof( typename elf_header_impl_types::Shdr_type ); + header.e_phentsize = (*convertor)( header.e_phentsize ); + header.e_shentsize = (*convertor)( header.e_shentsize ); + } + + bool + load( std::istream& stream ) + { + stream.seekg( 0 ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return (stream.gcount() == sizeof( header ) ); + } + + bool + save( std::ostream& stream ) const + { + stream.seekp( 0 ); + stream.write( reinterpret_cast( &header ), sizeof( header ) ); + + return stream.good(); + } + + // ELF header functions + ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); + ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); + ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); + ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); + ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); + ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); + + ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version); + ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); + ELFIO_GET_SET_ACCESS( unsigned char, abi_version, header.e_ident[EI_ABIVERSION] ); + ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); + ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); + ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); + ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); + ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); + + private: + T header; + endianess_convertor* convertor; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_note.hpp b/ZAPDTR/lib/elfio/elfio/elfio_note.hpp new file mode 100644 index 000000000..8619c7385 --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_note.hpp @@ -0,0 +1,170 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_NOTE_HPP +#define ELFIO_NOTE_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// There are discrepancies in documentations. SCO documentation +// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) +// requires 8 byte entries alignment for 64-bit ELF file, +// but Oracle's definition uses the same structure +// for 32-bit and 64-bit formats. +// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) +// +// It looks like EM_X86_64 Linux implementation is similar to Oracle's +// definition. Therefore, the same alignment works for both formats +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template< class S > +class note_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + note_section_accessor_template( const elfio& elf_file_, S* section_ ) : + elf_file( elf_file_ ), note_section( section_ ) + { + process_section(); + } + +//------------------------------------------------------------------------------ + Elf_Word + get_notes_num() const + { + return (Elf_Word)note_start_positions.size(); + } + +//------------------------------------------------------------------------------ + bool + get_note( Elf_Word index, + Elf_Word& type, + std::string& name, + void*& desc, + Elf_Word& descSize ) const + { + if ( index >= note_section->get_size() ) { + return false; + } + + const char* pData = note_section->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + type = convertor( *(const Elf_Word*)( pData + 2*align ) ); + Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); + descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); + Elf_Xword max_name_size = note_section->get_size() - note_start_positions[index]; + if ( namesz > max_name_size || + namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3*align, namesz - 1); + if ( 0 == descSize ) { + desc = 0; + } + else { + desc = const_cast ( pData + 3*align + + ( ( namesz + align - 1 )/align )*align ); + } + + return true; + } + +//------------------------------------------------------------------------------ + void add_note( Elf_Word type, + const std::string& name, + const void* desc, + Elf_Word descSize ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = convertor( nameLen ); + std::string buffer( reinterpret_cast( &nameLenConv ), align ); + Elf_Word descSizeConv = convertor( descSize ); + buffer.append( reinterpret_cast( &descSizeConv ), align ); + type = convertor( type ); + buffer.append( reinterpret_cast( &type ), align ); + buffer.append( name ); + buffer.append( 1, '\x00' ); + const char pad[] = { '\0', '\0', '\0', '\0' }; + if ( nameLen % align != 0 ) { + buffer.append( pad, align - nameLen % align ); + } + if ( desc != 0 && descSize != 0 ) { + buffer.append( reinterpret_cast( desc ), descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, align - descSize % align ); + } + } + + note_start_positions.push_back( note_section->get_size() ); + note_section->append_data( buffer ); + } + + private: +//------------------------------------------------------------------------------ + void process_section() + { + const endianess_convertor& convertor = elf_file.get_convertor(); + const char* data = note_section->get_data(); + Elf_Xword size = note_section->get_size(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( 0 == data || 0 == size ) { + return; + } + + int align = sizeof( Elf_Word ); + while ( current + 3*align <= size ) { + note_start_positions.push_back( current ); + Elf_Word namesz = convertor( + *(const Elf_Word*)( data + current ) ); + Elf_Word descsz = convertor( + *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); + + current += 3*sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * align + + ( ( descsz + align - 1 ) / align ) * align; + } + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* note_section; + std::vector note_start_positions; +}; + +using note_section_accessor = note_section_accessor_template
; +using const_note_section_accessor = note_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_relocation.hpp b/ZAPDTR/lib/elfio/elfio/elfio_relocation.hpp new file mode 100644 index 000000000..238598e97 --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_relocation.hpp @@ -0,0 +1,373 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_RELOCATION_HPP +#define ELFIO_RELOCATION_HPP + +namespace ELFIO { + +template struct get_sym_and_type; +template<> struct get_sym_and_type< Elf32_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf32_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; + + +//------------------------------------------------------------------------------ +template< class S > +class relocation_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + relocation_section_accessor_template( const elfio& elf_file_, S* section_ ) : + elf_file( elf_file_ ), + relocation_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != relocation_section->get_entry_size() ) { + nRet = relocation_section->get_size() / relocation_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf32_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf32_Rela >( index, offset, symbol, + type, addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf64_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf64_Rela >( index, offset, symbol, + type, addend ); + } + } + + return true; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + Elf_Word& type, + Elf_Sxword& addend, + Elf_Sxword& calcValue ) const + { + // Do regular job + Elf_Word symbol; + bool ret = get_entry( index, offset, symbol, type, addend ); + + // Find the symbol + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + Elf_Half section; + unsigned char other; + + symbol_section_accessor symbols( elf_file, elf_file.sections[get_symbol_table_index()] ); + ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, + size, bind, symbolType, section, other ); + + if ( ret ) { // Was it successful? + switch ( type ) { + case R_386_NONE: // none + calcValue = 0; + break; + case R_386_32: // S + A + calcValue = symbolValue + addend; + break; + case R_386_PC32: // S + A - P + calcValue = symbolValue + addend - offset; + break; + case R_386_GOT32: // G + A - P + calcValue = 0; + break; + case R_386_PLT32: // L + A - P + calcValue = 0; + break; + case R_386_COPY: // none + calcValue = 0; + break; + case R_386_GLOB_DAT: // S + case R_386_JMP_SLOT: // S + calcValue = symbolValue; + break; + case R_386_RELATIVE: // B + A + calcValue = addend; + break; + case R_386_GOTOFF: // S + A - GOT + calcValue = 0; + break; + case R_386_GOTPC: // GOT + A - P + calcValue = 0; + break; + default: // Not recognized symbol! + calcValue = 0; + break; + } + } + + return ret; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rel >( offset, info ); + } + else { + generic_add_entry< Elf64_Rel >( offset, info ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO((Elf_Xword)symbol, type ); + } + + add_entry( offset, info ); + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rela >( offset, info, addend ); + } + else { + generic_add_entry< Elf64_Rela >( offset, info, addend ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type, + Elf_Sxword addend ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info, addend ); + } + +//------------------------------------------------------------------------------ + void + add_entry( string_section_accessor str_writer, + const char* str, + symbol_section_accessor sym_writer, + Elf64_Addr value, + Elf_Word size, + unsigned char sym_info, + unsigned char other, + Elf_Half shndx, + Elf64_Addr offset, + unsigned char type ) + { + Elf_Word str_index = str_writer.add_string( str ); + Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, + sym_info, other, shndx ); + add_entry( offset, sym_index, type ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = 0; + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = convertor( pEntry->r_addend ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_addend = addend; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + entry.r_addend = convertor( entry.r_addend ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* relocation_section; +}; + +using relocation_section_accessor = relocation_section_accessor_template
; +using const_relocation_section_accessor = relocation_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_section.hpp b/ZAPDTR/lib/elfio/elfio/elfio_section.hpp new file mode 100644 index 000000000..3bfc2333c --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_section.hpp @@ -0,0 +1,314 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_SECTION_HPP +#define ELFIO_SECTION_HPP + +#include +#include + +namespace ELFIO { + +class section +{ + friend class elfio; + public: + virtual ~section() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( std::string, name ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); + ELFIO_GET_ACCESS_DECL ( Elf64_Off, offset ); + size_t stream_size; + size_t get_stream_size() const + { + return stream_size; + } + + void set_stream_size(size_t value) + { + stream_size = value; + } + + virtual const char* get_data() const = 0; + virtual void set_data( const char* pData, Elf_Word size ) = 0; + virtual void set_data( const std::string& data ) = 0; + virtual void append_data( const char* pData, Elf_Word size ) = 0; + virtual void append_data( const std::string& data ) = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual void load( std::istream& stream, + std::streampos header_offset ) = 0; + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; + virtual bool is_address_initialized() const = 0; +}; + + +template< class T > +class section_impl : public section +{ + public: +//------------------------------------------------------------------------------ + section_impl( const endianess_convertor* convertor_ ) : convertor( convertor_ ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + is_address_set = false; + data = 0; + data_size = 0; + } + +//------------------------------------------------------------------------------ + ~section_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); + ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); + ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); + ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); + ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); + ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); + ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); + ELFIO_GET_ACCESS ( Elf64_Addr, address, header.sh_addr ); + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + + +//------------------------------------------------------------------------------ + std::string + get_name() const + { + return name; + } + +//------------------------------------------------------------------------------ + void + set_name( std::string name_ ) + { + name = name_; + } + +//------------------------------------------------------------------------------ + void + set_address( Elf64_Addr value ) + { + header.sh_addr = value; + header.sh_addr = (*convertor)( header.sh_addr ); + is_address_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_address_initialized() const + { + return is_address_set; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + void + set_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + delete [] data; + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + size = 0; + } + if ( 0 != data && 0 != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data ); + } + } + + set_size( size ); + } + +//------------------------------------------------------------------------------ + void + set_data( const std::string& str_data ) + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + void + append_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + if ( get_size() + size < data_size ) { + std::copy( raw_data, raw_data + size, data + get_size() ); + } + else { + data_size = 2*( data_size + size); + char* new_data; + try { + new_data = new char[data_size]; + } catch (const std::bad_alloc&) { + new_data = 0; + size = 0; + } + if ( 0 != new_data ) { + std::copy( data, data + get_size(), new_data ); + std::copy( raw_data, raw_data + size, new_data + get_size() ); + delete [] data; + data = new_data; + } + } + set_size( get_size() + size ); + } + } + +//------------------------------------------------------------------------------ + void + append_data( const std::string& str_data ) + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + + stream.seekg ( 0, stream.end ); + set_stream_size ( stream.tellg() ); + + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + + Elf_Xword size = get_size(); + if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() && size < get_stream_size()) { + try { + data = new char[size + 1]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + } + + if ( ( 0 != size ) && ( 0 != data ) ) { + stream.seekg( (*convertor)( header.sh_offset ) ); + stream.read( data, size ); + data[size] = 0; // Ensure data is ended with 0 to avoid oob read + data_size = size; + } + } + } + +//------------------------------------------------------------------------------ + void + save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) + { + if ( 0 != get_index() ) { + header.sh_offset = data_offset; + header.sh_offset = (*convertor)( header.sh_offset ); + } + + save_header( stream, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != 0 ) { + save_data( stream, data_offset ); + } + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + save_header( std::ostream& stream, + std::streampos header_offset ) const + { + stream.seekp( header_offset ); + stream.write( reinterpret_cast( &header ), sizeof( header ) ); + } + +//------------------------------------------------------------------------------ + void + save_data( std::ostream& stream, + std::streampos data_offset ) const + { + stream.seekp( data_offset ); + stream.write( get_data(), get_size() ); + } + +//------------------------------------------------------------------------------ + private: + T header; + Elf_Half index; + std::string name; + char* data; + Elf_Word data_size; + const endianess_convertor* convertor; + bool is_address_set; +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_segment.hpp b/ZAPDTR/lib/elfio/elfio/elfio_segment.hpp new file mode 100644 index 000000000..642fd2907 --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_segment.hpp @@ -0,0 +1,246 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_SEGMENT_HPP +#define ELFIO_SEGMENT_HPP + +#include +#include + +namespace ELFIO { + +class segment +{ + friend class elfio; + public: + virtual ~segment() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + virtual const char* get_data() const = 0; + + virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0; + virtual Elf_Half get_sections_num() const = 0; + virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; + virtual bool is_offset_initialized() const = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual const std::vector& get_sections() const = 0; + virtual void load( std::istream& stream, std::streampos header_offset ) = 0; + virtual void save( std::ostream& stream, std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + + +//------------------------------------------------------------------------------ +template< class T > +class segment_impl : public segment +{ + public: +//------------------------------------------------------------------------------ + segment_impl( endianess_convertor* convertor_ ) : + stream_size( 0 ), index( 0 ), data( 0 ), convertor( convertor_ ) + { + is_offset_set = false; + std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); + } + +//------------------------------------------------------------------------------ + virtual ~segment_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); + ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); + ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); + ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); + size_t stream_size; + +//------------------------------------------------------------------------------ + size_t + get_stream_size() const + { + return stream_size; + } + +//------------------------------------------------------------------------------ + void + set_stream_size(size_t value) + { + stream_size = value; + } + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + Elf_Half + add_section_index( Elf_Half sec_index, Elf_Xword addr_align ) + { + sections.push_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_sections_num() const + { + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_section_index_at( Elf_Half num ) const + { + if ( num < sections.size() ) { + return sections[num]; + } + + return Elf_Half(-1); + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ + void + set_offset( Elf64_Off value ) + { + ph.p_offset = value; + ph.p_offset = (*convertor)( ph.p_offset ); + is_offset_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_offset_initialized() const + { + return is_offset_set; + } + +//------------------------------------------------------------------------------ + const std::vector& + get_sections() const + { + return sections; + } + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + + stream.seekg ( 0, stream.end ); + set_stream_size ( stream.tellg() ); + + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + is_offset_set = true; + + if ( PT_NULL != get_type() && 0 != get_file_size() ) { + stream.seekg( (*convertor)( ph.p_offset ) ); + Elf_Xword size = get_file_size(); + + if ( size > get_stream_size() ) { + data = 0; + } + else { + try { + data = new char[size + 1]; + } catch (const std::bad_alloc&) { + data = 0; + } + + if ( 0 != data ) { + stream.read( data, size ); + data[size] = 0; + } + } + } + } + +//------------------------------------------------------------------------------ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) + { + ph.p_offset = data_offset; + ph.p_offset = (*convertor)(ph.p_offset); + stream.seekp( header_offset ); + stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + +//------------------------------------------------------------------------------ + private: + T ph; + Elf_Half index; + char* data; + std::vector sections; + endianess_convertor* convertor; + bool is_offset_set; +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_strings.hpp b/ZAPDTR/lib/elfio/elfio/elfio_strings.hpp new file mode 100644 index 000000000..552f00029 --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_strings.hpp @@ -0,0 +1,100 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_STRINGS_HPP +#define ELFIO_STRINGS_HPP + +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template< class S > +class string_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + string_section_accessor_template( S* section_ ) : + string_section( section_ ) + { + } + + +//------------------------------------------------------------------------------ + const char* + get_string( Elf_Word index ) const + { + if ( string_section ) { + if ( index < string_section->get_size() ) { + const char* data = string_section->get_data(); + if ( 0 != data ) { + return data + index; + } + } + } + + return 0; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const char* str ) + { + Elf_Word current_position = 0; + + if (string_section) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)string_section->get_size(); + + if ( current_position == 0 ) { + char empty_string = '\0'; + string_section->append_data( &empty_string, 1 ); + current_position++; + } + string_section->append_data( str, (Elf_Word)std::strlen( str ) + 1 ); + } + + return current_position; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + +//------------------------------------------------------------------------------ + private: + S* string_section; +}; + +using string_section_accessor = string_section_accessor_template
; +using const_string_section_accessor = string_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_symbols.hpp b/ZAPDTR/lib/elfio/elfio/elfio_symbols.hpp new file mode 100644 index 000000000..d18756a9a --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_symbols.hpp @@ -0,0 +1,282 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_SYMBOLS_HPP +#define ELFIO_SYMBOLS_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template< class S > +class symbol_section_accessor_template +{ + public: +//------------------------------------------------------------------------------ + symbol_section_accessor_template( const elfio& elf_file_, S* symbol_section_ ) : + elf_file( elf_file_ ), + symbol_section( symbol_section_ ) + { + find_hash_section(); + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_symbols_num() const + { + Elf_Xword nRet = 0; + if ( 0 != symbol_section->get_entry_size() ) { + nRet = symbol_section->get_size() / symbol_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + else { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + + return ret; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( 0 != get_hash_table_index() ) { + Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); + Elf_Word nchain = *(const Elf_Word*)( hash_section->get_data() + + sizeof( Elf_Word ) ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + + Elf_Word y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + if ( str == name ) { + ret = true; + } + } + + return ret; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word nRet; + + if ( symbol_section->get_size() == 0 ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + else { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + else { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word index = pStrWriter.add_string( str ); + return add_symbol( index, value, size, info, other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( pStrWriter, str, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + find_hash_section() + { + hash_section = 0; + hash_section_index = 0; + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() ) { + hash_section = sec; + hash_section_index = i; + } + } + } + +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)symbol_section->get_link(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_hash_table_index() const + { + return hash_section_index; + } + +//------------------------------------------------------------------------------ + template< class T > + bool + generic_get_symbol( Elf_Xword index, + std::string& name, Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( index < get_symbols_num() ) { + const T* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + + section* string_section = elf_file.sections[get_string_table_index()]; + string_section_accessor str_reader( string_section ); + const char* pStr = str_reader.get_string( convertor( pSym->st_name ) ); + if ( 0 != pStr ) { + name = pStr; + } + value = convertor( pSym->st_value ); + size = convertor( pSym->st_size ); + bind = ELF_ST_BIND( pSym->st_info ); + type = ELF_ST_TYPE( pSym->st_info ); + section_index = convertor( pSym->st_shndx ); + other = pSym->st_other; + + ret = true; + } + + return ret; + } + +//------------------------------------------------------------------------------ + template< class T > + Elf_Word + generic_add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.st_name = convertor( name ); + entry.st_value = value; + entry.st_value = convertor( entry.st_value ); + entry.st_size = size; + entry.st_size = convertor( entry.st_size ); + entry.st_info = convertor( info ); + entry.st_other = convertor( other ); + entry.st_shndx = convertor( shndx ); + + symbol_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + + Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1; + + return nRet; + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* symbol_section; + Elf_Half hash_section_index; + const section* hash_section; +}; + +using symbol_section_accessor = symbol_section_accessor_template
; +using const_symbol_section_accessor = symbol_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/ZAPDTR/lib/elfio/elfio/elfio_utils.hpp b/ZAPDTR/lib/elfio/elfio/elfio_utils.hpp new file mode 100644 index 000000000..2baf5a77c --- /dev/null +++ b/ZAPDTR/lib/elfio/elfio/elfio_utils.hpp @@ -0,0 +1,209 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +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. +*/ + +#ifndef ELFIO_UTILS_HPP +#define ELFIO_UTILS_HPP + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( TYPE value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( TYPE value ) = 0 + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class endianess_convertor { + public: +//------------------------------------------------------------------------------ + endianess_convertor() + { + need_conversion = false; + } + +//------------------------------------------------------------------------------ + void + setup( unsigned char elf_file_encoding ) + { + need_conversion = ( elf_file_encoding != get_host_encoding() ); + } + +//------------------------------------------------------------------------------ + uint64_t + operator()( uint64_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00000000000000FFull ) << 56 ) | + ( ( value & 0x000000000000FF00ull ) << 40 ) | + ( ( value & 0x0000000000FF0000ull ) << 24 ) | + ( ( value & 0x00000000FF000000ull ) << 8 ) | + ( ( value & 0x000000FF00000000ull ) >> 8 ) | + ( ( value & 0x0000FF0000000000ull ) >> 24 ) | + ( ( value & 0x00FF000000000000ull ) >> 40 ) | + ( ( value & 0xFF00000000000000ull ) >> 56 ); + + return value; + } + +//------------------------------------------------------------------------------ + int64_t + operator()( int64_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int64_t)(*this)( (uint64_t)value ); + } + +//------------------------------------------------------------------------------ + uint32_t + operator()( uint32_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x000000FF ) << 24 ) | + ( ( value & 0x0000FF00 ) << 8 ) | + ( ( value & 0x00FF0000 ) >> 8 ) | + ( ( value & 0xFF000000 ) >> 24 ); + + return value; + } + +//------------------------------------------------------------------------------ + int32_t + operator()( int32_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int32_t)(*this)( (uint32_t)value ); + } + +//------------------------------------------------------------------------------ + uint16_t + operator()( uint16_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00FF ) << 8 ) | + ( ( value & 0xFF00 ) >> 8 ); + + return value; + } + +//------------------------------------------------------------------------------ + int16_t + operator()( int16_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int16_t)(*this)( (uint16_t)value ); + } + +//------------------------------------------------------------------------------ + int8_t + operator()( int8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + uint8_t + operator()( uint8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + unsigned char + get_host_encoding() const + { + static const int tmp = 1; + if ( 1 == *(const char*)&tmp ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + +//------------------------------------------------------------------------------ + private: + bool need_conversion; +}; + + +//------------------------------------------------------------------------------ +inline +uint32_t +elf_hash( const unsigned char *name ) +{ + uint32_t h = 0, g; + while ( *name ) { + h = (h << 4) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/ZAPDTR/lib/libgfxd/.gitrepo b/ZAPDTR/lib/libgfxd/.gitrepo new file mode 100644 index 000000000..4c8b7fe76 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@github.com:glankk/libgfxd.git + branch = master + commit = 008f73dca8ebc9151b205959b17773a19c5bd0da + parent = c92cfda733aa740a53129a21f69c8abb08a465c7 + method = merge + cmdver = 0.4.3 diff --git a/ZAPDTR/lib/libgfxd/LICENSE b/ZAPDTR/lib/libgfxd/LICENSE new file mode 100644 index 000000000..a7655f829 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016-2021 glank (glankk@github.com) + +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. diff --git a/ZAPDTR/lib/libgfxd/Makefile b/ZAPDTR/lib/libgfxd/Makefile new file mode 100644 index 000000000..b340ff5c0 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/Makefile @@ -0,0 +1,25 @@ +CFLAGS = -Wall -O2 -g +UC_OBJ = uc_f3d.o uc_f3db.o uc_f3dex.o uc_f3dexb.o uc_f3dex2.o +OBJ = gfxd.o $(UC_OBJ) +LIB = libgfxd.a + +CPPFLAGS-$(MT) += -DCONFIG_MT +CPPFLAGS += $(CPPFLAGS-y) + +.PHONY: all +all: $(LIB) + +.PHONY: clean +clean: + rm -f $(OBJ) $(LIB) + +.INTERMEDIATE: $(OBJ) + +$(OBJ): gbi.h gfxd.h priv.h +$(UC_OBJ): uc.c uc_argfn.c uc_argtbl.c uc_macrofn.c uc_macrotbl.c + +$(LIB): $(OBJ) + $(AR) rcs $@ $^ + +%.o: %.c + $(COMPILE.c) $(OUTPUT_OPTION) $< diff --git a/ZAPDTR/lib/libgfxd/README.md b/ZAPDTR/lib/libgfxd/README.md new file mode 100644 index 000000000..2e8258943 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/README.md @@ -0,0 +1,478 @@ +## Installing +Run `make` for a single-threaded build, or `make MT=y` for a multi-threaded +build. Copy `libgfxd.a` to your lib directory, and `gfxd.h` to your include +directory. + +## Example usage +Example source code: +``` +#include +#include + +static int macro_fn(void) +{ + /* Print a tab before each macro, and a comma and newline after each + macro */ + gfxd_puts("\t"); + gfxd_macro_dflt(); /* Execute the default macro handler */ + gfxd_puts(",\n"); + + return 0; +} + +int main() +{ + /* Read from stdin and write to stdout */ + gfxd_input_fd(fileno(stdin)); + gfxd_output_fd(fileno(stdout)); + + /* Override the default macro handler to make the output prettier */ + gfxd_macro_fn(macro_fn); + + /* Select F3DEX as the target microcode */ + gfxd_target(gfxd_f3dex); + + /* Set the input endianness to big endian, and the word size to 4 */ + gfxd_endian(gfxd_endian_big, 4); + + /* Print an opening brace */ + gfxd_puts("{\n"); + + /* Execute until the end of input, or until encountering an invalid + command */ + gfxd_execute(); + + /* Print a closing brace */ + gfxd_puts("}\n"); +} +``` + +Example input (binary): +``` +0xe7000000, 0x00000000, +0xfc127e03, 0xfffffdf8, +0xb900031d, 0xc8112078, +0xb6000000, 0x000e0000, +0xb7000000, 0x00012000, +0xfa000000, 0xffffffff, +0x040030bf, 0x000002e0, +0xb1000204, 0x00020604, +0xb1080a0c, 0x000a0e0c, +0xb10a1012, 0x000a120e, +0xb1140200, 0x00140016, +0xb8000000, 0x00000000, +``` + +Example output: +``` +{ + gsDPPipeSync(), + gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, 0, 0, 0, 1, COMBINED, 0, PRIMITIVE, 0, 0, 0, 0, COMBINED), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_OPA_SURF2), + gsSPClearGeometryMode(G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR), + gsSPSetGeometryMode(G_CULL_BACK | G_FOG), + gsDPSetPrimColor(0, 0, 0xFF, 0xFF, 0xFF, 0xFF), + gsSPVertex(0x000002E0, 12, 0), + gsSP2Triangles(0, 1, 2, 0, 1, 3, 2, 0), + gsSP2Triangles(4, 5, 6, 0, 5, 7, 6, 0), + gsSP1Quadrangle(5, 8, 9, 7, 0), + gsSP1Quadrangle(10, 1, 0, 11, 0), + gsSPEndDisplayList(), +} +``` + +## Input/output methods +The input consists of any number of `Gfx` packets, and the output is the +decompiled macros in plain-text. The endianness and microcode type of the input +can be set using `gfxd_endian` and `gfxd_target`. + +Several methods of doing I/O are available. No method is selected by default, +meaning there will be no input, and any output will be discarded. + +--- + +##### `void gfxd_input_buffer(const void *buf, int size)` +##### `void gfxd_output_buffer(char *buf, int size)` +Use the buffer pointed to by `buf`, of `size` bytes. + +--- + +##### `void gfxd_input_fd(int fd)` +##### `void gfxd_output_fd(int fd)` +Use `read()` / `write()` with the provided file descriptor, `fd`. + +--- + +##### `typedef int gfxd_input_fn_t(void *buf, int count)` +##### `typedef int gfxd_output_fn_t(const char *buf, int count)` +##### `void gfxd_input_callback(gfxd_input_fn_t *fn)` +##### `void gfxd_output_callback(gfxd_output_fn_t *fn)` +Use the provided callback function, `fn`. `fn` should copy at most `count` +bytes to/from `buf`, and return the number of bytes actually copied. The input +callback should return 0 to signal end of input. + +## Handlers +The macro handler function is responsible for writing the output of each +decompiled macro. The default macro handler is `gfxd_macro_dflt`, but this can +be changed with `gfxd_macro_fn`. The new handler can extend the default +function by calling `gfxd_macro_dflt` within it, or it can override it +completely. + +--- + +##### `int gfxd_macro_dflt()` +The default macro handler. Outputs the macro name, dynamic display list pointer +if one has been specified, and then each argument in order using the function +registered using `gfxd_arg_fn` (`gfxd_arg_dflt` by default), and returns zero. +Because it is designed to be extended, it only outputs the macro text, without +any whitespace or punctuation before or after. When this function is used as +the sole macro handler, it will output the entire display list on one line +without any separation between macros, which is probably not what you want. + +--- + +##### `void gfxd_macro_fn(gfxd_macro_fn_t *fn)` +Set `fn` to be the macro handler function. `fn` can be null, in which case the +handler is reset to the default. + +--- + +##### `void gfxd_arg_dflt(int arg_num)` +The default argument handler for `gfxd_macro_dflt`. For the argument with index +`arg_num`, calls `gfxd_arg_callbacks`, and prints the argument value if the +callback returns zero, or if there is no callback for the given argument. + +--- + +##### `void gfxd_arg_fn(gfxd_arg_fn_t *fn)` +Set `fn` to be the argument handler function, called by `gfxd_macro_dflt`, +for each argument in the current macro, not counting the dynamic display list +pointer if one has been specified. `fn` can be null, in which case the handler +is reset to the default. This only affects the output of `gfxd_macro_dflt`, and +has no observable effect if `gfxd_macro_dflt` is overridden (not extended). + +## Argument callbacks +Callbacks can be registered that will be executed when an argument of a certain +type is encountered. The default argument handler `gfxd_arg_dflt` will execute +callbacks as needed using `gfxd_arg_callbacks`. If a callback returns non-zero, +`gfxd_arg_dflt` will not output anything. This is to allow callbacks to +override the default argument output. Otherwise, `gfxd_arg_dflt` will output +the argument value after the callback function's output. + +--- + +##### `int gfxd_arg_callbacks(int arg_num)` +Examines the argument with index `arg_num` and executes the callback function +for that argument type, if such a callback is supported and has been +registered. This function returns the value that was returned by the callback +function. If no callback function has been registered for the argument type, +zero is returned. + +Most argument callbacks have some extra parameters containing information that +might be relevant to the argument that triggered the callback. The extra +information is extracted only from the current macro, as gfxd does not retain +any context information from previous or subsequent macros. If any of the extra +parameter values is not available in the current macro, the value for that +parameter is substituted with `-1` for signed parameters, and zero for unsigned +parameters. + +--- + +##### `typedef int gfxd_tlut_fn_t(uint32_t tlut, int32_t idx, int32_t count)` +##### `void gfxd_tlut_callback(gfxd_tlut_fn_t *fn)` +Set the callback function for palette arguments. The argument type is +`gfxd_Tlut`. The palette index is in `idx` and the number of colors in `count`. + +--- + +##### `typedef int gfxd_timg_fn_t(uint32_t timg, int32_t fmt, int32_t siz, int32_t width, int32_t height, int32_t pal)` +##### `void gfxd_timg_callback(gfxd_timg_fn_t *fn)` +Set the callback function for texture arguments. The argument type is +`gfxd_Timg`. The image format is in `fmt` and `siz`, the dimensions in `width` +and `height`, and the palette index in `pal`. + +--- + +##### `typedef int gfxd_cimg_fn_t(uint32_t cimg, int32_t fmt, int32_t siz, int32_t width)` +##### `void gfxd_cimg_callback(gfxd_cimg_fn_t *fn)` +Set the callback function for frame buffer arguments. The argument type is +`gfxd_Cimg`. The image format is in `fmt` and `siz`, and the horizontal +resolution in `width`. + +--- + +##### `typedef int gfxd_zimg_fn_t(uint32_t zimg)` +##### `void gfxd_zimg_callback(gfxd_zimg_fn_t *fn)` +Set the callback function for depth buffer arguments. The argument type is +`gfxd_Zimg`. + +--- + +##### `typedef int gfxd_dl_fn_t(uint32_t dl)` +##### `void gfxd_dl_callback(gfxd_dl_fn_t *fn)` +Set the callback function for display list arguments. The argument type is +`gfxd_Dl`. + +--- + +##### `typedef int gfxd_mtx_fn_t(uint32_t mtx)` +##### `void gfxd_mtx_callback(gfxd_mtx_fn_t *fn)` +Set the callback function for matrix arguments. The argument type is +`gfxd_Mtxptr`. + +--- + +##### `typedef int gfxd_lookat_fn_t(uint32_t lookat, int32_t count)` +##### `void gfxd_lookat_callback(gfxd_lookat_fn_t *fn)` +Set the callback function for lookat array arguments. The argument type is +`gfxd_Lookatptr`. The number of lookat structures (1 or 2) is in `count`. + +--- + +##### `typedef int gfxd_light_fn_t(uint32_t light, int32_t count)` +##### `void gfxd_light_callback(gfxd_light_fn_t *fn)` +Set the callback function for light array arguments. The argument type is +`gfxd_Lightptr`. The number of light structures is in `count`. + +--- + +##### `typedef int gfxd_seg_fn_t(uint32_t seg, int32_t num)` +##### `void gfxd_seg_callback(gfxd_seg_fn_t *fn)` +Set the callback function for segment base arguments. The argument type is +`gfxd_Segptr`. The segment number is in `num`. + +--- + +##### `typedef int gfxd_vtx_fn_t(uint32_t vtx, int32_t num)` +##### `void gfxd_vtx_callback(gfxd_vtx_fn_t *fn)` +Set the callback function for vertex array arguments. The argument type is +`gfxd_Vtxptr`. The number of vertex structures is in `num`. + +--- + +##### `typedef int gfxd_vp_fn_t(uint32_t vp)` +##### `void gfxd_vp_callback(gfxd_vp_fn_t *fn)` +Set the callback function for viewport arguments. The argument type is +`gfxd_Vp`. + +--- + +##### `typedef int gfxd_uctext_fn_t(uint32_t text, uint32_t size)` +##### `void gfxd_uctext_callback(gfxd_uctext_fn_t *fn)` +Set the callback function for microcode text arguments. The argument type is +`gfxd_Uctext`. The size of the text segment is in `size`. + +--- + +##### `typedef int gfxd_ucdata_fn_t(uint32_t data, uint32_t size)` +##### `void gfxd_ucdata_callback(gfxd_ucdata_fn_t *fn)` +Set the callback function for microcode data arguments. The argument type is +`gfxd_Ucdata`. The size of the data segment is in `size`. + +--- + +##### `typedef int gfxd_dram_fn_t(uint32_t dram, uint32_t size)` +##### `void gfxd_dram_callback(gfxd_dram_fn_t *fn)` +Set the callback function for generic pointer arguments. The argument type is +`gfxd_Dram`. The size of the data is in `size`. + +## General settings +These functions control general input and output settings. + +--- + +##### `void gfxd_target(gfxd_ucode_t ucode)` +Select `ucode` as the target microcode. `ucode` can be `gfxd_f3d`, `gfxd_f3db`, +`gfxd_f3dex`, `gfxd_f3dexb`, or `gfxd_f3dex2`. The microcode must be selected +before `gfxd_execute`, as no microcode is selected by default. + +--- + +##### `void gfxd_endian(int endian, int wordsize)` +Select `endian` as the endianness of the input, and `wordsize` as the size of +each word in number of bytes. `endian` can be `gfxd_endian_big`, +`gfxd_endian_little`, or `gfxd_endian_host` (the endianness of the host +machine). `wordsize` can be 1, 2, 4, or 8. Big endian is selected by default, +with a word size of 4. + +--- + +##### `void gfxd_dynamic(const char *arg)` +Enable or disable the use of dynamic `g` macros instead of static `gs` macros, +and select the dynamic display list pointer argument to be used. `arg` will be +used by `gfxd_macro_dflt` as the first argument to dynamic macros. If `arg` is +null, dynamic macros are disabled, and `gs` macros are used. Also affects the +result of `gfxd_macro_name`, as it will return either the dynamic or static +version of the macro name as selected by this setting. + +--- + +##### `void gfxd_enable(int cap)` +##### `void gfxd_disable(int cap)` +Enable or disable the feature specified by `cap`. Can be one of the following; +- `gfxd_stop_on_invalid`: Stop execution when encountering an invalid macro. +Enabled by default. +- `gfxd_stop_on_end`: Stop execution when encountering a `SPBranchList` or +`SPEndDisplayList`. Enabled by default. +- `gfxd_emit_dec_color`: Print color components as decimal instead of +hexadecimal. Disabled by default. +- `gfxd_emit_q_macro`: Print fixed-point conversion `q` macros for fixed-point +values. Disabled by default. +- `gfxd_emit_ext_macro`: Emit non-standard macros. Some commands are valid +(though possibly meaningless), but have no macros associated with them, such as +a standalone `G_RDPHALF_1`. When this feature is enabled, such a command will +produce a non-standard `gsDPHalf1` macro instead of a raw hexadecimal command. +Also enables some non-standard multi-packet texture loading macros. Disabled by +default. + +--- + +##### `void gfxd_udata_set(void *ptr)` +##### `void *gfxd_udata_get(void)` +Set or get a generic pointer that can be used to pass user-defined data in and +out of callback functions. + +## Execution +Decompilation is started using the `gfxd_execute` function. When gfxd is +executing (i.e. after `gfxd_execute` has been entered, and before it returns), +the general settings and the I/O settings should not be changed. + +--- + +##### `int gfxd_execute()` +Start executing gfxd with the current settings. For each macro, the macro +handler registered with `gfxd_macro_fn` is called. Execution ends when the +input ends, the macro handler returns non-zero, when an invalid macro is +encountered and `gfxd_stop_on_invalid` is enabled, or when `SPBranchList` or +`SPEndDisplayList` is encountered and `gfxd_stop_on_end` is enabled. If +execution ends due to an invalid macro, `-1` is returned. If execution ends +because the macro handler returns non-zero, the return value from the macro +handler is returned. Otherwise zero is returned. + +## Macro information +The following functions can be used to obtain information about the current +macro and its arguments. They should only be used in custom handlers and +callbacks from within `gfxd_execute`. If used elsewhere, their behavior is +undefined. + +--- + +##### `int gfxd_macro_offset()` +Returns the offset in the input data of the current macro. The offset starts +at zero when `gfxd_execute` is called. + +--- + +##### `int gfxd_macro_packets()` +Returns the number of `Gfx` packets within the current macro. + +--- + +##### `const void *gfxd_macro_data()` +Returns a pointer to the input data for the current macro. The data is not +byte-swapped. The data has a length of `sizeof(Gfx) * gfxd_macro_packets()`. + +--- + +##### `int gfxd_macro_id()` +Returns a number that uniquely identifies the current macro. The number will +be one of the constants in `gfxd.h`. + +--- + +##### `const char *gfxd_macro_name()` +Returns the name of the current macro. If the macro does not have a name (i.e. +it's invalid), null is returned. If a dynamic display list pointer has been +specified, the dynamic `g` version is returned. Otherwise the static `gs` +version is returned. The returned pointer is invalidated by a subsequent call +to `gfxd_macro_name`. + +--- + +##### `int gfxd_arg_count()` +Returns the number of arguments to the current macro, not including a dynamic +display list pointer if one has been specified. + +--- + +##### `int gfxd_arg_type(int arg_num)` +Returns a number that identifies the type of the argument with index `arg_num`. +The number will be one of the constants in `gfxd.h`. + +--- + +##### `const char *gfxd_arg_name(int arg_num)` +Returns the name of the argument with index `arg_num`. Argument names are not +canonical, nor are they needed for macro disassembly, but they can be useful +for informational and diagnostic purposes. + +--- + +##### `int gfxd_arg_fmt(int arg_num)` +Returns the data format of the argument with index `arg_num`. The return value +will be `gfxd_argfmt_i` for `int32_t`, `gfxd_argfmt_u` for `uint32_t`, or +`gfxd_argfmt_f` for `float`. When accessing the value of the argument with +`gfxd_arg_value`, the member with the corresponding type should be used. + +--- + +##### `const gfxd_value_t *gfxd_arg_value(int arg_num)` +Returns a pointer to the value of the argument with index `arg_num`. The value +is a union of type `gfxd_value_t` with the following layout; +``` +typedef union +{ + int32_t i; + uint32_t u; + float f; +} gfxd_value_t +``` + +--- + +##### `const gfxd_value_t *gfxd_value_by_type(int type, int idx)` +Returns a pointer to the value of the argument that is of `type`, and has order +`idx` in all arguments of that type. An `idx` of zero returns the first +argument that has the specified type. If there is no argument with the given +type and order, null is returned. + +--- + +##### `int gfxd_arg_valid(int arg_num)` +Returns non-zero if the argument with index `arg_num` is "valid", for some +definition of valid. An invalid argument generally means that the disassembler +found inconsistencies in the input data, or that the data can not be reproduced +by the current macro type. The argument still has a value that can be printed, +though the value is not guaranteed to make any sense. + +## Custom output +When the default handlers are overridden or extended, the custom handler +functions will want to do some output of their own. The following methods are +available for inserting custom text into the gfxd output. + +--- + +##### `int gfxd_write(const void *buf, int count)` +Insert `count` bytes from the buffer at `buf` into the output. The number of +characters written is returned. + +--- + +##### `int gfxd_puts(const char *str)` +Insert the null-terminated string at `str` into the output. The number of +characters written is returned. + +--- + +##### `int gfxd_printf(const char *fmt, ...)` +Insert the printf-formatted string described by `fmt` and additional arguments +into the output. Limited to 255 characters. The number of characters written is +returned. + +--- + +##### `int gfxd_print_value(int type, const gfxd_value_t *value)` +Insert the type-formatted value into the output. The type should be one of the +constants in `gfxd.h`. The number of characters written is returned. The +macro argument with index `n` can be printed with +`gfxd_print_value(gfxd_arg_type(n), gfxd_arg_value(n))`. diff --git a/ZAPDTR/lib/libgfxd/gbi.h b/ZAPDTR/lib/libgfxd/gbi.h new file mode 100644 index 000000000..69fa7f12e --- /dev/null +++ b/ZAPDTR/lib/libgfxd/gbi.h @@ -0,0 +1,3838 @@ +/** + * gbi.h version 0.3.6 + * n64 graphics microcode interface library + * compatible with fast3d, f3dex, f3dex2, s2dex, and s2dex2 + * + * select a microcode with one of these preprocessor definitions; + * #define F3D_GBI + * for fast3d (selected automatically by default), or + * #define F3DEX_GBI + * for f3dex/s2dex, or + * #define F3DEX_GBI_2 + * for f3dex2/s2dex2 + * + * for early versions of fast3d and f3dex, also define the following; + * #define F3D_BETA + * + * ido incompatibilities; + * - use of c99 variadic macros + * - use of c99 fixed-width integer types + * - use of c99 designated initializers + * - use of c99 compound literals + * - use of c11 _Alignas + * - use of gnu c compound expressions + * - use of gnu c __typeof__ + * + * libultra incompatibilities; + * - many private, undocumented, or obsolete macros not commonly used by + * programmers are missing + * - many different implementation details that will produce matching gbi, + * but not matching code +**/ + +#ifndef N64_GBI_H +#define N64_GBI_H + +#include + +/* use fast3d by default */ +#if !defined(F3D_GBI) && !defined(F3DEX_GBI) && !defined(F3DEX_GBI_2) +# define F3D_GBI +#endif + +/* commands for fast3d and f3dex */ +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define G_SPNOOP 0x00 +# define G_MTX 0x01 +# define G_MOVEMEM 0x03 +# define G_VTX 0x04 +# define G_DL 0x06 +# if defined(F3D_BETA) +# define G_RDPHALF_2 0xB2 +# define G_RDPHALF_1 0xB3 +# define G_PERSPNORM 0xB4 +# else +# define G_RDPHALF_2 0xB3 +# define G_RDPHALF_1 0xB4 +# endif +# define G_LINE3D 0xB5 +# define G_CLEARGEOMETRYMODE 0xB6 +# define G_SETGEOMETRYMODE 0xB7 +# define G_ENDDL 0xB8 +# define G_SETOTHERMODE_L 0xB9 +# define G_SETOTHERMODE_H 0xBA +# define G_TEXTURE 0xBB +# define G_MOVEWORD 0xBC +# define G_POPMTX 0xBD +# define G_CULLDL 0xBE +# define G_TRI1 0xBF +# define G_NOOP 0xC0 +#endif + +/* commands for f3dex */ +#if defined(F3DEX_GBI) +# define G_LOAD_UCODE 0xAF +# define G_BRANCH_Z 0xB0 +# define G_TRI2 0xB1 +# if !defined(F3D_BETA) +# define G_MODIFYVTX 0xB2 +# endif +#endif + +/* commands for f3dex2 */ +#if defined(F3DEX_GBI_2) +# define G_NOOP 0x00 +# define G_VTX 0x01 +# define G_MODIFYVTX 0x02 +# define G_CULLDL 0x03 +# define G_BRANCH_Z 0x04 +# define G_TRI1 0x05 +# define G_TRI2 0x06 +# define G_QUAD 0x07 +# define G_LINE3D 0x08 +# define G_SPECIAL_3 0xD3 +# define G_SPECIAL_2 0xD4 +# define G_SPECIAL_1 0xD5 +# define G_DMA_IO 0xD6 +# define G_TEXTURE 0xD7 +# define G_POPMTX 0xD8 +# define G_GEOMETRYMODE 0xD9 +# define G_MTX 0xDA +# define G_MOVEWORD 0xDB +# define G_MOVEMEM 0xDC +# define G_LOAD_UCODE 0xDD +# define G_DL 0xDE +# define G_ENDDL 0xDF +# define G_SPNOOP 0xE0 +# define G_RDPHALF_1 0xE1 +# define G_SETOTHERMODE_L 0xE2 +# define G_SETOTHERMODE_H 0xE3 +# define G_RDPHALF_2 0xF1 +#endif + +/* rdp commands */ +#define G_TEXRECT 0xE4 +#define G_TEXRECTFLIP 0xE5 +#define G_RDPLOADSYNC 0xE6 +#define G_RDPPIPESYNC 0xE7 +#define G_RDPTILESYNC 0xE8 +#define G_RDPFULLSYNC 0xE9 +#define G_SETKEYGB 0xEA +#define G_SETKEYR 0xEB +#define G_SETCONVERT 0xEC +#define G_SETSCISSOR 0xED +#define G_SETPRIMDEPTH 0xEE +#define G_RDPSETOTHERMODE 0xEF +#define G_LOADTLUT 0xF0 +#define G_SETTILESIZE 0xF2 +#define G_LOADBLOCK 0xF3 +#define G_LOADTILE 0xF4 +#define G_SETTILE 0xF5 +#define G_FILLRECT 0xF6 +#define G_SETFILLCOLOR 0xF7 +#define G_SETFOGCOLOR 0xF8 +#define G_SETBLENDCOLOR 0xF9 +#define G_SETPRIMCOLOR 0xFA +#define G_SETENVCOLOR 0xFB +#define G_SETCOMBINE 0xFC +#define G_SETTIMG 0xFD +#define G_SETZIMG 0xFE +#define G_SETCIMG 0xFF + +/* commands for s2dex */ +#if defined(F3DEX_GBI) +# define G_BG_1CYC 0x01 +# define G_BG_COPY 0x02 +# define G_OBJ_RECTANGLE 0x03 +# define G_OBJ_SPRITE 0x04 +# define G_OBJ_MOVEMEM 0x05 +# define G_SELECT_DL 0xB0 +# define G_OBJ_RENDERMODE 0xB1 +# define G_OBJ_RECTANGLE_R 0xB2 +# define G_OBJ_LOADTXTR 0xC1 +# define G_OBJ_LDTX_SPRITE 0xC2 +# define G_OBJ_LDTX_RECT 0xC3 +# define G_OBJ_LDTX_RECT_R 0xC4 +#endif + +/* commands for s2dex2 */ +#if defined(F3DEX_GBI_2) +# define G_OBJ_RECTANGLE 0x01 +# define G_OBJ_SPRITE 0x02 +# define G_SELECT_DL 0x04 +# define G_OBJ_LOADTXTR 0x05 +# define G_OBJ_LDTX_SPRITE 0x06 +# define G_OBJ_LDTX_RECT 0x07 +# define G_OBJ_LDTX_RECT_R 0x08 +# define G_BG_1CYC 0x09 +# define G_BG_COPY 0x0A +# define G_OBJ_RENDERMODE 0x0B +# define G_OBJ_RECTANGLE_R 0xDA +# define G_OBJ_MOVEMEM 0xDC +#endif + +/* commands for s2dex and s2dex2 */ +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +# define G_RDPHALF_0 0xE4 +#endif + +/* image formats */ +#define G_IM_FMT_RGBA 0 +#define G_IM_FMT_YUV 1 +#define G_IM_FMT_CI 2 +#define G_IM_FMT_IA 3 +#define G_IM_FMT_I 4 +#define G_IM_SIZ_4b 0 +#define G_IM_SIZ_8b 1 +#define G_IM_SIZ_16b 2 +#define G_IM_SIZ_32b 3 + +/* texture settings */ +#define G_TX_NOMIRROR (gI_(0b0) << 0) +#define G_TX_MIRROR (gI_(0b1) << 0) +#define G_TX_WRAP (gI_(0b0) << 1) +#define G_TX_CLAMP (gI_(0b1) << 1) +#define G_TX_NOMASK gI_(0) +#define G_TX_NOLOD gI_(0) +#define G_OFF gI_(0) +#define G_ON gI_(1) + +/* tile indices */ +#define G_TX_LOADTILE 7 +#define G_TX_RENDERTILE 0 + +/* loadblock constants */ +#define G_TX_DXT_FRAC 11 +#define G_TX_LDBLK_MAX_TXL 2047 + +/* geometry mode */ +#define G_ZBUFFER (gI_(0b1) << 0) +#define G_SHADE (gI_(0b1) << 2) +#define G_CULL_BOTH (G_CULL_FRONT | G_CULL_BACK) +#define G_FOG (gI_(0b1) << 16) +#define G_LIGHTING (gI_(0b1) << 17) +#define G_TEXTURE_GEN (gI_(0b1) << 18) +#define G_TEXTURE_GEN_LINEAR (gI_(0b1) << 19) +#define G_LOD (gI_(0b1) << 20) + +/* geometry mode for fast3d */ +#if defined(F3D_GBI) +# define G_CLIPPING (gI_(0b0) << 0) +#endif + +/* geometry mode for fast3d and f3dex */ +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define G_TEXTURE_ENABLE (gI_(0b1) << 1) +# define G_SHADING_SMOOTH (gI_(0b1) << 9) +# define G_CULL_FRONT (gI_(0b1) << 12) +# define G_CULL_BACK (gI_(0b1) << 13) +#endif + +/* geometry mode for f3dex and f3dex2 */ +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +# define G_CLIPPING (gI_(0b1) << 23) +#endif + +/* geometry mode for f3dex2 */ +#if defined(F3DEX_GBI_2) +# define G_TEXTURE_ENABLE (gI_(0b0) << 0) +# define G_CULL_FRONT (gI_(0b1) << 9) +# define G_CULL_BACK (gI_(0b1) << 10) +# define G_SHADING_SMOOTH (gI_(0b1) << 21) +#endif + +/* othermode lo */ +#define G_MDSFT_ALPHACOMPARE 0 +#define G_MDSFT_ZSRCSEL 2 +#define G_MDSFT_RENDERMODE 3 +#define G_MDSFT_BLENDER 16 +#define G_MDSIZ_ALPHACOMPARE 2 +#define G_MDSIZ_ZSRCSEL 1 +#define G_MDSIZ_RENDERMODE 29 +#define G_MDSIZ_BLENDER 13 + +#define G_AC_NONE (gI_(0b00) << G_MDSFT_ALPHACOMPARE) +#define G_AC_THRESHOLD (gI_(0b01) << G_MDSFT_ALPHACOMPARE) +#define G_AC_DITHER (gI_(0b11) << G_MDSFT_ALPHACOMPARE) +#define G_ZS_PIXEL (gI_(0b0) << G_MDSFT_ZSRCSEL) +#define G_ZS_PRIM (gI_(0b1) << G_MDSFT_ZSRCSEL) +#define AA_EN (gI_(0b1) << (G_MDSFT_RENDERMODE + 0)) +#define Z_CMP (gI_(0b1) << (G_MDSFT_RENDERMODE + 1)) +#define Z_UPD (gI_(0b1) << (G_MDSFT_RENDERMODE + 2)) +#define IM_RD (gI_(0b1) << (G_MDSFT_RENDERMODE + 3)) +#define CLR_ON_CVG (gI_(0b1) << (G_MDSFT_RENDERMODE + 4)) +#define CVG_DST_CLAMP (gI_(0b00) << (G_MDSFT_RENDERMODE + 5)) +#define CVG_DST_WRAP (gI_(0b01) << (G_MDSFT_RENDERMODE + 5)) +#define CVG_DST_FULL (gI_(0b10) << (G_MDSFT_RENDERMODE + 5)) +#define CVG_DST_SAVE (gI_(0b11) << (G_MDSFT_RENDERMODE + 5)) +#define ZMODE_OPA (gI_(0b00) << (G_MDSFT_RENDERMODE + 7)) +#define ZMODE_INTER (gI_(0b01) << (G_MDSFT_RENDERMODE + 7)) +#define ZMODE_XLU (gI_(0b10) << (G_MDSFT_RENDERMODE + 7)) +#define ZMODE_DEC (gI_(0b11) << (G_MDSFT_RENDERMODE + 7)) +#define CVG_X_ALPHA (gI_(0b1) << (G_MDSFT_RENDERMODE + 9)) +#define ALPHA_CVG_SEL (gI_(0b1) << (G_MDSFT_RENDERMODE + 10)) +#define FORCE_BL (gI_(0b1) << (G_MDSFT_RENDERMODE + 11)) + +#define G_BL_1MA gI_(0b00) +#define G_BL_1 gI_(0b10) +#define G_BL_0 gI_(0b11) +#define G_BL_CLR_IN gI_(0b00) +#define G_BL_CLR_MEM gI_(0b01) +#define G_BL_CLR_BL gI_(0b10) +#define G_BL_CLR_FOG gI_(0b11) +#define G_BL_A_IN gI_(0b00) +#define G_BL_A_FOG gI_(0b01) +#define G_BL_A_MEM gI_(0b01) +#define G_BL_A_SHADE gI_(0b10) + +#define GBL_c1(p, a, m, b) \ + ( \ + gF_(p, 2, 30) | \ + gF_(a, 2, 26) | \ + gF_(m, 2, 22) | \ + gF_(b, 2, 18) \ + ) +#define GBL_c2(p, a, m, b) \ + ( \ + gF_(p, 2, 28) | \ + gF_(a, 2, 24) | \ + gF_(m, 2, 20) | \ + gF_(b, 2, 16) \ + ) + +/* render modes */ +#define G_RM_OPA_SURF \ + ( \ + CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_OPA_SURF2 \ + ( \ + CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_AA_OPA_SURF \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_OPA_SURF2 \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_OPA_SURF \ + ( \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_OPA_SURF2 \ + ( \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_ZB_OPA_SURF \ + ( \ + Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_ZB_OPA_SURF2 \ + ( \ + Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_OPA_SURF \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_OPA_SURF2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_ZB_OPA_SURF \ + ( \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_ZB_OPA_SURF2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) + +#define G_RM_XLU_SURF \ + ( \ + IM_RD | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_XLU_SURF2 \ + ( \ + IM_RD | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_XLU_SURF \ + ( \ + AA_EN | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_OPA | \ + FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_XLU_SURF2 \ + ( \ + AA_EN | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_OPA | \ + FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_ZB_XLU_SURF \ + ( \ + Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_XLU | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_ZB_XLU_SURF2 \ + ( \ + Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_XLU | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_XLU_SURF \ + ( \ + AA_EN | Z_CMP | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | \ + ZMODE_XLU | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_XLU_SURF2 \ + ( \ + AA_EN | Z_CMP | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | \ + ZMODE_XLU | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_ZB_OPA_DECAL \ + ( \ + Z_CMP | CVG_DST_FULL | ZMODE_DEC | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_ZB_OPA_DECAL2 \ + ( \ + Z_CMP | CVG_DST_FULL | ZMODE_DEC | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_OPA_DECAL \ + ( \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ZMODE_DEC | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_OPA_DECAL2 \ + ( \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ZMODE_DEC | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_ZB_OPA_DECAL \ + ( \ + AA_EN | Z_CMP | CVG_DST_WRAP | ZMODE_DEC | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_ZB_OPA_DECAL2 \ + ( \ + AA_EN | Z_CMP | CVG_DST_WRAP | ZMODE_DEC | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) + +#define G_RM_ZB_XLU_DECAL \ + ( \ + Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_DEC | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_ZB_XLU_DECAL2 \ + ( \ + Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_DEC | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_XLU_DECAL \ + ( \ + AA_EN | Z_CMP | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | \ + ZMODE_DEC | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_XLU_DECAL2 \ + ( \ + AA_EN | Z_CMP | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | \ + ZMODE_DEC | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_AA_ZB_OPA_INTER \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_INTER | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_OPA_INTER2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_INTER | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_ZB_OPA_INTER \ + ( \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ZMODE_INTER | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_RA_ZB_OPA_INTER2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ZMODE_INTER | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) + +#define G_RM_AA_ZB_XLU_INTER \ + ( \ + AA_EN | Z_CMP | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | \ + ZMODE_INTER | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_XLU_INTER2 \ + ( \ + AA_EN | Z_CMP | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | \ + ZMODE_INTER | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_AA_XLU_LINE \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_XLU_LINE2 \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_XLU_LINE \ + ( \ + AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | ZMODE_XLU | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_XLU_LINE2 \ + ( \ + AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | ZMODE_XLU | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_AA_DEC_LINE \ + ( \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_DEC_LINE2 \ + ( \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_DEC_LINE \ + ( \ + AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | ZMODE_DEC | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_DEC_LINE2 \ + ( \ + AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | ZMODE_DEC | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + + +#define G_RM_TEX_EDGE \ + ( \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_TEX_EDGE2 \ + ( \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_AA_TEX_EDGE \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_TEX_EDGE2 \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_TEX_EDGE \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_TEX_EDGE2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) + +#define G_RM_AA_ZB_TEX_INTER \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_INTER | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_TEX_INTER2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_INTER | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) + +#define G_RM_AA_SUB_SURF \ + ( \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_SUB_SURF2 \ + ( \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_SUB_SURF \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) +#define G_RM_AA_ZB_SUB_SURF2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) \ + ) + +#define G_RM_PCL_SURF \ + ( \ + G_AC_DITHER | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_PCL_SURF2 \ + ( \ + G_AC_DITHER | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_AA_PCL_SURF \ + ( \ + G_AC_DITHER | AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_PCL_SURF2 \ + ( \ + G_AC_DITHER | AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_ZB_PCL_SURF \ + ( \ + G_AC_DITHER | Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | \ + GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_ZB_PCL_SURF2 \ + ( \ + G_AC_DITHER | Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | \ + GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_AA_ZB_PCL_SURF \ + ( \ + G_AC_DITHER | AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_PCL_SURF2 \ + ( \ + G_AC_DITHER | AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_AA_OPA_TERR \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_OPA_TERR2 \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_OPA_TERR \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_OPA_TERR2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_AA_TEX_TERR \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_TEX_TERR2 \ + ( \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_TEX_TERR \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_TEX_TERR2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_AA_SUB_TERR \ + ( \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_SUB_TERR2 \ + ( \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_SUB_TERR \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_ZB_SUB_TERR2 \ + ( \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_CLD_SURF \ + ( \ + IM_RD | CVG_DST_SAVE | ZMODE_OPA | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_CLD_SURF2 \ + ( \ + IM_RD | CVG_DST_SAVE | ZMODE_OPA | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_ZB_CLD_SURF \ + ( \ + Z_CMP | IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_ZB_CLD_SURF2 \ + ( \ + Z_CMP | IM_RD | CVG_DST_SAVE | ZMODE_XLU | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_ZB_OVL_SURF \ + ( \ + Z_CMP | IM_RD | CVG_DST_SAVE | ZMODE_DEC | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_ZB_OVL_SURF2 \ + ( \ + Z_CMP | IM_RD | CVG_DST_SAVE | ZMODE_DEC | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) + +#define G_RM_ADD \ + ( \ + IM_RD | CVG_DST_SAVE | ZMODE_OPA | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1) \ + ) +#define G_RM_ADD2 \ + ( \ + IM_RD | CVG_DST_SAVE | ZMODE_OPA | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1) \ + ) + +#define G_RM_FOG_SHADE_A \ + GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA) + +#define G_RM_FOG_PRIM_A \ + GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_IN, G_BL_1MA) + +#define G_RM_PASS \ + GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define G_RM_VISCVG \ + ( \ + IM_RD | FORCE_BL | \ + GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM) \ + ) +#define G_RM_VISCVG2 \ + ( \ + IM_RD | FORCE_BL | \ + GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM) \ + ) + +#define G_RM_OPA_CI \ + ( \ + CVG_DST_CLAMP | ZMODE_OPA | \ + GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) +#define G_RM_OPA_CI2 \ + ( \ + CVG_DST_CLAMP | ZMODE_OPA | \ + GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) \ + ) + +#define G_RM_NOOP GBL_c1(0, 0, 0, 0) +#define G_RM_NOOP2 GBL_c2(0, 0, 0, 0) + +#define G_RM_SPRITE G_RM_OPA_SURF +#define G_RM_SPRITE2 G_RM_OPA_SURF2 +#define G_RM_RA_SPRITE \ + ( \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | \ + GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_RA_SPRITE2 \ + ( \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | \ + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) \ + ) +#define G_RM_AA_SPRITE G_RM_AA_TEX_TERR +#define G_RM_AA_SPRITE2 G_RM_AA_TEX_TERR2 +#define G_RM_XLU_SPRITE G_RM_XLU_SURF +#define G_RM_XLU_SPRITE2 G_RM_XLU_SURF2 +#define G_RM_AA_XLU_SPRITE G_RM_AA_XLU_SURF +#define G_RM_AA_XLU_SPRITE2 G_RM_AA_XLU_SURF2 + +#define G_OBJRM_NOTXCLAMP (gI_(0b1) << 0) +#define G_OBJRM_XLU (gI_(0b1) << 1) +#define G_OBJRM_ANTIALIAS (gI_(0b1) << 2) +#define G_OBJRM_BILERP (gI_(0b1) << 3) +#define G_OBJRM_SHRINKSIZE_1 (gI_(0b1) << 4) +#define G_OBJRM_SHRINKSIZE_2 (gI_(0b1) << 5) +#define G_OBJRM_WIDEN (gI_(0b1) << 6) + +/* othermode hi */ +#define G_MDSFT_ALPHADITHER 4 +#define G_MDSFT_RGBDITHER 6 +#define G_MDSFT_COMBKEY 8 +#define G_MDSFT_TEXTCONV 9 +#define G_MDSFT_TEXTFILT 12 +#define G_MDSFT_TEXTLUT 14 +#define G_MDSFT_TEXTLOD 16 +#define G_MDSFT_TEXTDETAIL 17 +#define G_MDSFT_TEXTPERSP 19 +#define G_MDSFT_CYCLETYPE 20 +#define G_MDSFT_PIPELINE 23 +#define G_MDSIZ_ALPHADITHER 2 +#define G_MDSIZ_RGBDITHER 2 +#define G_MDSIZ_COMBKEY 1 +#define G_MDSIZ_TEXTCONV 3 +#define G_MDSIZ_TEXTFILT 2 +#define G_MDSIZ_TEXTLUT 2 +#define G_MDSIZ_TEXTLOD 1 +#define G_MDSIZ_TEXTDETAIL 2 +#define G_MDSIZ_TEXTPERSP 1 +#define G_MDSIZ_CYCLETYPE 2 +#define G_MDSIZ_PIPELINE 1 + +#define G_AD_PATTERN (gI_(0b00) << G_MDSFT_ALPHADITHER) +#define G_AD_NOTPATTERN (gI_(0b01) << G_MDSFT_ALPHADITHER) +#define G_AD_NOISE (gI_(0b10) << G_MDSFT_ALPHADITHER) +#define G_AD_DISABLE (gI_(0b11) << G_MDSFT_ALPHADITHER) +#define G_CD_MAGICSQ (gI_(0b00) << G_MDSFT_RGBDITHER) +#define G_CD_BAYER (gI_(0b01) << G_MDSFT_RGBDITHER) +#define G_CD_NOISE (gI_(0b10) << G_MDSFT_RGBDITHER) +#define G_CD_DISABLE (gI_(0b11) << G_MDSFT_RGBDITHER) +#define G_CD_ENABLE (gI_(0b10) << G_MDSFT_RGBDITHER) +#define G_CK_NONE (gI_(0b0) << G_MDSFT_COMBKEY) +#define G_CK_KEY (gI_(0b1) << G_MDSFT_COMBKEY) +#define G_TC_CONV (gI_(0b000) << G_MDSFT_TEXTCONV) +#define G_TC_FILTCONV (gI_(0b101) << G_MDSFT_TEXTCONV) +#define G_TC_FILT (gI_(0b110) << G_MDSFT_TEXTCONV) +#define G_TF_POINT (gI_(0b00) << G_MDSFT_TEXTFILT) +#define G_TF_BILERP (gI_(0b10) << G_MDSFT_TEXTFILT) +#define G_TF_AVERAGE (gI_(0b11) << G_MDSFT_TEXTFILT) +#define G_TT_NONE (gI_(0b00) << G_MDSFT_TEXTLUT) +#define G_TT_RGBA16 (gI_(0b10) << G_MDSFT_TEXTLUT) +#define G_TT_IA16 (gI_(0b11) << G_MDSFT_TEXTLUT) +#define G_TL_TILE (gI_(0b0) << G_MDSFT_TEXTLOD) +#define G_TL_LOD (gI_(0b1) << G_MDSFT_TEXTLOD) +#define G_TD_CLAMP (gI_(0b00) << G_MDSFT_TEXTDETAIL) +#define G_TD_SHARPEN (gI_(0b01) << G_MDSFT_TEXTDETAIL) +#define G_TD_DETAIL (gI_(0b10) << G_MDSFT_TEXTDETAIL) +#define G_TP_NONE (gI_(0b0) << G_MDSFT_TEXTPERSP) +#define G_TP_PERSP (gI_(0b1) << G_MDSFT_TEXTPERSP) +#define G_CYC_1CYCLE (gI_(0b00) << G_MDSFT_CYCLETYPE) +#define G_CYC_2CYCLE (gI_(0b01) << G_MDSFT_CYCLETYPE) +#define G_CYC_COPY (gI_(0b10) << G_MDSFT_CYCLETYPE) +#define G_CYC_FILL (gI_(0b11) << G_MDSFT_CYCLETYPE) +#define G_PM_NPRIMITIVE (gI_(0b0) << G_MDSFT_PIPELINE) +#define G_PM_1PRIMITIVE (gI_(0b1) << G_MDSFT_PIPELINE) + +/* color conversion constants */ +#define G_CV_K0 (175) +#define G_CV_K1 (-43) +#define G_CV_K2 (-89) +#define G_CV_K3 (222) +#define G_CV_K4 (114) +#define G_CV_K5 (42) + +/* color combiner */ +#define G_CCMUX_COMBINED 0 +#define G_CCMUX_TEXEL0 1 +#define G_CCMUX_TEXEL1 2 +#define G_CCMUX_PRIMITIVE 3 +#define G_CCMUX_SHADE 4 +#define G_CCMUX_ENVIRONMENT 5 +#define G_CCMUX_1 6 +#define G_CCMUX_NOISE 7 +#define G_CCMUX_0 31 +#define G_CCMUX_CENTER 6 +#define G_CCMUX_K4 7 +#define G_CCMUX_SCALE 6 +#define G_CCMUX_COMBINED_ALPHA 7 +#define G_CCMUX_TEXEL0_ALPHA 8 +#define G_CCMUX_TEXEL1_ALPHA 9 +#define G_CCMUX_PRIMITIVE_ALPHA 10 +#define G_CCMUX_SHADE_ALPHA 11 +#define G_CCMUX_ENV_ALPHA 12 +#define G_CCMUX_LOD_FRACTION 13 +#define G_CCMUX_PRIM_LOD_FRAC 14 +#define G_CCMUX_K5 15 +#define G_ACMUX_COMBINED 0 +#define G_ACMUX_TEXEL0 1 +#define G_ACMUX_TEXEL1 2 +#define G_ACMUX_PRIMITIVE 3 +#define G_ACMUX_SHADE 4 +#define G_ACMUX_ENVIRONMENT 5 +#define G_ACMUX_1 6 +#define G_ACMUX_0 7 +#define G_ACMUX_LOD_FRACTION 0 +#define G_ACMUX_PRIM_LOD_FRAC 6 + +/* + * combine modes + * ( A - B ) * C + D +*/ +#define G_CC_MODULATEI \ + TEXEL0, 0, SHADE, 0, \ + 0, 0, 0, SHADE +#define G_CC_MODULATEIA \ + TEXEL0, 0, SHADE, 0, \ + TEXEL0, 0, SHADE, 0 +#define G_CC_MODULATEIDECALA \ + TEXEL0, 0, SHADE, 0, \ + 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB \ + G_CC_MODULATEI +#define G_CC_MODULATERGBA \ + G_CC_MODULATEIA +#define G_CC_MODULATERGBDECALA \ + G_CC_MODULATEIDECALA +#define G_CC_MODULATEI_PRIM \ + TEXEL0, 0, PRIMITIVE, 0, \ + 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM \ + TEXEL0, 0, PRIMITIVE, 0, \ + TEXEL0, 0, PRIMITIVE, 0 +#define G_CC_MODULATEIDECALA_PRIM \ + TEXEL0, 0, PRIMITIVE, 0, \ + 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB_PRIM \ + G_CC_MODULATEI_PRIM +#define G_CC_MODULATERGBA_PRIM \ + G_CC_MODULATEIA_PRIM +#define G_CC_MODULATERGBDECALA_PRIM \ + G_CC_MODULATEIDECALA_PRIM +#define G_CC_DECALRGB \ + 0, 0, 0, TEXEL0, \ + 0, 0, 0, SHADE +#define G_CC_DECALRGBA \ + 0, 0, 0, TEXEL0, \ + 0, 0, 0, TEXEL0 +#define G_CC_BLENDI \ + ENVIRONMENT, SHADE, TEXEL0, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_BLENDIA \ + ENVIRONMENT, SHADE, TEXEL0, SHADE, \ + TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDIDECALA \ + ENVIRONMENT, SHADE, TEXEL0, SHADE, \ + 0, 0, 0, TEXEL0 +#define G_CC_BLENDRGBA \ + TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_BLENDRGBDECALA \ + TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, \ + 0, 0, 0, TEXEL0 +#define G_CC_REFLECTRGB \ + ENVIRONMENT, 0, TEXEL0, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_REFLECTRGBDECALA \ + ENVIRONMENT, 0, TEXEL0, SHADE, \ + 0, 0, 0, TEXEL0 +#define G_CC_HILITERGB \ + PRIMITIVE, SHADE, TEXEL0, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_HILITERGBA \ + PRIMITIVE, SHADE, TEXEL0, SHADE, \ + PRIMITIVE, SHADE, TEXEL0, SHADE +#define G_CC_HILITERGBDECALA \ + PRIMITIVE, SHADE, TEXEL0, SHADE, \ + 0, 0, 0, TEXEL0 +#define G_CC_1CYUV2RGB \ + TEXEL0, K4, K5, TEXEL0, \ + 0, 0, 0, SHADE +#define G_CC_PRIMITIVE \ + 0, 0, 0, PRIMITIVE, \ + 0, 0, 0, PRIMITIVE +#define G_CC_SHADE \ + 0, 0, 0, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_ADDRGB \ + 1, 0, TEXEL0, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_ADDRGBDECALA \ + 1, 0, TEXEL0, SHADE, \ + 0, 0, 0, TEXEL0 +#define G_CC_SHADEDECALA \ + 0, 0, 0, SHADE, \ + 0, 0, 0, TEXEL0 +#define G_CC_BLENDPE \ + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, \ + TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDPEDECALA \ + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, \ + 0, 0, 0, TEXEL0 +#define G_CC_TRILERP \ + TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, \ + TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0 +#define G_CC_TEMPLERP \ + TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, \ + TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0 +#define G_CC_INTERFERENCE \ + TEXEL0, 0, TEXEL1, 0, \ + TEXEL0, 0, TEXEL1, 0 +#define _G_CC_BLENDPE \ + ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, \ + TEXEL0, 0, SHADE, 0 +#define _G_CC_BLENDPEDECALA \ + ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, \ + 0, 0, 0, TEXEL0 +#define _G_CC_SPARSEST \ + PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0, \ + PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0 +#define _G_CC_TWOCOLORTEX \ + PRIMITIVE, SHADE, TEXEL0, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_MODULATEI2 \ + COMBINED, 0, SHADE, 0, \ + 0, 0, 0, SHADE +#define G_CC_MODULATEIA2 \ + COMBINED, 0, SHADE, 0, \ + COMBINED, 0, SHADE, 0 +#define G_CC_MODULATERGB2 \ + G_CC_MODULATEI2 +#define G_CC_MODULATERGBA2 \ + G_CC_MODULATEIA2 +#define G_CC_MODULATEI_PRIM2 \ + COMBINED, 0, PRIMITIVE, 0, \ + 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM2 \ + COMBINED, 0, PRIMITIVE, 0, \ + COMBINED, 0, PRIMITIVE, 0 +#define G_CC_MODULATERGB_PRIM2 \ + G_CC_MODULATEI_PRIM2 +#define G_CC_MODULATERGBA_PRIM2 \ + G_CC_MODULATEIA_PRIM2 +#define G_CC_DECALRGB2 \ + 0, 0, 0, COMBINED, \ + 0, 0, 0, SHADE +#define G_CC_BLENDI2 \ + ENVIRONMENT, SHADE, COMBINED, SHADE, \ + 0, 0, 0, SHADE +#define G_CC_BLENDIA2 \ + ENVIRONMENT, SHADE, COMBINED, SHADE, \ + COMBINED, 0, SHADE, 0 +#define G_CC_HILITERGB2 \ + ENVIRONMENT, COMBINED, TEXEL0, COMBINED, \ + 0, 0, 0, SHADE +#define G_CC_HILITERGBA2 \ + ENVIRONMENT, COMBINED, TEXEL0, COMBINED, \ + ENVIRONMENT, COMBINED, TEXEL0, COMBINED +#define G_CC_HILITERGBDECALA2 \ + ENVIRONMENT, COMBINED, TEXEL0, COMBINED, \ + 0, 0, 0, TEXEL0 +#define G_CC_HILITERGBPASSA2 \ + ENVIRONMENT, COMBINED, TEXEL0, COMBINED, \ + 0, 0, 0, COMBINED +#define G_CC_CHROMA_KEY2 \ + TEXEL0, CENTER, SCALE, 0, \ + 0, 0, 0, 0 +#define G_CC_YUV2RGB \ + TEXEL1, K4, K5, TEXEL1, \ + 0, 0, 0, 0 +#define G_CC_PASS2 \ + 0, 0, 0, COMBINED, \ + 0, 0, 0, COMBINED +#define G_CC_LERP(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \ + a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ + ( \ + gFL_(G_CCMUX_##a0, 4, 52) | \ + gFL_(G_CCMUX_##c0, 5, 47) | \ + gFL_(G_ACMUX_##Aa0, 3, 44) | \ + gFL_(G_ACMUX_##Ac0, 3, 41) | \ + gFL_(G_CCMUX_##a1, 4, 37) | \ + gFL_(G_CCMUX_##c1, 5, 32) | \ + gFL_(G_CCMUX_##b0, 4, 28) | \ + gFL_(G_CCMUX_##b1, 4, 24) | \ + gFL_(G_ACMUX_##Aa1, 3, 21) | \ + gFL_(G_ACMUX_##Ac1, 3, 18) | \ + gFL_(G_CCMUX_##d0, 3, 15) | \ + gFL_(G_ACMUX_##Ab0, 3, 12) | \ + gFL_(G_ACMUX_##Ad0, 3, 9) | \ + gFL_(G_CCMUX_##d1, 3, 6) | \ + gFL_(G_ACMUX_##Ab1, 3, 3) | \ + gFL_(G_ACMUX_##Ad1, 3, 0) \ + ) +#define G_CC_MODE(mode1, mode2) G_CC_LERP(mode1, mode2) + +/* scissor modes */ +#define G_SC_NON_INTERLACE gI_(0b00) +#define G_SC_EVEN_INTERLACE gI_(0b10) +#define G_SC_ODD_INTERLACE gI_(0b11) + +/* display list branch flags */ +#define G_DL_PUSH gI_(0b0) +#define G_DL_NOPUSH gI_(0b1) + +/* conditional branching flags (f3dex and f3dex2) */ +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +# define G_BZ_PERSP 0 +# define G_BZ_ORTHO 1 +#endif + +/* matrix params */ +#define G_MTX_MUL (gI_(0b0) << 1) +#define G_MTX_LOAD (gI_(0b1) << 1) + +/* matrix params for fast3d and f3dex */ +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define G_MTX_MODELVIEW (gI_(0b0) << 0) +# define G_MTX_PROJECTION (gI_(0b1) << 0) +# define G_MTX_NOPUSH (gI_(0b0) << 2) +# define G_MTX_PUSH (gI_(0b1) << 2) +#endif + +/* matrix params for f3dex2 */ +#if defined(F3DEX_GBI_2) +# define G_MTX_NOPUSH (gI_(0b0) << 0) +# define G_MTX_PUSH (gI_(0b1) << 0) +# define G_MTX_MODELVIEW (gI_(0b0) << 2) +# define G_MTX_PROJECTION (gI_(0b1) << 2) +#endif + +/* moveword indices */ +#define G_MW_MATRIX 0 +#define G_MW_NUMLIGHT 2 +#define G_MW_CLIP 4 +#define G_MW_SEGMENT 6 +#define G_MW_FOG 8 +#define G_MW_GENSTAT 8 +#define G_MW_LIGHTCOL 10 +#define G_MW_PERSPNORM 14 + +/* moveword indices for fast3d and f3dex */ +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define G_MW_POINTS 12 +#endif + +/* moveword indices for f3dex2 */ +#if defined(F3DEX_GBI_2) +# define G_MW_FORCEMTX 12 +#endif + +/* moveword offsets */ +#define G_MWO_NUMLIGHT gI_(0x00) +#define G_MWO_CLIP_RNX gI_(0x04) +#define G_MWO_CLIP_RNY gI_(0x0C) +#define G_MWO_CLIP_RPX gI_(0x14) +#define G_MWO_CLIP_RPY gI_(0x1C) +#define G_MWO_SEGMENT_0 gI_(0x00) +#define G_MWO_SEGMENT_1 gI_(0x04) +#define G_MWO_SEGMENT_2 gI_(0x08) +#define G_MWO_SEGMENT_3 gI_(0x0C) +#define G_MWO_SEGMENT_4 gI_(0x10) +#define G_MWO_SEGMENT_5 gI_(0x14) +#define G_MWO_SEGMENT_6 gI_(0x18) +#define G_MWO_SEGMENT_7 gI_(0x1C) +#define G_MWO_SEGMENT_8 gI_(0x20) +#define G_MWO_SEGMENT_9 gI_(0x24) +#define G_MWO_SEGMENT_A gI_(0x28) +#define G_MWO_SEGMENT_B gI_(0x2C) +#define G_MWO_SEGMENT_C gI_(0x30) +#define G_MWO_SEGMENT_D gI_(0x34) +#define G_MWO_SEGMENT_E gI_(0x38) +#define G_MWO_SEGMENT_F gI_(0x3C) +#define G_MWO_FOG gI_(0x00) +#define G_MWO_aLIGHT_1 gI_(0x00) +#define G_MWO_bLIGHT_1 gI_(0x04) +#define G_MWO_MATRIX_XX_XY_I gI_(0x00) +#define G_MWO_MATRIX_XZ_XW_I gI_(0x04) +#define G_MWO_MATRIX_YX_YY_I gI_(0x08) +#define G_MWO_MATRIX_YZ_YW_I gI_(0x0C) +#define G_MWO_MATRIX_ZX_ZY_I gI_(0x10) +#define G_MWO_MATRIX_ZZ_ZW_I gI_(0x14) +#define G_MWO_MATRIX_WX_WY_I gI_(0x18) +#define G_MWO_MATRIX_WZ_WW_I gI_(0x1C) +#define G_MWO_MATRIX_XX_XY_F gI_(0x20) +#define G_MWO_MATRIX_XZ_XW_F gI_(0x24) +#define G_MWO_MATRIX_YX_YY_F gI_(0x28) +#define G_MWO_MATRIX_YZ_YW_F gI_(0x2C) +#define G_MWO_MATRIX_ZX_ZY_F gI_(0x30) +#define G_MWO_MATRIX_ZZ_ZW_F gI_(0x34) +#define G_MWO_MATRIX_WX_WY_F gI_(0x38) +#define G_MWO_MATRIX_WZ_WW_F gI_(0x3C) +#define G_MWO_POINT_RGBA gI_(0x10) +#define G_MWO_POINT_ST gI_(0x14) +#define G_MWO_POINT_XYSCREEN gI_(0x18) +#define G_MWO_POINT_ZSCREEN gI_(0x1C) + +/* moveword offsets for fast3d and f3dex */ +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define G_MWO_aLIGHT_2 gI_(0x20) +# define G_MWO_bLIGHT_2 gI_(0x24) +# define G_MWO_aLIGHT_3 gI_(0x40) +# define G_MWO_bLIGHT_3 gI_(0x44) +# define G_MWO_aLIGHT_4 gI_(0x60) +# define G_MWO_bLIGHT_4 gI_(0x64) +# define G_MWO_aLIGHT_5 gI_(0x80) +# define G_MWO_bLIGHT_5 gI_(0x84) +# define G_MWO_aLIGHT_6 gI_(0xA0) +# define G_MWO_bLIGHT_6 gI_(0xA4) +# define G_MWO_aLIGHT_7 gI_(0xC0) +# define G_MWO_bLIGHT_7 gI_(0xC4) +# define G_MWO_aLIGHT_8 gI_(0xE0) +# define G_MWO_bLIGHT_8 gI_(0xE4) +#endif + +/* moveword offsets for f3dex2 */ +#if defined(F3DEX_GBI_2) +# define G_MWO_aLIGHT_2 gI_(0x18) +# define G_MWO_bLIGHT_2 gI_(0x1C) +# define G_MWO_aLIGHT_3 gI_(0x30) +# define G_MWO_bLIGHT_3 gI_(0x34) +# define G_MWO_aLIGHT_4 gI_(0x48) +# define G_MWO_bLIGHT_4 gI_(0x4C) +# define G_MWO_aLIGHT_5 gI_(0x60) +# define G_MWO_bLIGHT_5 gI_(0x64) +# define G_MWO_aLIGHT_6 gI_(0x78) +# define G_MWO_bLIGHT_6 gI_(0x7C) +# define G_MWO_aLIGHT_7 gI_(0x90) +# define G_MWO_bLIGHT_7 gI_(0x94) +# define G_MWO_aLIGHT_8 gI_(0xA8) +# define G_MWO_bLIGHT_8 gI_(0xAC) +#endif + +/* movemem params for fast3d and f3dex */ +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define G_MV_VIEWPORT 128 +# define G_MV_LOOKATY 130 +# define G_MV_LOOKATX 132 +# define G_MV_L0 134 +# define G_MV_L1 136 +# define G_MV_L2 138 +# define G_MV_L3 140 +# define G_MV_L4 142 +# define G_MV_L5 144 +# define G_MV_L6 146 +# define G_MV_L7 148 +# define G_MV_TXTATT 150 +# define G_MV_MATRIX_2 152 +# define G_MV_MATRIX_3 154 +# define G_MV_MATRIX_4 156 +# define G_MV_MATRIX_1 158 +#endif + +/* movemem params for f3dex2 */ +#if defined(F3DEX_GBI_2) +# define G_MV_MMTX 2 +# define G_MV_PMTX 6 +# define G_MV_VIEWPORT 8 +# define G_MV_LIGHT 10 +# define G_MV_POINT 12 +# define G_MV_MATRIX 14 +# define G_MVO_LOOKATX gI_(0 * 0x18) +# define G_MVO_LOOKATY gI_(1 * 0x18) +# define G_MVO_L0 gI_(2 * 0x18) +# define G_MVO_L1 gI_(3 * 0x18) +# define G_MVO_L2 gI_(4 * 0x18) +# define G_MVO_L3 gI_(5 * 0x18) +# define G_MVO_L4 gI_(6 * 0x18) +# define G_MVO_L5 gI_(7 * 0x18) +# define G_MVO_L6 gI_(8 * 0x18) +# define G_MVO_L7 gI_(9 * 0x18) +#endif + +/* frustum ratios */ +#define FRUSTRATIO_1 gI_(1) +#define FRUSTRATIO_2 gI_(2) +#define FRUSTRATIO_3 gI_(3) +#define FRUSTRATIO_4 gI_(4) +#define FRUSTRATIO_5 gI_(5) +#define FRUSTRATIO_6 gI_(6) + +/* light params */ +#define NUMLIGHTS_0 1 +#define NUMLIGHTS_1 1 +#define NUMLIGHTS_2 2 +#define NUMLIGHTS_3 3 +#define NUMLIGHTS_4 4 +#define NUMLIGHTS_5 5 +#define NUMLIGHTS_6 6 +#define NUMLIGHTS_7 7 +#define LIGHT_1 1 +#define LIGHT_2 2 +#define LIGHT_3 3 +#define LIGHT_4 4 +#define LIGHT_5 5 +#define LIGHT_6 6 +#define LIGHT_7 7 +#define LIGHT_8 8 + +/* light params for fast3d and f3dex */ +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define NUML(n) (((n) + 1) * 32 + 0x80000000) +#endif + +/* light params for f3dex2 */ +#if defined(F3DEX_GBI_2) +# define NUML(n) ((n) * 0x18) +#endif + +/* background load types */ +#define G_BGLT_LOADBLOCK gI_(0x0033) +#define G_BGLT_LOADTILE gI_(0xFFF4) + +/* background flags */ +#define G_BG_FLAG_FLIPS (gI_(0b1) << 0) +#define G_BG_FLAG_FLIPT (gI_(0b1) << 1) + +/* object load types */ +#define G_OBJLT_TXTRBLOCK gI_(0x00001033) +#define G_OBJLT_TXTRTILE gI_(0x00FC1034) +#define G_OBJLT_TLUT gI_(0x00000030) + +/* object flags */ +#define G_OBJ_FLAG_FLIPS (gI_(0b1) << 0) +#define G_OBJ_FLAG_FLIPT (gI_(0b1) << 4) + +/* color macros */ +#define G_MAXZ 0x03FF +#define G_MAXFBZ 0x3FFF +#define GPACK_RGBA5551(r, g, b, a) \ + ( \ + gF_(r, 5, 11) | \ + gF_(g, 5, 6) | \ + gF_(b, 5, 1) | \ + gF_(a, 1, 0) \ + ) +#define GPACK_RGBA8888(r, g, b, a) \ + ( \ + gF_(r, 8, 24) | \ + gF_(g, 8, 16) | \ + gF_(b, 8, 8) | \ + gF_(a, 8, 0) \ + ) +#define GPACK_RGB24A8(rgb, a) (gF_(rgb, 24, 8) | gF_(a, 8, 0)) +#define GPACK_ZDZ(z, dz) (gF_(z, 14, 2) | gF_(dz, 2, 0)) + +/* structure definition macros */ +#define gdSPDefMtx(xx, xy, xz, xw, \ + yx, yy, yz, yw, \ + zx, zy, zz, zw, \ + wx, wy, wz, ww) \ + ( \ + (Mtx) \ + { \ + .i = \ + { \ + (qs1616(xx) >> 16) & 0xFFFF, \ + (qs1616(xy) >> 16) & 0xFFFF, \ + (qs1616(xz) >> 16) & 0xFFFF, \ + (qs1616(xw) >> 16) & 0xFFFF, \ + (qs1616(yx) >> 16) & 0xFFFF, \ + (qs1616(yy) >> 16) & 0xFFFF, \ + (qs1616(yz) >> 16) & 0xFFFF, \ + (qs1616(yw) >> 16) & 0xFFFF, \ + (qs1616(zx) >> 16) & 0xFFFF, \ + (qs1616(zy) >> 16) & 0xFFFF, \ + (qs1616(zz) >> 16) & 0xFFFF, \ + (qs1616(zw) >> 16) & 0xFFFF, \ + (qs1616(wx) >> 16) & 0xFFFF, \ + (qs1616(wy) >> 16) & 0xFFFF, \ + (qs1616(wz) >> 16) & 0xFFFF, \ + (qs1616(ww) >> 16) & 0xFFFF, \ + }, \ + .f = \ + { \ + qs1616(xx) & 0xFFFF, \ + qs1616(xy) & 0xFFFF, \ + qs1616(xz) & 0xFFFF, \ + qs1616(xw) & 0xFFFF, \ + qs1616(yx) & 0xFFFF, \ + qs1616(yy) & 0xFFFF, \ + qs1616(yz) & 0xFFFF, \ + qs1616(yw) & 0xFFFF, \ + qs1616(zx) & 0xFFFF, \ + qs1616(zy) & 0xFFFF, \ + qs1616(zz) & 0xFFFF, \ + qs1616(zw) & 0xFFFF, \ + qs1616(wx) & 0xFFFF, \ + qs1616(wy) & 0xFFFF, \ + qs1616(wz) & 0xFFFF, \ + qs1616(ww) & 0xFFFF, \ + } \ + } \ + ) +#define gdSPDefLookAt(rx, ry, rz, ux, uy, uz) \ + ( \ + (LookAt) \ + { \ + .l[0].l = \ + { \ + .col = {0, 0, 0}, \ + .colc = {0, 0, 0}, \ + .dir = {rx, ry, rz}, \ + }, \ + .l[1].l = \ + { \ + .col = {0, 0x80, 0}, \ + .colc = {0, 0x80, 0}, \ + .dir = {ux, uy, uz}, \ + }, \ + } \ + ) +#define gdSPDefLights0(ar, ag, ab) \ + ( \ + (Lights0) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + } \ + } \ + ) +#define gdSPDefLights1(ar, ag, ab, \ + r1, g1, b1, x1, y1, z1) \ + ( \ + (Lights1) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + .col = {r1, g1, b1}, \ + .colc = {r1, g1, b1}, \ + .dir = {x1, y1, z1}, \ + } \ + } \ + ) +#define gdSPDefLights2(ar, ag, ab, \ + r1, g1, b1, x1, y1, z1, \ + r2, g2, b2, x2, y2, z2) \ + ( \ + (Lights2) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + .col = {r1, g1, b1}, \ + .colc = {r1, g1, b1}, \ + .dir = {x1, y1, z1}, \ + } \ + .l[1].l = \ + { \ + .col = {r2, g2, b2}, \ + .colc = {r2, g2, b2}, \ + .dir = {x2, y2, z2}, \ + } \ + } \ + ) +#define gdSPDefLights3(ar, ag, ab, \ + r1, g1, b1, x1, y1, z1, \ + r2, g2, b2, x2, y2, z2, \ + r3, g3, b3, x3, y3, z3) \ + ( \ + (Lights3) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + .col = {r1, g1, b1}, \ + .colc = {r1, g1, b1}, \ + .dir = {x1, y1, z1}, \ + } \ + .l[1].l = \ + { \ + .col = {r2, g2, b2}, \ + .colc = {r2, g2, b2}, \ + .dir = {x2, y2, z2}, \ + } \ + .l[2].l = \ + { \ + .col = {r3, g3, b3}, \ + .colc = {r3, g3, b3}, \ + .dir = {x3, y3, z3}, \ + } \ + } \ + ) +#define gdSPDefLights4(ar, ag, ab, \ + r1, g1, b1, x1, y1, z1, \ + r2, g2, b2, x2, y2, z2, \ + r3, g3, b3, x3, y3, z3, \ + r4, g4, b4, x4, y4, z4) \ + ( \ + (Lights4) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + .col = {r1, g1, b1}, \ + .colc = {r1, g1, b1}, \ + .dir = {x1, y1, z1}, \ + } \ + .l[1].l = \ + { \ + .col = {r2, g2, b2}, \ + .colc = {r2, g2, b2}, \ + .dir = {x2, y2, z2}, \ + } \ + .l[2].l = \ + { \ + .col = {r3, g3, b3}, \ + .colc = {r3, g3, b3}, \ + .dir = {x3, y3, z3}, \ + } \ + .l[3].l = \ + { \ + .col = {r4, g4, b4}, \ + .colc = {r4, g4, b4}, \ + .dir = {x4, y4, z4}, \ + } \ + } \ + ) +#define gdSPDefLights5(ar, ag, ab, \ + r1, g1, b1, x1, y1, z1, \ + r2, g2, b2, x2, y2, z2, \ + r3, g3, b3, x3, y3, z3, \ + r4, g4, b4, x4, y4, z4, \ + r5, g5, b5, x5, y5, z5) \ + ( \ + (Lights5) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + .col = {r1, g1, b1}, \ + .colc = {r1, g1, b1}, \ + .dir = {x1, y1, z1}, \ + } \ + .l[1].l = \ + { \ + .col = {r2, g2, b2}, \ + .colc = {r2, g2, b2}, \ + .dir = {x2, y2, z2}, \ + } \ + .l[2].l = \ + { \ + .col = {r3, g3, b3}, \ + .colc = {r3, g3, b3}, \ + .dir = {x3, y3, z3}, \ + } \ + .l[3].l = \ + { \ + .col = {r4, g4, b4}, \ + .colc = {r4, g4, b4}, \ + .dir = {x4, y4, z4}, \ + } \ + .l[4].l = \ + { \ + .col = {r5, g5, b5}, \ + .colc = {r5, g5, b5}, \ + .dir = {x5, y5, z5}, \ + } \ + } \ + ) +#define gdSPDefLights6(ar, ag, ab, \ + r1, g1, b1, x1, y1, z1, \ + r2, g2, b2, x2, y2, z2, \ + r3, g3, b3, x3, y3, z3, \ + r4, g4, b4, x4, y4, z4, \ + r5, g5, b5, x5, y5, z5, \ + r6, g6, b6, x6, y6, z6)\ + ( \ + (Lights6) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + .col = {r1, g1, b1}, \ + .colc = {r1, g1, b1}, \ + .dir = {x1, y1, z1}, \ + } \ + .l[1].l = \ + { \ + .col = {r2, g2, b2}, \ + .colc = {r2, g2, b2}, \ + .dir = {x2, y2, z2}, \ + } \ + .l[2].l = \ + { \ + .col = {r3, g3, b3}, \ + .colc = {r3, g3, b3}, \ + .dir = {x3, y3, z3}, \ + } \ + .l[3].l = \ + { \ + .col = {r4, g4, b4}, \ + .colc = {r4, g4, b4}, \ + .dir = {x4, y4, z4}, \ + } \ + .l[4].l = \ + { \ + .col = {r5, g5, b5}, \ + .colc = {r5, g5, b5}, \ + .dir = {x5, y5, z5}, \ + } \ + .l[5].l = \ + { \ + .col = {r6, g6, b6}, \ + .colc = {r6, g6, b6}, \ + .dir = {x6, y6, z6}, \ + } \ + } \ + ) +#define gdSPDefLights7(ar, ag, ab, \ + r1, g1, b1, x1, y1, z1, \ + r2, g2, b2, x2, y2, z2, \ + r3, g3, b3, x3, y3, z3, \ + r4, g4, b4, x4, y4, z4, \ + r5, g5, b5, x5, y5, z5, \ + r6, g6, b6, x6, y6, z6, \ + r7, g7, b7, x7, y7, z7) \ + ( \ + (Lights7) \ + { \ + .a.l = \ + { \ + .col = {ar, ag, ab}, \ + .colc = {ar, ag, ab}, \ + }, \ + .l[0].l = \ + { \ + .col = {r1, g1, b1}, \ + .colc = {r1, g1, b1}, \ + .dir = {x1, y1, z1}, \ + } \ + .l[1].l = \ + { \ + .col = {r2, g2, b2}, \ + .colc = {r2, g2, b2}, \ + .dir = {x2, y2, z2}, \ + } \ + .l[2].l = \ + { \ + .col = {r3, g3, b3}, \ + .colc = {r3, g3, b3}, \ + .dir = {x3, y3, z3}, \ + } \ + .l[3].l = \ + { \ + .col = {r4, g4, b4}, \ + .colc = {r4, g4, b4}, \ + .dir = {x4, y4, z4}, \ + } \ + .l[4].l = \ + { \ + .col = {r5, g5, b5}, \ + .colc = {r5, g5, b5}, \ + .dir = {x5, y5, z5}, \ + } \ + .l[5].l = \ + { \ + .col = {r6, g6, b6}, \ + .colc = {r6, g6, b6}, \ + .dir = {x6, y6, z6}, \ + } \ + .l[6].l = \ + { \ + .col = {r7, g7, b7}, \ + .colc = {r7, g7, b7}, \ + .dir = {x7, y7, z7}, \ + } \ + } \ + ) +#define gdSPDefVtx(x, y, z, s, t) \ + ( \ + (Vtx) \ + { \ + .v = \ + { \ + .ob = {x, y, z}, \ + .tc = {qs105(s), qs105(t)}, \ + } \ + } \ + ) +#define gdSPDefVtxC(x, y, z, s, t, cr, cg, cb, ca) \ + ( \ + (Vtx) \ + { \ + .v = \ + { \ + .ob = {x, y, z}, \ + .tc = {qs105(s), qs105(t)}, \ + .cn = {cr, cg, cb, ca}, \ + } \ + } \ + ) +#define gdSPDefVtxN(x, y, z, s, t, nx, ny, nz, ca) \ + ( \ + (Vtx) \ + { \ + .n = \ + { \ + .ob = {x, y, z}, \ + .tc = {qs105(s), qs105(t)}, \ + .n = {nx, ny, nz}, \ + .a = ca \ + } \ + } \ + ) + +/* instruction macros */ + +#define gsDPFillRectangle(ulx, uly, lrx, lry) \ + gO_( \ + G_FILLRECT, \ + gF_(lrx, 10, 14) | \ + gF_(lry, 10, 2), \ + gF_(ulx, 10, 14) | \ + gF_(uly, 10, 2)) + +#define gsDPScisFillRectangle(ulx, uly, lrx, lry) \ + gsDPFillRectangle(gScC_(ulx), gScC_(uly), gScC_(lrx), gScC_(lry)) + +#define gsDPFullSync() \ + gO_(G_RDPFULLSYNC, 0, 0) + +#define gsDPLoadSync() \ + gO_(G_RDPLOADSYNC, 0, 0) + +#define gsDPTileSync() \ + gO_(G_RDPTILESYNC, 0, 0) + +#define gsDPPipeSync() \ + gO_(G_RDPPIPESYNC, 0, 0) + +#define gsDPLoadTLUT_pal16(pal, dram) \ + gsDPLoadTLUT(16, 256 + (gI_(pal) & 0xF) * 16, dram) + +#define gsDPLoadTLUT_pal256(dram) \ + gsDPLoadTLUT(256, 256, dram) + +#define gLTB_(timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + dxt, tmem, rt, line) \ + gsDPSetTextureImage(fmt, G_SIZ_LDSIZ(siz), 1, timg), \ + gsDPSetTile( \ + fmt, G_SIZ_LDSIZ(siz), 0, tmem, G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock( \ + G_TX_LOADTILE, 0, 0, \ + G_LTB_LRS(width, height, siz), \ + dxt), \ + gsDPPipeSync(), \ + gsDPSetTile( \ + fmt, siz, line, tmem, rt, pal, \ + cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize(rt, 0, 0, qu102((width) - 1), qu102((height) - 1)) + +#define gsDPLoadTextureBlock(timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(siz, width), 0x0, G_TX_RENDERTILE, \ + ((width) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define gsDPLoadTextureBlockS(timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, 0x0, G_TX_RENDERTILE, \ + ((width) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define gsDPLoadTextureBlock_4b(timg, fmt, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, G_IM_SIZ_4b, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(G_IM_SIZ_4b, width), 0x0, G_TX_RENDERTILE, \ + ((width) * 4 + 63) / 64) + +#define gsDPLoadTextureBlock_4bS(timg, fmt, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, G_IM_SIZ_4b, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, 0x0, G_TX_RENDERTILE, \ + ((width) * 4 + 63) / 64) + +#define gsDPLoadTextureBlockYuv(timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(siz, width), 0x0, G_TX_RENDERTILE, \ + ((width) + 7) / 8) + +#define gsDPLoadTextureBlockYuvS(timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, 0x0, G_TX_RENDERTILE, \ + ((width) + 7) / 8) + +#define _gsDPLoadTextureBlock(timg, tmem, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(siz, width), tmem, G_TX_RENDERTILE, \ + ((width) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define _gsDPLoadTextureBlockS(timg, tmem, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, tmem, G_TX_RENDERTILE, \ + ((width) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define _gsDPLoadTextureBlock_4b(timg, tmem, fmt, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, G_IM_SIZ_4b, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(G_IM_SIZ_4b, width), tmem, G_TX_RENDERTILE, \ + ((width) * 4 + 63) / 64) + +#define _gsDPLoadTextureBlock_4bS(timg, tmem, fmt, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, G_IM_SIZ_4b, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, tmem, G_TX_RENDERTILE, \ + ((width) * 4 + 63) / 64) + +#define _gsDPLoadTextureBlockYuv(timg, tmem, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(siz, width), tmem, G_TX_RENDERTILE, \ + ((width) + 7) / 8) + +#define _gsDPLoadTextureBlockYuvS(timg, tmem, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, tmem, G_TX_RENDERTILE, \ + ((width) + 7) / 8) + +#define gsDPLoadMultiBlock(timg, tmem, rt, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(siz, width), tmem, rt, \ + ((width) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define gsDPLoadMultiBlockS(timg, tmem, rt, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, tmem, rt, \ + ((width) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define gsDPLoadMultiBlock_4b(timg, tmem, rt, fmt, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, G_IM_SIZ_4b, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(G_IM_SIZ_4b, width), tmem, rt, \ + ((width) * 4 + 63) / 64) + +#define gsDPLoadMultiBlock_4bS(timg, tmem, rt, fmt, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, G_IM_SIZ_4b, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, tmem, rt, \ + ((width) * 4 + 63) / 64) + +#define gsDPLoadMultiBlockYuv(timg, tmem, rt, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + G_DXT(siz, width), tmem, rt, \ + ((width) + 7) / 8) + +#define gsDPLoadMultiBlockYuvS(timg, tmem, rt, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTB_( \ + timg, fmt, siz, width, height, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0, tmem, rt, \ + ((width) + 7) / 8) + +#define gLTT_(timg, fmt, siz, width, height, uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, rt, line) \ + gsDPSetTextureImage(fmt, siz, width, timg), \ + gsDPSetTile( \ + fmt, siz, line, tmem, \ + G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile( \ + G_TX_LOADTILE, \ + qu102(uls), qu102(ult), \ + qu102(lrs), qu102(lrt)), \ + gsDPPipeSync(), \ + gsDPSetTile( \ + fmt, siz, line, \ + tmem, rt, pal, \ + cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize( \ + rt, \ + qu102(uls), qu102(ult), \ + qu102(lrs), qu102(lrt)) + +#define gLTT4_(timg, fmt, width, height, uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, rt) \ + gsDPSetTextureImage(fmt, G_IM_SIZ_8b, (width) / 2, timg), \ + gsDPSetTile( \ + fmt, G_IM_SIZ_8b, \ + (((lrs) - (uls) + 1) / 2 + 7) / 8, \ + tmem, G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile( \ + G_TX_LOADTILE, \ + qu102(uls) / 2, qu102(ult), \ + qu102(lrs) / 2, qu102(lrt)), \ + gsDPPipeSync(), \ + gsDPSetTile( \ + fmt, G_IM_SIZ_4b, \ + (((lrs) - (uls) + 1) / 2 + 7) / 8, \ + tmem, rt, pal, \ + cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize( \ + rt, \ + qu102(uls), qu102(ult), \ + qu102(lrs), qu102(lrt)) + +#define gsDPLoadTextureTile(timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT_( \ + timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0x0, G_TX_RENDERTILE, \ + (((lrs) - (uls) + 1) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define gsDPLoadTextureTile_4b(timg, fmt, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT4_( \ + timg, fmt, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0x0, G_TX_RENDERTILE) + +#define gsDPLoadTextureTileYuv(timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT_( \ + timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + 0x0, G_TX_RENDERTILE, \ + (((lrs) - (uls) + 1) + 7) / 8) + +#define _gsDPLoadTextureTile(timg, tmem, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT_( \ + timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, G_TX_RENDERTILE, \ + (((lrs) - (uls) + 1) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define _gsDPLoadTextureTile_4b(timg, tmem, fmt, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT4_( \ + timg, fmt, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, G_TX_RENDERTILE) + +#define _gsDPLoadTextureTileYuv(timg, tmem, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, cms, cmt, \ + masks, maskt, shifts, shiftt) \ + gLTT_( \ + timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, G_TX_RENDERTILE, \ + (((lrs) - (uls) + 1) + 7) / 8) + +#define gsDPLoadMultiTile(timg, tmem, rt, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT_( \ + timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, rt, \ + (((lrs) - (uls) + 1) * G_SIZ_LDBITS(siz) + 63) / 64) + +#define gsDPLoadMultiTile_4b(timg, tmem, rt, fmt, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT4_( \ + timg, fmt, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, rt) + +#define gsDPLoadMultiTileYuv(timg, tmem, rt, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ + gLTT_( \ + timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt, \ + tmem, rt, \ + (((lrs) - (uls) + 1) + 7) / 8) + +#define gsDPLoadBlock(tile, uls, ult, lrs, dxt) \ + gO_( \ + G_LOADBLOCK, \ + gF_(uls, 12, 12) | \ + gF_(ult, 12, 0), \ + gF_(tile, 3, 24) | \ + gF_(G_LDBLK_TXL(lrs), 12, 12) | \ + gF_(dxt, 12, 0)) + +#define gsDPNoOp() \ + gsDPNoOpTag(0) + +#define gsDPNoOpTag(tag) \ + gO_(G_NOOP, 0, tag) + +#define gsDPPipelineMode(mode) \ + gsSPSetOtherModeHi(G_MDSFT_PIPELINE, G_MDSIZ_PIPELINE, mode) + +#define gsDPSetBlendColor(r, g, b, a) \ + gO_( \ + G_SETBLENDCOLOR, \ + 0, \ + gF_(r, 8, 24) | \ + gF_(g, 8, 16) | \ + gF_(b, 8, 8) | \ + gF_(a, 8, 0)) + +#define gsDPSetEnvColor(r, g, b, a) \ + gO_( \ + G_SETENVCOLOR, \ + 0, \ + gF_(r, 8, 24) | \ + gF_(g, 8, 16) | \ + gF_(b, 8, 8) | \ + gF_(a, 8, 0)) + +#define gsDPSetFillColor(c) \ + gO_(G_SETFILLCOLOR, 0, c) + +#define gsDPSetFogColor(r, g, b, a) \ + gO_( \ + G_SETFOGCOLOR, 0, \ + gF_(r, 8, 24) | \ + gF_(g, 8, 16) | \ + gF_(b, 8, 8) | \ + gF_(a, 8, 0)) + +#define gsDPSetPrimColor(m, l, r, g, b, a) \ + gO_( \ + G_SETPRIMCOLOR, \ + gF_(m, 8, 8) | \ + gF_(l, 8, 0), \ + gF_(r, 8, 24) | \ + gF_(g, 8, 16) | \ + gF_(b, 8, 8) | \ + gF_(a, 8, 0)) + +#define gsDPSetColorImage(fmt, siz, width, img) \ + gO_( \ + G_SETCIMG, \ + gF_(fmt, 3, 21) | \ + gF_(siz, 2, 19) | \ + gF_((width) - 1, 12, 0), \ + img) + +#define gsDPSetDepthImage(img) \ + gO_(G_SETZIMG, 0, img) + +#define gsDPSetTextureImage(fmt, siz, width, img) \ + gO_( \ + G_SETTIMG, \ + gF_(fmt, 3, 21) | \ + gF_(siz, 2, 19) | \ + gF_((width) - 1, 12, 0), \ + img) + +#define gsDPSetHilite1Tile(tile, hilite, width, height) \ + gsDPSetTileSize( \ + tile, \ + ((Hilite *)(hilite))->h.x1 & 0xFFF, \ + ((Hilite *)(hilite))->h.y1 & 0xFFF, \ + (((width) - 1) * 4 + ((Hilite *)(hilite))->h.x1) & 0xFFF, \ + (((height) - 1) * 4 + ((Hilite *)(hilite))->h.y1) & 0xFFF) + +#define gsDPSetHilite2Tile(tile, hilite, width, height) \ + gsDPSetTileSize( \ + tile, \ + ((Hilite *)(hilite))->h.x2 & 0xFFF, \ + ((Hilite *)(hilite))->h.y2 & 0xFFF, \ + (((width) - 1) * 4 + ((Hilite *)(hilite))->h.x2) & 0xFFF, \ + (((height) - 1) * 4 + ((Hilite *)(hilite))->h.y2) & 0xFFF) + +#define gsDPSetAlphaCompare(mode) \ + gsSPSetOtherModeLo(G_MDSFT_ALPHACOMPARE, G_MDSIZ_ALPHACOMPARE, mode) + +#define gsDPSetAlphaDither(type) \ + gsSPSetOtherModeHi(G_MDSFT_ALPHADITHER, G_MDSIZ_ALPHADITHER, type) + +#define gsDPSetColorDither(type) \ + gsSPSetOtherModeHi(G_MDSFT_RGBDITHER, G_MDSIZ_RGBDITHER, type) + +#define gsDPSetCombineMode(mode1, mode2) \ + gsDPSetCombineLERP(mode1, mode2) + +#define gsDPSetCombineLERP(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \ + a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ + gO_( \ + G_SETCOMBINE, \ + gF_(G_CCMUX_##a0, 4, 20) | \ + gF_(G_CCMUX_##c0, 5, 15) | \ + gF_(G_ACMUX_##Aa0, 3, 12) | \ + gF_(G_ACMUX_##Ac0, 3, 9) | \ + gF_(G_CCMUX_##a1, 4, 5) | \ + gF_(G_CCMUX_##c1, 5, 0), \ + gF_(G_CCMUX_##b0, 4, 28) | \ + gF_(G_CCMUX_##b1, 4, 24) | \ + gF_(G_ACMUX_##Aa1, 3, 21) | \ + gF_(G_ACMUX_##Ac1, 3, 18) | \ + gF_(G_CCMUX_##d0, 3, 15) | \ + gF_(G_ACMUX_##Ab0, 3, 12) | \ + gF_(G_ACMUX_##Ad0, 3, 9) | \ + gF_(G_CCMUX_##d1, 3, 6) | \ + gF_(G_ACMUX_##Ab1, 3, 3) | \ + gF_(G_ACMUX_##Ad1, 3, 0)) + +#define gsDPSetConvert(k0, k1, k2, k3, k4, k5) \ + gO_( \ + G_SETCONVERT, \ + gF_(k0, 9, 13) | \ + gF_(k1, 9, 4) | \ + gF_(gI_(k2) >> 5, 4, 0), \ + gF_(k2, 5, 27) | \ + gF_(k3, 9, 18) | \ + gF_(k4, 9, 9) | \ + gF_(k5, 9, 0)) + +#define gsDPSetTextureConvert(type) \ + gsSPSetOtherModeHi(G_MDSFT_TEXTCONV, G_MDSIZ_TEXTCONV, type) + +#define gsDPSetCycleType(type) \ + gsSPSetOtherModeHi(G_MDSFT_CYCLETYPE, G_MDSIZ_CYCLETYPE, type) + +#define gsDPSetDepthSource(source) \ + gsSPSetOtherModeLo(G_MDSFT_ZSRCSEL, G_MDSIZ_ZSRCSEL, source) + +#define gsDPSetCombineKey(type) \ + gsSPSetOtherModeHi(G_MDSFT_COMBKEY, G_MDSIZ_COMBKEY, type) + +#define gsDPSetKeyGB(cG, sG, wG, cB, sB, wB) \ + gO_( \ + G_SETKEYGB, \ + gF_(wG, 12, 12) | \ + gF_(wB, 12, 0), \ + gF_(cG, 8, 24) | \ + gF_(sG, 8, 16) | \ + gF_(cB, 8, 8) | \ + gF_(sB, 8, 0)) + +#define gsDPSetKeyR(cR, sR, wR) \ + gO_( \ + G_SETKEYR, 0, \ + gF_(wR, 12, 16) | \ + gF_(cR, 8, 8) | \ + gF_(sR, 8, 0)) + +#define gsDPSetPrimDepth(z, dz) \ + gO_( \ + G_SETPRIMDEPTH, \ + 0, \ + gF_(z, 16, 16) | \ + gF_(dz, 16, 0)) + +#define gsDPSetRenderMode(mode1, mode2) \ + gsSPSetOtherModeLo( \ + G_MDSFT_RENDERMODE, \ + G_MDSIZ_RENDERMODE, \ + gI_(mode1) | \ + gI_(mode2)) + +#define gsDPSetScissor(mode, ulx, uly, lrx, lry) \ + gsDPSetScissorFrac( \ + mode, \ + qu102(gI_(ulx)), \ + qu102(gI_(uly)), \ + qu102(gI_(lrx)), \ + qu102(gI_(lry))) + +#define gsDPSetScissorFrac(mode, ulx, uly, lrx, lry) \ + gO_( \ + G_SETSCISSOR, \ + gF_(ulx, 12, 12) | \ + gF_(uly, 12, 0), \ + gF_(mode, 2, 24) | \ + gF_(lrx, 12, 12) | \ + gF_(lry, 12, 0)) + +#define gsDPSetTextureDetail(type) \ + gsSPSetOtherModeHi(G_MDSFT_TEXTDETAIL, G_MDSIZ_TEXTDETAIL, type) + +#define gsDPSetTextureFilter(mode) \ + gsSPSetOtherModeHi(G_MDSFT_TEXTFILT, G_MDSIZ_TEXTFILT, mode) + +#define gsDPSetTextureLOD(mode) \ + gsSPSetOtherModeHi(G_MDSFT_TEXTLOD, G_MDSIZ_TEXTLOD, mode) + +#define gsDPSetTextureLUT(mode) \ + gsSPSetOtherModeHi(G_MDSFT_TEXTLUT, G_MDSIZ_TEXTLUT, mode) + +#define gsDPSetTexturePersp(enable) \ + gsSPSetOtherModeHi(G_MDSFT_TEXTPERSP, G_MDSIZ_TEXTPERSP, enable) + +#define gsDPSetTile(fmt, siz, line, tmem, tile, palette, \ + cmt, maskt, shiftt, cms, masks, shifts) \ + gO_( \ + G_SETTILE, \ + gF_(fmt, 3, 21) | \ + gF_(siz, 2, 19) | \ + gF_(line, 9, 9) | \ + gF_(tmem, 9, 0), \ + gF_(tile, 3, 24) | \ + gF_(palette, 4, 20) | \ + gF_(cmt, 2, 18) | \ + gF_(maskt, 4, 14) | \ + gF_(shiftt, 4, 10) | \ + gF_(cms, 2, 8) | \ + gF_(masks, 4, 4) | \ + gF_(shifts, 4, 0)) + +#define gsDPSetTileSize(tile, uls, ult, lrs, lrt) \ + gO_( \ + G_SETTILESIZE, \ + gF_(uls, 12, 12) | \ + gF_(ult, 12, 0), \ + gF_(tile, 3, 24) | \ + gF_(lrs, 12, 12) | \ + gF_(lrt, 12, 0)) + +#define gsSPBranchList(dl) \ + gsDisplayList(dl, 1) + +#define gsSPClipRatio(r) \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNX, (uint16_t)(r)), \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNY, (uint16_t)(r)), \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPX, (uint16_t)-(r)), \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPY, (uint16_t)-(r)) + +#define gsSPDisplayList(dl) \ + gsDisplayList(dl, 0) + +#define gsSPEndDisplayList() \ + gO_(G_ENDDL, 0, 0) + +#define gsSPFogFactor(fm, fo) \ + gsMoveWd( \ + G_MW_FOG, \ + G_MWO_FOG, \ + gF_(fm, 16, 16) | \ + gF_(fo, 16, 0)) + +#define gsSPFogPosition(min, max) \ + gsSPFogFactor( \ + (500 * 0x100) / ((max) - (min)), \ + (500 - (min)) * 0x100 / ((max) - (min))) + +#define gsSPLine3D(v0, v1, flag) \ + gsSPLineW3D(v0, v1, 0, flag) + +#define gsSPLookAt(l) \ + gsSPLookAtX(l), \ + gsSPLookAtY(gI_(l) + 0x10) + +#define gsSPSegment(seg, base) \ + gsMoveWd(G_MW_SEGMENT, (seg) * 4, base) + +#define gsSPSetLights0(lites) \ + gsSPNumLights(NUMLIGHTS_0), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).a, 2) + +#define gsSPSetLights1(lites) \ + gsSPNumLights(NUMLIGHTS_1), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).a, 2) + +#define gsSPSetLights2(lites) \ + gsSPNumLights(NUMLIGHTS_2), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).l[1], 2), \ + gsSPLight(&(lites).a, 3) + +#define gsSPSetLights3(lites) \ + gsSPNumLights(NUMLIGHTS_3), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).l[1], 2), \ + gsSPLight(&(lites).l[2], 3), \ + gsSPLight(&(lites).a, 4) + +#define gsSPSetLights4(lites) \ + gsSPNumLights(NUMLIGHTS_4), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).l[1], 2), \ + gsSPLight(&(lites).l[2], 3), \ + gsSPLight(&(lites).l[3], 4), \ + gsSPLight(&(lites).a, 5) + +#define gsSPSetLights5(lites) \ + gsSPNumLights(NUMLIGHTS_5), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).l[1], 2), \ + gsSPLight(&(lites).l[2], 3), \ + gsSPLight(&(lites).l[3], 4), \ + gsSPLight(&(lites).l[4], 5), \ + gsSPLight(&(lites).a, 6) + +#define gsSPSetLights6(lites) \ + gsSPNumLights(NUMLIGHTS_6), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).l[1], 2), \ + gsSPLight(&(lites).l[2], 3), \ + gsSPLight(&(lites).l[3], 4), \ + gsSPLight(&(lites).l[4], 5), \ + gsSPLight(&(lites).l[5], 6), \ + gsSPLight(&(lites).a, 7) + +#define gsSPSetLights7(lites) \ + gsSPNumLights(NUMLIGHTS_7), \ + gsSPLight(&(lites).l[0], 1), \ + gsSPLight(&(lites).l[1], 2), \ + gsSPLight(&(lites).l[2], 3), \ + gsSPLight(&(lites).l[3], 4), \ + gsSPLight(&(lites).l[4], 5), \ + gsSPLight(&(lites).l[5], 6), \ + gsSPLight(&(lites).l[6], 7), \ + gsSPLight(&(lites).a, 8) + +#define gsSPSetStatus(sid, val) \ + gsMoveWd(G_MW_GENSTAT, sid, val) + +#define gsSPNumLights(n) \ + gsMoveWd(G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n)) + +#define gsSPLightColor(Lightnum, packedcolor) \ + gsMoveWd(G_MW_LIGHTCOL, G_MWO_a##Lightnum, packedcolor), \ + gsMoveWd(G_MW_LIGHTCOL, G_MWO_b##Lightnum, packedcolor) + +#define gsSPTextureRectangle(ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy) \ + gsTexRect(ulx, uly, lrx, lry, tile), \ + gsDPHalf1(gF_(s, 16, 16) | gF_(t, 16, 0)), \ + gsDPHalf2(gF_(dsdx, 16, 16) | gF_(dtdy, 16, 0)) + +#define gsSPScisTextureRectangle(ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy) \ + gsTexRect(gScC_(ulx), gScC_(uly), gScC_(lrx), gScC_(lry), tile), \ + gsDPHalf1( \ + gF_(gScD_(s, ulx, dsdx), 16, 16) | \ + gF_(gScD_(t, uly, dtdy), 16, 0)), \ + gsDPHalf2(gF_(dsdx, 16, 16) | gF_(dtdy, 16, 0)) + +#define gsSPTextureRectangleFlip(ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy) \ + gsTexRectFlip(ulx, uly, lrx, lry, tile), \ + gsDPHalf1(gF_(s, 16, 16) | gF_(t, 16, 0)), \ + gsDPHalf2(gF_(dsdx, 16, 16) | gF_(dtdy, 16, 0)) + +#define gsSPScisTextureRectangleFlip( \ + ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy) \ + gsTexRectFlip(gScC_(ulx), gScC_(uly), gScC_(lrx), gScC_(lry), tile), \ + gsDPHalf1( \ + gF_(gScD_(s, ulx, dsdx), 16, 16) | \ + gF_(gScD_(t, uly, dtdy), 16, 0)), \ + gsDPHalf2(gF_(dsdx, 16, 16) | gF_(dtdy, 16, 0)) + +#define gsSPBgRectCopy(bg) \ + gO_(G_BG_COPY, 0, bg) + +#define gsSPBgRect1Cyc(bg) \ + gO_(G_BG_1CYC, 0, bg) + +#define gsSPObjRectangle(sp) \ + gO_(G_OBJ_RECTANGLE, 0, sp) + +#define gsSPObjRectangleR(sp) \ + gO_(G_OBJ_RECTANGLE_R, 0, sp) + +#define gsSPObjSprite(sp) \ + gO_(G_OBJ_SPRITE, 0, sp) + +#define gsSPObjMatrix(mtx) \ + gO_( \ + G_OBJ_MOVEMEM, \ + gF_(sizeof(uObjMtx) - 1, 8, 16), \ + mtx) + +#define gsSPObjSubMatrix(mtx) \ + gO_( \ + G_OBJ_MOVEMEM, \ + gF_(sizeof(uObjSubMtx) - 1, 8, 16) | \ + gF_(2, 16, 0), \ + mtx) + +#define gsSPObjRenderMode(mode) \ + gO_(G_OBJ_RENDERMODE, 0, mode) + +#define gsSPObjLoadTxtr(tx) \ + gO_(G_OBJ_LOADTXTR, 23, tx) + +#define gsSPObjLoadTxRect(txsp) \ + gO_(G_OBJ_LDTX_RECT, 47, txsp) + +#define gsSPObjLoadTxRectR(txsp) \ + gO_(G_OBJ_LDTX_RECT_R, 47, txsp) + +#define gsSPObjLoadTxSprite(txsp) \ + gO_(G_OBJ_LDTX_SPRITE, 47, txsp) + +#define gsSPSelectDL(ldl, sid, flag, mask) \ + gO_( \ + G_RDPHALF_0, \ + gF_(sid, 8, 16) | \ + gF_(ldl, 16, 0), \ + flag), \ + gO_( \ + G_SELECT_DL, \ + gF_(0x00, 8, 16) | \ + gF_(gI_(ldl) >> 16, 16, 0), \ + mask) + +#define gsSPSelectBranchDL(bdl, sid, flag, mask) \ + gO_( \ + G_RDPHALF_0, \ + gF_(sid, 8, 16) | \ + gF_(bdl, 16, 0), \ + flag), \ + gO_( \ + G_SELECT_DL, \ + gF_(0x01, 8, 16) | \ + gF_(gI_(bdl) >> 16, 16, 0), \ + mask) + +/* unlisted instructions */ + +#define gsDPLoadTLUTCmd(tile, count) \ + gO_( \ + G_LOADTLUT, \ + 0, \ + gF_(tile, 3, 24) | \ + gF_(count, 10, 14)) + +#define gsDPLoadTLUT(count, tmem, dram) \ + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \ + gsDPTileSync(), \ + gsDPSetTile(0, 0, 0, tmem, G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0), \ + gsDPLoadSync(), \ + gsDPLoadTLUTCmd(G_TX_LOADTILE, (count) - 1), \ + gsDPPipeSync() + +#define gsDisplayList(dl, branch) \ + gO_(G_DL, gF_(branch, 8, 16), dl) + +#define gsDPLoadTile(tile, uls, ult, lrs, lrt) \ + gO_( \ + G_LOADTILE, \ + gF_(uls, 12, 12) | \ + gF_(ult, 12, 0), \ + gF_(tile, 3, 24) | \ + gF_(lrs, 12, 12) | \ + gF_(lrt, 12, 0)) + +#define gsDPSetCombine(c) \ + gO_( \ + G_SETCOMBINE, \ + (gL_(c) >> 32) & 0xFFFFFFFF, \ + (gL_(c) >> 0) & 0xFFFFFFFF) + +#define gsSPSetOtherModeLo(shift, length, data) \ + gsSPSetOtherMode(G_SETOTHERMODE_L, shift, length, data) + +#define gsSPSetOtherModeHi(shift, length, data) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, shift, length, data) + +#define gsDPSetOtherMode(mode0, mode1) \ + gO_(G_RDPSETOTHERMODE, gF_(mode0, 24, 0), mode1) + +#define gsTexRect(ulx, uly, lrx, lry, tile) \ + gO_( \ + G_TEXRECT, \ + gF_(lrx, 12, 12) | \ + gF_(lry, 12, 0), \ + gF_(tile, 3, 24) | \ + gF_(ulx, 12, 12) | \ + gF_(uly, 12, 0)) + +#define gsTexRectFlip(ulx, uly, lrx, lry, tile) \ + gO_( \ + G_TEXRECTFLIP, \ + gF_(lrx, 12, 12) | \ + gF_(lry, 12, 0), \ + gF_(tile, 3, 24) | \ + gF_(ulx, 12, 12) | \ + gF_(uly, 12, 0)) + +#define gsSPNoOp() \ + gO_(G_SPNOOP, 0, 0) + +#define gsDPHalf1(wordhi) \ + gO_(G_RDPHALF_1, 0, wordhi) + +#define gsDPHalf2(wordlo) \ + gO_(G_RDPHALF_2, 0, wordlo) + +#define gsDPWord(wordhi, wordlo) \ + gsDPHalf1(wordhi), \ + gsDPHalf2(wordlo) + +/* instruction macros for fast3d */ + +#if defined(F3D_GBI) + +# define gsSP1Triangle(v0, v1, v2, flag) \ + gO_( \ + G_TRI1, \ + 0, \ + gF_(flag, 8, 24) | \ + gF_(gI_(v0) * 10, 8, 16) | \ + gF_(gI_(v1) * 10, 8, 8) | \ + gF_(gI_(v2) * 10, 8, 0)) + +# define gsSPCullDisplayList(v0, vn) \ + gO_( \ + G_CULLDL, \ + (gI_(v0) & 0xF) * 40, \ + gI_((vn) + 1) & 0xF) * 40) + +# define gsSPLineW3D(v0, v1, wd, flag) \ + gO_( \ + G_LINE3D, \ + 0, \ + gF_(flag, 8, 24) | \ + gF_(gI_(v0) * 10, 8, 16) | \ + gF_(gI_(v1) * 10, 8, 8) | \ + gF_(wd, 8, 0)) + +# define gsSPVertex(v, n, v0) \ + gO_( \ + G_VTX, \ + gF_((n) - 1, 4, 20) | \ + gF_(v0, 4, 16) | \ + gF_(sizeof(Vtx) * (n), 16, 0), \ + v) + +#endif + +/* instruction macros for fast3d and beta f3dex */ +#if defined(F3D_GBI) || (defined(F3D_BETA) && defined(F3DEX_GBI)) + +# define gsSPModifyVertex(vtx, where, val) \ + gsMoveWd(G_MW_POINTS, (vtx) * 40 + (where), val) + +#endif + +/* instruction macros for fast3d and f3dex */ + +#if defined(F3D_GBI) || defined(F3DEX_GBI) + +# define gsSPForceMatrix(mptr) \ + gsMoveMem(16, G_MV_MATRIX_1, (char *)(mptr)), \ + gsMoveMem(16, G_MV_MATRIX_2, (char *)(mptr) + 16), \ + gsMoveMem(16, G_MV_MATRIX_3, (char *)(mptr) + 32), \ + gsMoveMem(16, G_MV_MATRIX_4, (char *)(mptr) + 48) + +# define gsSPSetGeometryMode(mode) \ + gO_(G_SETGEOMETRYMODE, 0, gI_(mode)) + +# define gsSPClearGeometryMode(mode) \ + gO_(G_CLEARGEOMETRYMODE, 0, gI_(mode)) + +# define gsSPLoadGeometryMode(mode) \ + gsSPClearGeometryMode(~gI_(0)), \ + gsSPSetGeometryMode(mode) + +# define gsSPInsertMatrix(where, num) \ + gsMoveWd(G_MW_MATRIX, where, num) + +# define gsSPLookAtX(l) \ + gsMoveMem(sizeof(Light), G_MV_LOOKATX, l) + +# define gsSPLookAtY(l) \ + gsMoveMem(sizeof(Light), G_MV_LOOKATY, l) + +# define gsSPMatrix(matrix, param) \ + gO_( \ + G_MTX, \ + gF_(param, 8, 16) | \ + gF_(sizeof(Mtx), 16, 0), \ + matrix) + +# define gsSPPopMatrix(param) \ + gO_(G_POPMTX, 0, param) + +# define gsSPLight(l, n) \ + gsMoveMem(sizeof(Light), G_MV_L0 + ((n) - 1) * 2, l) + +# define gsSPTexture(sc, tc, level, tile, on) \ + gO_( \ + G_TEXTURE, \ + gF_(level, 3, 11) | \ + gF_(tile, 3, 8) | \ + gF_(on, 8, 0), \ + gF_(sc, 16, 16) | \ + gF_(tc, 16, 0)) + +# define gsSPViewport(v) \ + gsMoveMem(sizeof(Vp), G_MV_VIEWPORT, v) + +# define gsSPSetOtherMode(opc, shift, length, data) \ + gO_( \ + opc, \ + gF_(shift, 8, 8) | \ + gF_(length, 8, 0), \ + data) + +# define gsMoveWd(index, offset, data) \ + gO_( \ + G_MOVEWORD, \ + gF_(offset, 16, 8) | \ + gF_(index, 8, 0), \ + data) + +# define gsMoveMem(size, index, address) \ + gO_( \ + G_MOVEMEM, \ + gF_(index, 8, 16) | \ + gF_(size, 16, 0), \ + address) + +#endif + +/* instruction macros for f3dex */ + +#if defined(F3DEX_GBI) + +# define gsSP1Triangle(v0, v1, v2, flag) \ + gO_( \ + G_TRI1, \ + 0, \ + gF_(gV3_(v0, v1, v2, flag) * 2, 8, 16) | \ + gF_(gV3_(v1, v2, v0, flag) * 2, 8, 8) | \ + gF_(gV3_(v2, v0, v1, flag) * 2, 8, 0)) + +# define gsSP1Quadrangle(v0, v1, v2, v3, flag) \ + gO_( \ + G_TRI2, \ + gF_(gV4_(v0, v1, v2, v3, flag) * 2, 8, 16) | \ + gF_(gV4_(v1, v2, v3, v0, flag) * 2, 8, 8) | \ + gF_(gV4_(v2, v3, v0, v1, flag) * 2, 8, 0), \ + gF_(gV4_(v0, v1, v2, v3, flag) * 2, 8, 16) | \ + gF_(gV4_(v2, v3, v0, v1, flag) * 2, 8, 8) | \ + gF_(gV4_(v3, v0, v1, v2, flag) * 2, 8, 0)) + +# define gsSPLineW3D(v0, v1, wd, flag) \ + gO_( \ + G_LINE3D, \ + 0, \ + gF_(gV2_(v0, v1, flag) * 2, 8, 16) | \ + gF_(gV2_(v1, v0, flag) * 2, 8, 8) | \ + gF_(wd, 8, 0)) + +# define gsSPVertex(v, n, v0) \ + gO_( \ + G_VTX, \ + gF_((v0) * 2, 8, 16) | \ + gF_(n, 6, 10) | \ + gF_(sizeof(Vtx) * (n) - 1, 10, 0), \ + v) + +#endif + +/* instruction macros for f3dex and f3dex2 */ + +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + +# define gsSP2Triangles(v00, v01, v02, flag0, v10, v11, v12, flag1) \ + gO_( \ + G_TRI2, \ + gF_(gV3_(v00, v01, v02, flag0) * 2, 8, 16) | \ + gF_(gV3_(v01, v02, v00, flag0) * 2, 8, 8) | \ + gF_(gV3_(v02, v00, v01, flag0) * 2, 8, 0), \ + gF_(gV3_(v10, v11, v12, flag1) * 2, 8, 16) | \ + gF_(gV3_(v11, v12, v10, flag1) * 2, 8, 8) | \ + gF_(gV3_(v12, v10, v11, flag1) * 2, 8, 0)) + +# define gsSPBranchLessZ(branchdl, vtx, zval, near, far, flag) \ + gsSPBranchLessZrg(branchdl, vtx, zval, near, far, flag, 0, G_MAXZ) + +# define gsSPBranchLessZrg(branchdl, vtx, zval, near, far, flag, zmin, zmax) \ + gsSPBranchLessZraw(branchdl, vtx, \ + G_DEPTOZSrg(zval, near, far, flag, zmin, zmax)) + +# define gsSPBranchLessZraw(branchdl, vtx, zval) \ + gsDPHalf1(branchdl), \ + gsBranchZ(vtx, zval) + +# define gsSPCullDisplayList(v0, vn) \ + gO_( \ + G_CULLDL, \ + gF_((v0) * 2, 16, 0), \ + gF_((vn) * 2, 16, 0)) + +# define gsSPLoadUcode(uc_start, uc_dstart) \ + gsSPLoadUcodeEx(uc_start, uc_dstart, 0x800) + +# define gsSPLoadUcodeL(ucode) \ + gsSPLoadUcode( \ + gI_(&ucode##TextStart) & 0x1FFFFFFF, \ + gI_(&ucode##DataStart) & 0x1FFFFFFF) + +# if !(defined(F3D_BETA) && defined(F3DEX_GBI)) +# define gsSPModifyVertex(vtx, where, val) \ + gO_( \ + G_MODIFYVTX, \ + gF_(where, 8, 16) | \ + gF_((vtx) * 2, 16, 0), \ + val) +# endif + +# define gsBranchZ(vtx, zval) \ + gO_( \ + G_BRANCH_Z, \ + gF_((vtx) * 5, 12, 12) | \ + gF_((vtx) * 2, 12, 0), \ + zval) + +# define gsLoadUcode(uc_start, uc_dsize) \ + gO_( \ + G_LOAD_UCODE, \ + gF_((uc_dsize) - 1, 16, 0), \ + uc_start) + +# define gsSPLoadUcodeEx(uc_start, uc_dstart, uc_dsize) \ + gsDPHalf1(uc_dstart), \ + gsLoadUcode(uc_start, uc_dsize) + +#endif + +/* instruction macros for f3dex2 */ + +#if defined(F3DEX_GBI_2) + +# define gsSP1Triangle(v0, v1, v2, flag) \ + gO_( \ + G_TRI1, \ + gF_(gV3_(v0, v1, v2, flag) * 2, 8, 16) | \ + gF_(gV3_(v1, v2, v0, flag) * 2, 8, 8) | \ + gF_(gV3_(v2, v0, v1, flag) * 2, 8, 0), \ + 0) + +# define gsSP1Quadrangle(v0, v1, v2, v3, flag) \ + gO_( \ + G_QUAD, \ + gF_(gV4_(v0, v1, v2, v3, flag) * 2, 8, 16) | \ + gF_(gV4_(v1, v2, v3, v0, flag) * 2, 8, 8) | \ + gF_(gV4_(v2, v3, v0, v1, flag) * 2, 8, 0), \ + gF_(gV4_(v0, v1, v2, v3, flag) * 2, 8, 16) | \ + gF_(gV4_(v2, v3, v0, v1, flag) * 2, 8, 8) | \ + gF_(gV4_(v3, v0, v1, v2, flag) * 2, 8, 0)) + +# define gsSPForceMatrix(mptr) \ + gsMoveMem(sizeof(Mtx), G_MV_MATRIX, 0, mptr), \ + gsMoveWd(G_MW_FORCEMTX, 0, 0x10000) + +# define gsSPSetGeometryMode(mode) \ + gsSPGeometryMode(0, mode) + +# define gsSPClearGeometryMode(mode) \ + gsSPGeometryMode(mode, 0) + +# define gsSPLoadGeometryMode(mode) \ + gsSPGeometryMode(~gI_(0), mode) + +# define gsSPLineW3D(v0, v1, wd, flag) \ + gO_( \ + G_LINE3D, \ + gF_(gV2_(v0, v1, flag) * 2, 8, 16) | \ + gF_(gV2_(v1, v0, flag) * 2, 8, 8) | \ + gF_(wd, 8, 0), \ + 0) + +# define gsSPLookAtX(l) \ + gsMoveMem(sizeof(Light), G_MV_LIGHT, G_MVO_LOOKATX, l) + +# define gsSPLookAtY(l) \ + gsMoveMem(sizeof(Light), G_MV_LIGHT, G_MVO_LOOKATY, l) + +# define gsSPMatrix(matrix, param) \ + gO_( \ + G_MTX, \ + gF_((sizeof(Mtx) - 1) / 8, 5, 19) | \ + gF_(gI_(param) ^ G_MTX_PUSH, 8, 0), \ + matrix) + +# define gsSPPopMatrix(param) \ + gsSPPopMatrixN(param, 1) + +# define gsSPPopMatrixN(param, n) \ + gO_( \ + G_POPMTX, \ + gF_((sizeof(Mtx) - 1) / 8, 5, 19) | \ + gF_(2, 8, 0), \ + sizeof(Mtx) * (n)) + +# define gsSPLight(l, n) \ + gsMoveMem(sizeof(Light), G_MV_LIGHT, ((n) + 1) * 0x18, l) + +# define gsSPTexture(sc, tc, level, tile, on) \ + gO_( \ + G_TEXTURE, \ + gF_(level, 3, 11) | \ + gF_(tile, 3, 8) | \ + gF_(on, 7, 1), \ + gF_(sc, 16, 16) | \ + gF_(tc, 16, 0)) + +# define gsSPVertex(v, n, v0) \ + gO_( \ + G_VTX, \ + gF_(n, 8, 12) | \ + gF_((v0) + (n), 7, 1), \ + v) + +# define gsSPViewport(v) \ + gsMoveMem(sizeof(Vp), G_MV_VIEWPORT, 0, v) + +# define gsSPGeometryMode(clearbits, setbits) \ + gO_( \ + G_GEOMETRYMODE, \ + gF_(~gI_(clearbits), 24, 0), \ + setbits) + +# define gsSPSetOtherMode(opc, shift, length, data) \ + gO_( \ + opc, \ + gF_(32 - (shift) - (length), 8, 8) | \ + gF_((length) - 1, 8, 0), \ + data) + +# define gsMoveWd(index, offset, data) \ + gO_( \ + G_MOVEWORD, \ + gF_(index, 8, 16) | \ + gF_(offset, 16, 0), \ + data) + +# define gsMoveMem(size, index, offset, address) \ + gO_( \ + G_MOVEMEM, \ + gF_((size - 1) / 8, 5, 19) | \ + gF_((offset) / 8, 8, 8) | \ + gF_(index, 8, 0), \ + address) + +# define gsSPDma_io(flag, dmem, dram, size) \ + gO_( \ + G_DMA_IO, \ + gF_(flag, 1, 23) | \ + gF_((dmem) / 8, 10, 13) | \ + gF_((size) - 1, 12, 0), \ + dram) + +# define gsSPDmaRead(dmem, dram, size) \ + gsSPDma_io(0, dmem, dram, size) + +# define gsSPDmaWrite(dmem, dram, size) \ + gsSPDma_io(1, dmem, dram, size) + +# define gsSpecial3(hi, lo) \ + gO_(G_SPECIAL_3, hi, lo) + +# define gsSpecial2(hi, lo) \ + gO_(G_SPECIAL_2, hi, lo) + +# define gsSpecial1(hi, lo) \ + gO_(G_SPECIAL_1, hi, lo) + +#endif + +/* instruction macros for beta fast3d and f3dex */ + +#if defined(F3D_BETA) && (defined(F3D_GBI) || defined(F3DEX_GBI)) + +# define gsSPPerspNormalize(scale) \ + gO_(G_PERSPNORM, 0, scale) + +#else + +# define gsSPPerspNormalize(scale) \ + gsMoveWd(G_MW_PERSPNORM, 0, scale) + +#endif + +/* dynamic instruction macros */ + +#define gDisplayListPut(gdl, ...) \ + ({ \ + Gfx Gd_[] = {__VA_ARGS__}; \ + for(size_t Gi_ = 0; Gi_ < sizeof(Gd_) / sizeof(Gfx); Gi_++) \ + { \ + *(Gfx *)(gdl) = Gd_[Gi_]; \ + } \ + (void)0; \ + }) +#define gDisplayListAppend(pgdl, ...) \ + ({ \ + Gfx Gd_[] = {__VA_ARGS__}; \ + for(size_t Gi_ = 0; Gi_ < sizeof(Gd_) / sizeof(Gfx); Gi_++) \ + { \ + *(*(Gfx **)(pgdl))++ = Gd_[Gi_]; \ + } \ + (void)0; \ + }) +#define gDisplayListData(pgdl, d) \ + ({ \ + Gfx **Gp_ = (void *)(pgdl); \ + struct \ + { \ + __typeof__(d) v; \ + } *Gd_, *Gs_; \ + *Gp_ -= (sizeof(*Gd_) + sizeof(Gfx) - 1) / sizeof(Gfx); \ + Gd_ = (void *)*Gp_; \ + Gs_ = (void *)&(d); \ + *Gd_ = *Gs_; \ + &Gd_->v; \ + }) +#define gDisplayListAlloc(pgdl, s) \ + ({ \ + Gfx **Gp_ = (void *)(pgdl); \ + *Gp_ -= ((s) + sizeof(Gfx) - 1) / sizeof(Gfx); \ + (void *)*Gp_; \ + }) + +#define gDPFillRectangle(gdl, ...) \ + gD_(gdl, gsDPFillRectangle, __VA_ARGS__) +#define gDPScisFillRectangle(gdl, ...) \ + gD_(gdl, gsDPScisFillRectangle, __VA_ARGS__) +#define gDPFullSync(gdl) \ + gDisplayListPut(gdl, gsDPFullSync()) +#define gDPLoadSync(gdl) \ + gDisplayListPut(gdl, gsDPLoadSync()) +#define gDPTileSync(gdl) \ + gDisplayListPut(gdl, gsDPTileSync()) +#define gDPPipeSync(gdl) \ + gDisplayListPut(gdl, gsDPPipeSync()) +#define gDPLoadTLUT_pal16(gdl, ...) \ + gD_(gdl, gsDPLoadTLUT_pal16, __VA_ARGS__) +#define gDPLoadTLUT_pal256(gdl, ...) \ + gD_(gdl, gsDPLoadTLUT_pal256, __VA_ARGS__) +#define gDPLoadTextureBlock(gdl, ...) \ + gD_(gdl, gsDPLoadTextureBlock, __VA_ARGS__) +#define gDPLoadTextureBlockS(gdl, ...) \ + gD_(gdl, gsDPLoadTextureBlockS, __VA_ARGS__) +#define gDPLoadTextureBlock_4b(gdl, ...) \ + gD_(gdl, gsDPLoadTextureBlock_4b, __VA_ARGS__) +#define gDPLoadTextureBlock_4bS(gdl, ...) \ + gD_(gdl, gsDPLoadTextureBlock_4bS, __VA_ARGS__) +#define gDPLoadTextureBlockYuv(gdl, ...) \ + gD_(gdl, gsDPLoadTextureBlockYuv, __VA_ARGS__) +#define gDPLoadTextureBlockYuvS(gdl, ...) \ + gD_(gdl, gsDPLoadTextureBlockYuvS, __VA_ARGS__) +#define _gDPLoadTextureBlock(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureBlock, __VA_ARGS__) +#define _gDPLoadTextureBlockS(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureBlockS, __VA_ARGS__) +#define _gDPLoadTextureBlock_4b(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureBlock_4b, __VA_ARGS__) +#define _gDPLoadTextureBlock_4bS(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureBlock_4bS, __VA_ARGS__) +#define _gDPLoadTextureBlockYuv(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureBlockYuv, __VA_ARGS__) +#define _gDPLoadTextureBlockYuvS(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureBlockYuvS, __VA_ARGS__) +#define gDPLoadMultiBlock(gdl, ...) \ + gD_(gdl, gsDPLoadMultiBlock, __VA_ARGS__) +#define gDPLoadMultiBlockS(gdl, ...) \ + gD_(gdl, gsDPLoadMultiBlockS, __VA_ARGS__) +#define gDPLoadMultiBlock_4b(gdl, ...) \ + gD_(gdl, gsDPLoadMultiBlock_4b, __VA_ARGS__) +#define gDPLoadMultiBlock_4bS(gdl, ...) \ + gD_(gdl, gsDPLoadMultiBlock_4bS, __VA_ARGS__) +#define gDPLoadMultiBlockYuv(gdl, ...) \ + gD_(gdl, gsDPLoadMultiBlockYuv, __VA_ARGS__) +#define gDPLoadMultiBlockYuvS(gdl, ...) \ + gD_(gdl, gsDPLoadMultiBlockYuvS, __VA_ARGS__) +#define gDPLoadTextureTile(gdl, ...) \ + gD_(gdl, gsDPLoadTextureTile, __VA_ARGS__) +#define gDPLoadTextureTile_4b(gdl, ...) \ + gD_(gdl, gsDPLoadTextureTile_4b, __VA_ARGS__) +#define gDPLoadTextureTileYuv(gdl, ...) \ + gD_(gdl, gsDPLoadTextureTileYuv, __VA_ARGS__) +#define _gDPLoadTextureTile(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureTile, __VA_ARGS__) +#define _gDPLoadTextureTile_4b(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureTile_4b, __VA_ARGS__) +#define _gDPLoadTextureTileYuv(gdl, ...) \ + gD_(gdl, _gsDPLoadTextureTileYuv, __VA_ARGS__) +#define gDPLoadMultiTile(gdl, ...) \ + gD_(gdl, gsDPLoadMultiTile, __VA_ARGS__) +#define gDPLoadMultiTile_4b(gdl, ...) \ + gD_(gdl, gsDPLoadMultiTile_4b, __VA_ARGS__) +#define gDPLoadMultiTileYuv(gdl, ...) \ + gD_(gdl, gsDPLoadMultiTileYuv, __VA_ARGS__) +#define gDPLoadBlock(gdl, ...) \ + gD_(gdl, gsDPLoadBlock, __VA_ARGS__) +#define gDPNoOp(gdl) \ + gDisplayListPut(gdl, gsDPNoOp()) +#define gDPNoOpTag(gdl, ...) \ + gD_(gdl, gsDPNoOpTag, __VA_ARGS__) +#define gDPPipelineMode(gdl, ...) \ + gD_(gdl, gsDPPipelineMode, __VA_ARGS__) +#define gDPSetBlendColor(gdl, ...) \ + gD_(gdl, gsDPSetBlendColor, __VA_ARGS__) +#define gDPSetEnvColor(gdl, ...) \ + gD_(gdl, gsDPSetEnvColor, __VA_ARGS__) +#define gDPSetFillColor(gdl, ...) \ + gD_(gdl, gsDPSetFillColor, __VA_ARGS__) +#define gDPSetFogColor(gdl, ...) \ + gD_(gdl, gsDPSetFogColor, __VA_ARGS__) +#define gDPSetPrimColor(gdl, ...) \ + gD_(gdl, gsDPSetPrimColor, __VA_ARGS__) +#define gDPSetColorImage(gdl, ...) \ + gD_(gdl, gsDPSetColorImage, __VA_ARGS__) +#define gDPSetDepthImage(gdl, ...) \ + gD_(gdl, gsDPSetDepthImage, __VA_ARGS__) +#define gDPSetTextureImage(gdl, ...) \ + gD_(gdl, gsDPSetTextureImage, __VA_ARGS__) +#define gDPSetHilite1Tile(gdl, ...) \ + gD_(gdl, gsDPSetHilite1Tile, __VA_ARGS__) +#define gDPSetHilite2Tile(gdl, ...) \ + gD_(gdl, gsDPSetHilite2Tile, __VA_ARGS__) +#define gDPSetAlphaCompare(gdl, ...) \ + gD_(gdl, gsDPSetAlphaCompare, __VA_ARGS__) +#define gDPSetAlphaDither(gdl, ...) \ + gD_(gdl, gsDPSetAlphaDither, __VA_ARGS__) +#define gDPSetColorDither(gdl, ...) \ + gD_(gdl, gsDPSetColorDither, __VA_ARGS__) +#define gDPSetCombineMode(gdl, ...) \ + gD_(gdl, gsDPSetCombineLERP, __VA_ARGS__) +#define gDPSetCombineLERP(gdl, ...) \ + gD_(gdl, gsDPSetCombineLERP, __VA_ARGS__) +#define gDPSetConvert(gdl, ...) \ + gD_(gdl, gsDPSetConvert, __VA_ARGS__) +#define gDPSetTextureConvert(gdl, ...) \ + gD_(gdl, gsDPSetTextureConvert, __VA_ARGS__) +#define gDPSetCycleType(gdl, ...) \ + gD_(gdl, gsDPSetCycleType, __VA_ARGS__) +#define gDPSetDepthSource(gdl, ...) \ + gD_(gdl, gsDPSetDepthSource, __VA_ARGS__) +#define gDPSetCombineKey(gdl, ...) \ + gD_(gdl, gsDPSetCombineKey, __VA_ARGS__) +#define gDPSetKeyGB(gdl, ...) \ + gD_(gdl, gsDPSetKeyGB, __VA_ARGS__) +#define gDPSetKeyR(gdl, ...) \ + gD_(gdl, gsDPSetKeyR, __VA_ARGS__) +#define gDPSetPrimDepth(gdl, ...) \ + gD_(gdl, gsDPSetPrimDepth, __VA_ARGS__) +#define gDPSetRenderMode(gdl, ...) \ + gD_(gdl, gsDPSetRenderMode, __VA_ARGS__) +#define gDPSetScissor(gdl, ...) \ + gD_(gdl, gsDPSetScissor, __VA_ARGS__) +#define gDPSetScissorFrac(gdl, ...) \ + gD_(gdl, gsDPSetScissorFrac, __VA_ARGS__) +#define gDPSetTextureDetail(gdl, ...) \ + gD_(gdl, gsDPSetTextureDetail, __VA_ARGS__) +#define gDPSetTextureFilter(gdl, ...) \ + gD_(gdl, gsDPSetTextureFilter, __VA_ARGS__) +#define gDPSetTextureLOD(gdl, ...) \ + gD_(gdl, gsDPSetTextureLOD, __VA_ARGS__) +#define gDPSetTextureLUT(gdl, ...) \ + gD_(gdl, gsDPSetTextureLUT, __VA_ARGS__) +#define gDPSetTexturePersp(gdl, ...) \ + gD_(gdl, gsDPSetTexturePersp, __VA_ARGS__) +#define gDPSetTile(gdl, ...) \ + gD_(gdl, gsDPSetTile, __VA_ARGS__) +#define gDPSetTileSize(gdl, ...) \ + gD_(gdl, gsDPSetTileSize, __VA_ARGS__) +#define gSP1Triangle(gdl, ...) \ + gD_(gdl, gsSP1Triangle, __VA_ARGS__) +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +# define gSP2Triangles(gdl, ...) \ + gD_(gdl, gsSP2Triangles, __VA_ARGS__) +# define gSP1Quadrangle(gdl, ...) \ + gD_(gdl, gsSP1Quadrangle, __VA_ARGS__) +# define gSPBranchLessZ(gdl, ...) \ + gD_(gdl, gsSPBranchLessZ, __VA_ARGS__) +# define gSPBranchLessZrg(gdl, ...) \ + gD_(gdl, gsSPBranchLessZrg, __VA_ARGS__) +# define gSPBranchLessZraw(gdl, ...) \ + gD_(gdl, gsSPBranchLessZraw, __VA_ARGS__) +#endif +#define gSPBranchList(gdl, ...) \ + gD_(gdl, gsSPBranchList, __VA_ARGS__) +#define gSPClipRatio(gdl, ...) \ + gD_(gdl, gsSPClipRatio, __VA_ARGS__) +#define gSPCullDisplayList(gdl, ...) \ + gD_(gdl, gsSPCullDisplayList, __VA_ARGS__) +#define gSPDisplayList(gdl, ...) \ + gD_(gdl, gsSPDisplayList, __VA_ARGS__) +#define gSPEndDisplayList(gdl) \ + gDisplayListPut(gdl, gsSPEndDisplayList()) +#define gSPFogFactor(gdl, ...) \ + gD_(gdl, gsSPFogFactor, __VA_ARGS__) +#define gSPFogPosition(gdl, ...) \ + gD_(gdl, gsSPFogPosition, __VA_ARGS__) +#define gSPForceMatrix(gdl, ...) \ + gD_(gdl, gsSPForceMatrix, __VA_ARGS__) +#define gSPSetGeometryMode(gdl, ...) \ + gD_(gdl, gsSPSetGeometryMode, __VA_ARGS__) +#define gSPClearGeometryMode(gdl, ...) \ + gD_(gdl, gsSPClearGeometryMode, __VA_ARGS__) +#define gSPLoadGeometryMode(gdl, ...) \ + gD_(gdl, gsSPLoadGeometryMode, __VA_ARGS__) +#if defined(F3D_GBI) || defined(F3DEX_GBI) +# define gSPInsertMatrix(gdl, ...) \ + gD_(gdl, gsSPInsertMatrix, __VA_ARGS__) +#endif +#define gSPLine3D(gdl, ...) \ + gD_(gdl, gsSPLine3D, __VA_ARGS__) +#define gSPLineW3D(gdl, ...) \ + gD_(gdl, gsSPLineW3D, __VA_ARGS__) +#define gSPLoadUcode(gdl, ...) \ + gD_(gdl, gsSPLoadUcode, __VA_ARGS__) +#define gSPLoadUcodeL(gdl, ...) \ + gD_(gdl, gsSPLoadUcodeL, __VA_ARGS__) +#define gSPLookAtX(gdl, ...) \ + gD_(gdl, gsSPLookAtX, __VA_ARGS__) +#define gSPLookAtY(gdl, ...) \ + gD_(gdl, gsSPLookAtY, __VA_ARGS__) +#define gSPLookAt(gdl, ...) \ + gD_(gdl, gsSPLookAt, __VA_ARGS__) +#define gSPMatrix(gdl, ...) \ + gD_(gdl, gsSPMatrix, __VA_ARGS__) +#define gSPModifyVertex(gdl, ...) \ + gD_(gdl, gsSPModifyVertex, __VA_ARGS__) +#define gSPPerspNormalize(gdl, ...) \ + gD_(gdl, gsSPPerspNormalize, __VA_ARGS__) +#define gSPPopMatrix(gdl, ...) \ + gD_(gdl, gsSPPopMatrix, __VA_ARGS__) +#if defined(F3DEX_GBI_2) +# define gSPPopMatrixN(gdl, ...) \ + gD_(gdl, gsSPPopMatrixN, __VA_ARGS__) +#endif +#define gSPSegment(gdl, ...) \ + gD_(gdl, gsSPSegment, __VA_ARGS__) +#define gSPSetLights0(gdl, ...) \ + gD_(gdl, gsSPSetLights0, __VA_ARGS__) +#define gSPSetLights1(gdl, ...) \ + gD_(gdl, gsSPSetLights1, __VA_ARGS__) +#define gSPSetLights2(gdl, ...) \ + gD_(gdl, gsSPSetLights2, __VA_ARGS__) +#define gSPSetLights3(gdl, ...) \ + gD_(gdl, gsSPSetLights3, __VA_ARGS__) +#define gSPSetLights4(gdl, ...) \ + gD_(gdl, gsSPSetLights4, __VA_ARGS__) +#define gSPSetLights5(gdl, ...) \ + gD_(gdl, gsSPSetLights5, __VA_ARGS__) +#define gSPSetLights6(gdl, ...) \ + gD_(gdl, gsSPSetLights6, __VA_ARGS__) +#define gSPSetLights7(gdl, ...) \ + gD_(gdl, gsSPSetLights7, __VA_ARGS__) +#define gSPSetStatus(gdl, ...) \ + gD_(gdl, gsSPSetStatus, __VA_ARGS__) +#define gSPNumLights(gdl, ...) \ + gD_(gdl, gsSPNumLights, __VA_ARGS__) +#define gSPLight(gdl, ...) \ + gD_(gdl, gsSPLight, __VA_ARGS__) +#define gSPLightColor(gdl, ...) \ + gD_(gdl, gsSPLightColor, __VA_ARGS__) +#define gSPTexture(gdl, ...) \ + gD_(gdl, gsSPTexture, __VA_ARGS__) +#define gSPTextureRectangle(gdl, ...) \ + gD_(gdl, gsSPTextureRectangle, __VA_ARGS__) +#define gSPScisTextureRectangle(gdl, ...) \ + gD_(gdl, gsSPScisTextureRectangle, __VA_ARGS__) +#define gSPTextureRectangleFlip(gdl, ...) \ + gD_(gdl, gsSPTextureRectangleFlip, __VA_ARGS__) +#define gSPScisTextureRectangleFlip(gdl, ...) \ + gD_(gdl, gsSPScisTextureRectangleFlip, __VA_ARGS__) +#define gSPVertex(gdl, ...) \ + gD_(gdl, gsSPVertex, __VA_ARGS__) +#define gSPViewport(gdl, ...) \ + gD_(gdl, gsSPViewport, __VA_ARGS__) +#define gSPBgRectCopy(gdl, ...) \ + gD_(gdl, gsSPBgRectCopy, __VA_ARGS__) +#define gSPBgRect1Cyc(gdl, ...) \ + gD_(gdl, gsSPBgRect1Cyc, __VA_ARGS__) +#define gSPObjRectangle(gdl, ...) \ + gD_(gdl, gsSPObjRectangle, __VA_ARGS__) +#define gSPObjRectangleR(gdl, ...) \ + gD_(gdl, gsSPObjRectangleR, __VA_ARGS__) +#define gSPObjSprite(gdl, ...) \ + gD_(gdl, gsSPObjSprite, __VA_ARGS__) +#define gSPObjMatrix(gdl, ...) \ + gD_(gdl, gsSPObjMatrix, __VA_ARGS__) +#define gSPObjSubMatrix(gdl, ...) \ + gD_(gdl, gsSPObjSubMatrix, __VA_ARGS__) +#define gSPObjRenderMode(gdl, ...) \ + gD_(gdl, gsSPObjRenderMode, __VA_ARGS__) +#define gSPObjLoadTxtr(gdl, ...) \ + gD_(gdl, gsSPObjLoadTxtr, __VA_ARGS__) +#define gSPObjLoadTxRect(gdl, ...) \ + gD_(gdl, gsSPObjLoadTxRect, __VA_ARGS__) +#define gSPObjLoadTxRectR(gdl, ...) \ + gD_(gdl, gsSPObjLoadTxRectR, __VA_ARGS__) +#define gSPObjLoadTxSprite(gdl, ...) \ + gD_(gdl, gsSPObjLoadTxSprite, __VA_ARGS__) +#define gSPSelectDL(gdl, ...) \ + gD_(gdl, gsSPSelectDL, __VA_ARGS__) +#define gSPSelectBranchDL(gdl, ...) \ + gD_(gdl, gsSPSelectBranchDL, __VA_ARGS__) +#define gDPLoadTLUTCmd(gdl, ...) \ + gD_(gdl, gsDPLoadTLUTCmd, __VA_ARGS__) +#define gDPLoadTLUT(gdl, ...) \ + gD_(gdl, gsDPLoadTLUT, __VA_ARGS__) +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +# define gBranchZ(gdl, ...) \ + gD_(gdl, gsBranchZ, __VA_ARGS__) +#endif +#define gDisplayList(gdl, ...) \ + gD_(gdl, gsDisplayList, __VA_ARGS__) +#define gDPHalf1(gdl, ...) \ + gD_(gdl, gsDPHalf1, __VA_ARGS__) +#define gDPHalf2(gdl, ...) \ + gD_(gdl, gsDPHalf2, __VA_ARGS__) +#define gDPLoadTile(gdl, ...) \ + gD_(gdl, gsDPLoadTile, __VA_ARGS__) +#define gDPSetCombine(gdl, ...) \ + gD_(gdl, gsDPSetCombine, __VA_ARGS__) +#if defined(F3DEX_GBI_2) +# define gSPGeometryMode(gdl, ...) \ + gD_(gdl, gsSPGeometryMode, __VA_ARGS__) +#endif +#define gSPSetOtherMode(gdl, ...) \ + gD_(gdl, gsSPSetOtherMode, __VA_ARGS__) +#define gSPSetOtherModeLo(gdl, ...) \ + gD_(gdl, gsSPSetOtherModeLo, __VA_ARGS__) +#define gSPSetOtherModeHi(gdl, ...) \ + gD_(gdl, gsSPSetOtherModeHi, __VA_ARGS__) +#define gDPSetOtherMode(gdl, ...) \ + gD_(gdl, gsDPSetOtherMode, __VA_ARGS__) +#define gMoveWd(gdl, ...) \ + gD_(gdl, gsMoveWd, __VA_ARGS__) +#define gMoveMem(gdl, ...) \ + gD_(gdl, gsMoveMem, __VA_ARGS__) +#if defined(F3DEX_GBI_2) +# define gSPDma_io(gdl, ...) \ + gD_(gdl, gsSPDma_io, __VA_ARGS__) +# define gSPDmaRead(gdl, ...) \ + gD_(gdl, gsSPDmaRead, __VA_ARGS__) +# define gSPDmaWrite(gdl, ...) \ + gD_(gdl, gsSPDmaWrite, __VA_ARGS__) +#endif +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +# define gLoadUcode(gdl, ...) \ + gD_(gdl, gsLoadUcode, __VA_ARGS__) +# define gSPLoadUcodeEx(gdl, ...) \ + gD_(gdl, gsSPLoadUcodeEx, __VA_ARGS__) +#endif +#define gTexRect(gdl, ...) \ + gD_(gdl, gsTexRect, __VA_ARGS__) +#define gTexRectFlip(gdl, ...) \ + gD_(gdl, gsTexRectFlip, __VA_ARGS__) +#define gSPNoOp(gdl) \ + gDisplayListPut(gdl, gsSPNoOp()) +#define gDPWord(gdl, ...) \ + gD_(gdl, gsDPWord, __VA_ARGS__) +#if defined(F3DEX_GBI_2) +# define gSpecial3(gdl, ...) \ + gD_(gdl, gsSpecial3, __VA_ARGS__) +# define gSpecial2(gdl, ...) \ + gD_(gdl, gsSpecial2, __VA_ARGS__) +# define gSpecial1(gdl, ...) \ + gD_(gdl, gsSpecial1, __VA_ARGS__) +#endif + +/* data types and structures */ +typedef uint8_t qu08_t; +typedef uint16_t qu016_t; +typedef int16_t qs48_t; +typedef int16_t qs510_t; +typedef uint16_t qu510_t; +typedef int16_t qs102_t; +typedef uint16_t qu102_t; +typedef int16_t qs105_t; +typedef uint16_t qu105_t; +typedef int16_t qs132_t; +typedef int16_t qs142_t; +typedef int32_t qs1516_t; +typedef int32_t qs1616_t; +typedef int32_t qs205_t; + +typedef uint16_t g_bglt_t; +typedef uint8_t g_ifmt_t; +typedef uint8_t g_isiz_t; +typedef uint16_t g_bgf_t; +typedef uint8_t g_objf_t; +typedef uint32_t g_objlt_t; + +typedef struct +{ + _Alignas(8) + uint32_t hi; + uint32_t lo; +} Gfx; + +typedef struct +{ + int32_t x1; + int32_t y1; + int32_t x2; + int32_t y2; +} Hilite_t; + +typedef union +{ + _Alignas(8) + Hilite_t h; +} Hilite; + +typedef int32_t Mtx_t[4][4]; + +typedef union +{ + _Alignas(8) + Mtx_t m; + int32_t l[16]; + struct + { + int16_t i[16]; + uint16_t f[16]; + }; +} Mtx; + +typedef struct +{ + uint8_t col[3]; + char pad1; + uint8_t colc[3]; + char pad2; + int8_t dir[3]; + char pad3; +} Light_t; + +typedef union +{ + _Alignas(8) + Light_t l; +} Light; + +typedef struct +{ + Light l[2]; +} LookAt; + +typedef struct +{ + uint8_t col[3]; + char pad1; + uint8_t colc[3]; + char pad2; +} Ambient_t; + +typedef union +{ + _Alignas(8) + Ambient_t l; +} Ambient; + +typedef struct +{ + Ambient a; + Light l[1]; +} Lights0, Lights1; + +typedef struct +{ + Ambient a; + Light l[2]; +} Lights2; + +typedef struct +{ + Ambient a; + Light l[3]; +} Lights3; + +typedef struct +{ + Ambient a; + Light l[4]; +} Lights4; + +typedef struct +{ + Ambient a; + Light l[5]; +} Lights5; + +typedef struct +{ + Ambient a; + Light l[6]; +} Lights6; + +typedef struct +{ + Ambient a; + Light l[7]; +} Lightsn, Lights7; + +typedef struct +{ + int16_t ob[3]; + uint16_t flag; + qs105_t tc[2]; + uint8_t cn[4]; +} Vtx_t; + +typedef struct +{ + int16_t ob[3]; + uint16_t flag; + qs105_t tc[2]; + int8_t n[3]; + uint8_t a; +} Vtx_tn; + +typedef union +{ + _Alignas(8) + Vtx_t v; + Vtx_tn n; +} Vtx; + +typedef struct +{ + qs142_t vscale[4]; + qs142_t vtrans[4]; +} Vp_t; + +typedef union +{ + _Alignas(8) + Vp_t vp; +} Vp; + +typedef struct +{ + qs1516_t A; + qs1516_t B; + qs1516_t C; + qs1516_t D; + qs102_t X; + qs102_t Y; + qu510_t BaseScaleX; + qu510_t BaseScaleY; +} uObjMtx_t; + +typedef union +{ + _Alignas(8) + uObjMtx_t m; +} uObjMtx; + +typedef struct +{ + qs102_t X; + qs102_t Y; + qu510_t BaseScaleX; + qu510_t BaseScaleY; +} uObjSubMtx_t; + +typedef union +{ + _Alignas(8) + uObjSubMtx_t m; +} uObjSubMtx; + +typedef struct +{ + qu105_t imageX; + qu102_t imageW; + qs102_t frameX; + qu102_t frameW; + qu105_t imageY; + qu102_t imageH; + qs102_t frameY; + qu102_t frameH; + uint64_t * imagePtr; + g_bglt_t imageLoad; + g_ifmt_t imageFmt; + g_isiz_t imageSiz; + uint16_t imagePal; + g_bgf_t imageFlip; + uint16_t tmemW; + qs132_t tmemH; + uint16_t tmemLoadSH; + uint16_t tmemLoadTH; + uint16_t tmemSizeW; + uint16_t tmemSize; +} uObjBg_t; + +typedef struct +{ + qu105_t imageX; + qu102_t imageW; + qs102_t frameX; + qu102_t frameW; + qu105_t imageY; + qu102_t imageH; + qs102_t frameY; + qu102_t frameH; + uint64_t * imagePtr; + g_bglt_t imageLoad; + g_ifmt_t imageFmt; + g_isiz_t imageSiz; + uint16_t imagePal; + g_bgf_t imageFlip; + qu510_t scaleW; + qu510_t scaleH; + qs205_t imageYorig; + char padding[4]; +} uObjScaleBg_t; + +typedef union +{ + _Alignas(8) + uObjBg_t b; + uObjScaleBg_t s; +} uObjBg; + +typedef struct +{ + qs102_t objX; + qu510_t scaleW; + qu105_t imageW; + uint16_t paddingX; + qs102_t objY; + qu510_t scaleH; + qu105_t imageH; + uint16_t paddingY; + uint16_t imageStride; + uint16_t imageAdrs; + g_ifmt_t imageFmt; + g_isiz_t imageSiz; + uint16_t imagePal; + g_objf_t imageFlags; +} uObjSprite_t; + +typedef union +{ + _Alignas(8) + uObjSprite_t s; +} uObjSprite; + +typedef struct +{ + g_objlt_t type; + uint64_t * image; + uint16_t tmem; + uint16_t tsize; + uint16_t tline; + uint16_t sid; + uint32_t flag; + uint32_t mask; +} uObjTxtrBlock_t; + +typedef struct +{ + g_objlt_t type; + uint64_t * image; + uint16_t tmem; + uint16_t twidth; + uint16_t theight; + uint16_t sid; + uint32_t flag; + uint32_t mask; +} uObjTxtrTile_t; + +typedef struct +{ + g_objlt_t type; + uint64_t * image; + uint16_t phead; + uint16_t pnum; + uint16_t zero; + uint16_t sid; + uint32_t flag; + uint32_t mask; +} uObjTxtrTLUT_t; + +typedef union +{ + _Alignas(8) + uObjTxtrBlock_t block; + uObjTxtrTile_t tile; + uObjTxtrTLUT_t tlut; +} uObjTxtr; + +typedef struct +{ + uObjTxtr txtr; + uObjSprite sprite; +} uObjTxSprite; + +/* rectangle scissoring macros */ +#define gScC_(c) ((c) < 0 ? 0 : (c)) +#define gScD_(t, c, d) \ + ( \ + (c) < 0 ? \ + ( \ + (d) < 0 ? \ + (t) + (c) * (d) / 0x80 : \ + (t) - (c) * (d) / 0x80 \ + ) : \ + (t) \ + ) + +/* texture loading helper macros */ +#define G_SIZ_LDSIZ(siz) ((siz) < G_IM_SIZ_16b ? G_IM_SIZ_16b : (siz)) +#define G_SIZ_BITS(siz) (4 << gI_(siz)) +#define G_SIZ_LDBITS(siz) ((siz) < G_IM_SIZ_16b ? G_SIZ_BITS(siz) : 16) +#define G_DXT(siz, width) \ + ( \ + (width) * G_SIZ_BITS(siz) > 64 ? \ + ((1 << 11) + (width) * G_SIZ_BITS(siz) / 64 - 1) / \ + ((width) * G_SIZ_BITS(siz) / 64) : \ + (1 << 11) \ + ) +#define G_LTB_LRS(width, height, siz) \ + ( \ + (((width) * (height) + 1) * G_SIZ_BITS(siz) - 1) / \ + G_SIZ_BITS(G_SIZ_LDSIZ(siz)) - 1 \ + ) +#define G_LDBLK_TXL(txl) \ + ( \ + (txl) > G_TX_LDBLK_MAX_TXL ? \ + G_TX_LDBLK_MAX_TXL : \ + (txl) \ + ) + +/* depth value macros */ +#define gZp_(zval, near, far) \ + ( \ + (1.f - (float)(near) / (float)(zval)) / \ + (1.f - (float)(near) / (float)(far)) \ + ) +#define gZo_(zval, near, far) \ + ( \ + ((float)(zval) - (float)(near)) / \ + ((float)(far) - (float)(near)) \ + ) +#define gZf_(zval, near, far, flag) \ + qs1616 \ + ( \ + (flag) == G_BZ_PERSP ? \ + gZp_(zval, near, far) : \ + gZo_(zval, near, far) \ + ) +#define G_DEPTOZSrg(zval, near, far, flag, zmin, zmax) \ + ( \ + gZf_(zval, near, far, flag) * \ + ((int32_t)((zmax) - (zmin)) & ~(int32_t)1) + \ + qs1616(zmin) \ + ) +#define G_DEPTOZS(zval, near, far, flag) \ + G_DEPTOZSrg(zval, near, far, flag, 0, G_MAXZ) + +/* vertex ordering macros */ +#define gV2_(v0, v1, flag) \ + ( \ + (flag) == 0 ? gI_(v0) : \ + gI_(v1) \ + ) +#define gV3_(v0, v1, v2, flag) \ + ( \ + (flag) == 0 ? gI_(v0) : \ + (flag) == 1 ? gI_(v1) : \ + gI_(v2) \ + ) +#define gV4_(v0, v1, v2, v3, flag) \ + ( \ + (flag) == 0 ? gI_(v0) : \ + (flag) == 1 ? gI_(v1) : \ + (flag) == 2 ? gI_(v2) : \ + gI_(v3) \ + ) + +/* sprite texture parameter macros */ +#define GS_PIX2TMEM(pix, siz) ((pix) * G_SIZ_BITS(siz) / 64) +#define GS_TB_TSIZE(pix, siz) (GS_PIX2TMEM(pix, siz) - 1) +#define GS_TB_TLINE(pix, siz) (((1 << 11) - 1) / GS_PIX2TMEM(pix, siz) + 1) +#define GS_TT_TWIDTH(pix, siz) (GS_PIX2TMEM(pix, siz) * 4 - 1) +#define GS_TT_THEIGHT(pix, siz) ((pix) * 4 - 1) +#define GS_PAL_HEAD(head) ((head) + 256) +#define GS_PAL_NUM(num) ((num) - 1) + +/* fixed-point conversion macros */ +#define qu08(n) ((qu08_t)((n) * 0x100)) +#define qu016(n) ((qu016_t)((n) * 0x10000)) +#define qs48(n) ((qs48_t)((n) * 0x0100)) +#define qs510(n) ((qs510_t)((n) * 0x0400)) +#define qu510(n) ((qu510_t)((n) * 0x0400)) +#define qs102(n) ((qs102_t)((n) * 0x0004)) +#define qu102(n) ((qu102_t)((n) * 0x0004)) +#define qs105(n) ((qs105_t)((n) * 0x0020)) +#define qu105(n) ((qu105_t)((n) * 0x0020)) +#define qs132(n) ((qs132_t)((n) * 0x0004)) +#define qs142(n) ((qs142_t)((n) * 0x0004)) +#define qs1516(n) ((qs1516_t)((n) * 0x00010000)) +#define qs1616(n) ((qs1616_t)((n) * 0x00010000)) +#define qs205(n) ((qs205_t)((n) * 0x00000020)) + +/* private helper macros */ +#define gI_(i) ((uint32_t)(i)) +#define gL_(l) ((uint64_t)(l)) +#define gF_(i, n, s) ((gI_(i) & ((gI_(1) << (n)) - 1)) << (s)) +#define gFL_(l, n, s) ((gL_(l) & ((gL_(1) << (n)) - 1)) << (s)) +#define gO_(opc, hi, lo) ((Gfx){gF_(opc, 8, 24) | gI_(hi), gI_(lo)}) +#define gD_(gdl, m, ...) gDisplayListPut(gdl, m(__VA_ARGS__)) + +#endif diff --git a/ZAPDTR/lib/libgfxd/gfxd.c b/ZAPDTR/lib/libgfxd/gfxd.c new file mode 100644 index 000000000..76d7ded8a --- /dev/null +++ b/ZAPDTR/lib/libgfxd/gfxd.c @@ -0,0 +1,863 @@ +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +# define read _read +# define write _write +#else +# include +#endif +#include "gbi.h" +#include "gfxd.h" +#include "priv.h" + +static TLOCAL struct gfxd_state state; + +static int buffer_input_fn(void *buf, int count) +{ + if (count > config.input_buf_size) + count = config.input_buf_size; + memcpy(buf, config.input_buf, count); + config.input_buf += count; + config.input_buf_size -= count; + return count; +} + +static int buffer_output_fn(const char *buf, int count) +{ + if (count > config.output_buf_size) + count = config.output_buf_size; + memcpy(config.output_buf, buf, count); + config.output_buf += count; + config.output_buf_size -= count; + return count; +} + +static int fd_input_fn(void *buf, int count) +{ + return read(config.input_fd, buf, count); +} + +static int fd_output_fn(const char *buf, int count) +{ + return write(config.output_fd, buf, count); +} + +static void swap_words(Gfx *gfx) +{ + uint8_t b[8]; + uint8_t *pw = (void *) gfx; + uint8_t *pb = b; + + int endian = config.endian; + int wordsize = config.wordsize; + + for (int i = 0; i < 8 / wordsize; i++) + { + if (endian == gfxd_endian_host) + { + switch (wordsize) + { + case 1: + { + uint8_t w = *(uint8_t *) pw; + *pb++ = w >> 0; + break; + } + case 2: + { + uint16_t w = *(uint16_t *) pw; + *pb++ = w >> 8; + *pb++ = w >> 0; + break; + } + case 4: + { + uint32_t w = *(uint32_t *) pw; + *pb++ = w >> 24; + *pb++ = w >> 16; + *pb++ = w >> 8; + *pb++ = w >> 0; + break; + } + case 8: + { + uint64_t w = *(uint64_t *) pw; + *pb++ = w >> 56; + *pb++ = w >> 48; + *pb++ = w >> 40; + *pb++ = w >> 32; + *pb++ = w >> 24; + *pb++ = w >> 16; + *pb++ = w >> 8; + *pb++ = w >> 0; + break; + } + } + } + else + { + for (int j = 0; j < wordsize; j++) + { + if (endian == gfxd_endian_little) + *pb++ = pw[wordsize - 1 - j]; + else + *pb++ = pw[j]; + } + } + pw += wordsize; + } + + gfx->hi = ((uint32_t) b[0] << 24) + | ((uint32_t) b[1] << 16) + | ((uint32_t) b[2] << 8) + | ((uint32_t) b[3] << 0); + gfx->lo = ((uint32_t) b[4] << 24) + | ((uint32_t) b[5] << 16) + | ((uint32_t) b[6] << 8) + | ((uint32_t) b[7] << 0); +} + +static void get_more_input(void) +{ + if (state.end_input != 0) + return; + + char *recv_buf = (void *) &state.gfx[0]; + + while (state.n_gfx < sizeof(state.gfx) / sizeof(state.gfx[0])) + { + int n_read = sizeof(state.gfx) - state.n_byte; + n_read = config.input_fn(&recv_buf[state.n_byte], n_read); + if (n_read == 0) + return; + state.n_byte += n_read; + + while (state.n_gfx < state.n_byte / sizeof(Gfx)) + { + Gfx gfx = state.gfx[state.n_gfx]; + gfxd_macro_t *m = &state.macro[state.n_gfx]; + + swap_words(&gfx); + + int ret = config.ucode->disas_fn(m, gfx.hi, gfx.lo); + if (ret != 0 && config.stop_on_invalid != 0) + { + state.end_input = 1; + state.ret = ret; + return; + } + + state.n_gfx++; + } + } +} + +static int32_t typed_arg_i(int type, int idx) +{ + const gfxd_value_t *v = gfxd_value_by_type(type, idx); + if (v != NULL) + return v->i; + else + return -1; +} + +static uint32_t typed_arg_u(int type, int idx) +{ + const gfxd_value_t *v = gfxd_value_by_type(type, idx); + if (v != NULL) + return v->u; + else + return 0; +} + + +TLOCAL struct gfxd_config config = +{ + .ucode = NULL, + .endian = gfxd_endian_big, + .wordsize = 4, + .arg = NULL, + + .stop_on_invalid = 1, + .stop_on_end = 1, + .emit_dec_color = 0, + .emit_q_macro = 0, + .emit_ext_macro = 0, + + .input_buf = NULL, + .input_buf_size = 0, + .input_fn = &buffer_input_fn, + + .output_buf = NULL, + .output_buf_size = 0, + .output_fn = &buffer_output_fn, + + .macro_fn = &gfxd_macro_dflt, + .arg_fn = &gfxd_arg_dflt, + + .tlut_fn = NULL, + .timg_fn = NULL, + .cimg_fn = NULL, + .zimg_fn = NULL, + .dl_fn = NULL, + .mtx_fn = NULL, + .lookat_fn = NULL, + .light_fn = NULL, + .seg_fn = NULL, + .vtx_fn = NULL, + .vp_fn = NULL, + .uctext_fn = NULL, + .ucdata_fn = NULL, + .dram_fn = NULL, +}; + +void gfxd_input_buffer(const void *buf, int size) +{ + config.input_buf = buf; + config.input_buf_size = size; + config.input_fn = &buffer_input_fn; +} + +void gfxd_output_buffer(char *buf, int size) +{ + config.output_buf = buf; + config.output_buf_size = size; + config.output_fn = &buffer_output_fn; +} + +void gfxd_input_fd(int fd) +{ + config.input_fd = fd; + config.input_fn = &fd_input_fn; +} + +void gfxd_output_fd(int fd) +{ + config.output_fd = fd; + config.output_fn = &fd_output_fn; +} + +void gfxd_input_callback(gfxd_input_fn_t *fn) +{ + if (fn != NULL) + config.input_fn = fn; + else + gfxd_input_buffer(NULL, 0); +} + +void gfxd_output_callback(gfxd_output_fn_t *fn) +{ + if (fn != NULL) + config.output_fn = fn; + else + gfxd_output_buffer(NULL, 0); +} + +void gfxd_macro_fn(gfxd_macro_fn_t *fn) +{ + if (fn != NULL) + config.macro_fn = fn; + else + config.macro_fn = gfxd_macro_dflt; +} + +void gfxd_arg_fn(gfxd_arg_fn_t *fn) +{ + if (fn != NULL) + config.arg_fn = fn; + else + config.arg_fn = gfxd_arg_dflt; +} + +int gfxd_write(const void *buf, int count) +{ + return config.output_fn(buf, count); +} + +int gfxd_puts(const char *str) +{ + return gfxd_write(str, strlen(str)); +} + +int gfxd_printf(const char *fmt, ...) +{ + char s[256]; + + va_list arg; + va_start(arg, fmt); + int n = vsnprintf(s, sizeof(s), fmt, arg); + va_end(arg); + + if (n > sizeof(s) - 1) + n = sizeof(s) - 1; + + return gfxd_write(s, n); +} + +int gfxd_print_value(int type, const gfxd_value_t *value) +{ + return config.ucode->arg_tbl[type].fn(value); +} + +int gfxd_macro_dflt(void) +{ + gfxd_macro_t *m = &state.macro[0]; + const gfxd_macro_type_t *t = &config.ucode->macro_tbl[m->id]; + + const char *name = gfxd_macro_name(); + if (name == NULL) + { + if (config.arg != NULL) + { + gfxd_puts(config.arg); + gfxd_puts(" = "); + } + + gfxd_puts("(Gfx){"); + } + else + { + gfxd_puts(name); + gfxd_puts("("); + + if (config.arg != NULL) + { + gfxd_puts(config.arg); + if (t->n_arg != 0) + gfxd_puts(", "); + } + } + + for (int i = 0; i < t->n_arg; i++) + { + if (i != 0) + gfxd_puts(", "); + + config.arg_fn(i); + } + + if (name == NULL) + gfxd_puts("}"); + else + gfxd_puts(")"); + + return 0; +} + +int gfxd_arg_callbacks(int arg_num) +{ + int id = gfxd_macro_id(); + + switch (gfxd_arg_type(arg_num)) + { + case gfxd_Tlut: + { + if (config.tlut_fn != NULL) + { + int32_t num; + if (id == gfxd_DPLoadTLUT_pal16) + num = 16; + else if (id == gfxd_DPLoadTLUT_pal256) + num = 256; + else + num = typed_arg_i(gfxd_Num, 0); + return config.tlut_fn( + typed_arg_u(gfxd_Tlut, 0), + typed_arg_i(gfxd_Pal, 0), + num); + } + break; + } + case gfxd_Timg: + { + if (config.timg_fn != NULL) + { + int32_t siz = typed_arg_i(gfxd_Siz, 0); + if (siz == -1) + siz = G_IM_SIZ_4b; + return config.timg_fn( + typed_arg_u(gfxd_Timg, 0), + typed_arg_i(gfxd_Fmt, 0), + siz, + typed_arg_i(gfxd_Dim, 0), + typed_arg_i(gfxd_Dim, 1), + typed_arg_i(gfxd_Pal, 0)); + } + break; + } + case gfxd_Cimg: + { + if (config.cimg_fn != NULL) + { + return config.cimg_fn( + typed_arg_u(gfxd_Cimg, 0), + typed_arg_i(gfxd_Fmt, 0), + typed_arg_i(gfxd_Siz, 0), + typed_arg_i(gfxd_Dim, 0)); + } + break; + } + case gfxd_Zimg: + { + if (config.zimg_fn != NULL) + { + return config.zimg_fn( + typed_arg_u(gfxd_Zimg, 0)); + } + break; + } + case gfxd_Dl: + { + if (config.dl_fn != NULL) + { + return config.dl_fn( + typed_arg_u(gfxd_Dl, 0)); + } + break; + } + case gfxd_Mtxptr: + { + if (config.mtx_fn != NULL) + { + return config.mtx_fn( + typed_arg_u(gfxd_Mtxptr, 0)); + } + break; + } + case gfxd_Lookatptr: + { + if (config.lookat_fn != NULL) + { + int32_t num; + if (id == gfxd_SPLookAt) + num = 2; + else + num = 1; + return config.lookat_fn( + typed_arg_u(gfxd_Lookatptr, 0), + num); + } + break; + } + case gfxd_Lightptr: + { + if (config.light_fn != NULL) + { + int32_t num; + if (id == gfxd_SPSetLights1) + num = 1; + else if (id == gfxd_SPSetLights2) + num = 2; + else if (id == gfxd_SPSetLights3) + num = 3; + else if (id == gfxd_SPSetLights4) + num = 4; + else if (id == gfxd_SPSetLights5) + num = 5; + else if (id == gfxd_SPSetLights6) + num = 6; + else if (id == gfxd_SPSetLights7) + num = 7; + else + num = 1; + return config.light_fn( + typed_arg_u(gfxd_Lightptr, 0), + num); + } + break; + + } + case gfxd_Segptr: + { + if (config.seg_fn != NULL) + { + return config.seg_fn( + typed_arg_u(gfxd_Segptr, 0), + typed_arg_i(gfxd_Seg, 0)); + } + break; + } + case gfxd_Vtxptr: + { + if (config.vtx_fn != NULL) + { + return config.vtx_fn( + typed_arg_u(gfxd_Vtxptr, 0), + typed_arg_i(gfxd_Num, 0)); + } + break; + } + case gfxd_Vpptr: + { + if (config.vp_fn != NULL) + { + return config.vp_fn( + typed_arg_u(gfxd_Vpptr, 0)); + } + break; + } + case gfxd_Uctext: + { + if (config.uctext_fn != NULL) + { + return config.uctext_fn( + typed_arg_u(gfxd_Uctext, 0), + 0x1000); + } + break; + } + case gfxd_Ucdata: + { + if (config.ucdata_fn != NULL) + { + uint32_t size; + if (id == gfxd_SPLoadUcodeEx) + size = typed_arg_u(gfxd_Size, 0); + else + size = 0x800; + return config.ucdata_fn( + typed_arg_u(gfxd_Ucdata, 0), + size); + } + break; + } + case gfxd_Dram: + { + if (config.dram_fn != NULL) + { + return config.dram_fn( + typed_arg_u(gfxd_Dram, 0), + typed_arg_u(gfxd_Size, 0)); + } + break; + } + } + + return 0; +} + +void gfxd_arg_dflt(int arg_num) +{ + if (gfxd_arg_callbacks(arg_num) == 0) + { + gfxd_arg_t *a = &state.macro[0].arg[arg_num]; + + gfxd_print_value(a->type, &a->value); + } +} + +void gfxd_tlut_callback(gfxd_tlut_fn_t *fn) +{ + config.tlut_fn = fn; +} + +void gfxd_timg_callback(gfxd_timg_fn_t *fn) +{ + config.timg_fn = fn; +} + +void gfxd_cimg_callback(gfxd_cimg_fn_t *fn) +{ + config.cimg_fn = fn; +} + +void gfxd_zimg_callback(gfxd_zimg_fn_t *fn) +{ + config.zimg_fn = fn; +} + +void gfxd_dl_callback(gfxd_dl_fn_t *fn) +{ + config.dl_fn = fn; +} + +void gfxd_mtx_callback(gfxd_mtx_fn_t *fn) +{ + config.mtx_fn = fn; +} + +void gfxd_lookat_callback(gfxd_lookat_fn_t *fn) +{ + config.lookat_fn = fn; +} + +void gfxd_light_callback(gfxd_light_fn_t *fn) +{ + config.light_fn = fn; +} + +void gfxd_seg_callback(gfxd_seg_fn_t *fn) +{ + config.seg_fn = fn; +} + +void gfxd_vtx_callback(gfxd_vtx_fn_t *fn) +{ + config.vtx_fn = fn; +} + +void gfxd_vp_callback(gfxd_vp_fn_t *fn) +{ + config.vp_fn = fn; +} + +void gfxd_uctext_callback(gfxd_uctext_fn_t *fn) +{ + config.uctext_fn = fn; +} + +void gfxd_ucdata_callback(gfxd_ucdata_fn_t *fn) +{ + config.ucdata_fn = fn; +} + +void gfxd_dram_callback(gfxd_dram_fn_t *fn) +{ + config.dram_fn = fn; +} + +void gfxd_target(gfxd_ucode_t ucode) +{ + config.ucode = ucode; +} + +void gfxd_endian(int endian, int wordsize) +{ + config.endian = endian; + config.wordsize = wordsize; +} + +void gfxd_dynamic(const char *arg) +{ + config.arg = arg; +} + +void gfxd_enable(int cap) +{ + switch (cap) + { + case gfxd_stop_on_invalid: + config.stop_on_invalid = 1; + break; + + case gfxd_stop_on_end: + config.stop_on_end = 1; + break; + + case gfxd_emit_dec_color: + config.emit_dec_color = 1; + break; + + case gfxd_emit_q_macro: + config.emit_q_macro = 1; + break; + + case gfxd_emit_ext_macro: + config.emit_ext_macro = 1; + break; + } +} + +void gfxd_disable(int cap) +{ + switch (cap) + { + case gfxd_stop_on_invalid: + config.stop_on_invalid = 0; + return; + + case gfxd_stop_on_end: + config.stop_on_end = 0; + return; + + case gfxd_emit_dec_color: + config.emit_dec_color = 0; + break; + + case gfxd_emit_q_macro: + config.emit_q_macro = 0; + break; + + case gfxd_emit_ext_macro: + config.emit_ext_macro = 0; + break; + } +} + +void gfxd_udata_set(void *ptr) +{ + config.udata = ptr; +} + +void *gfxd_udata_get(void) +{ + return config.udata; +} + +int gfxd_execute(void) +{ + state.macro_offset = 0; + state.n_byte = 0; + state.n_gfx = 0; + state.end_input = 0; + state.ret = 0; + + for (;;) + { + get_more_input(); + if (state.n_gfx == 0) + break; + + gfxd_macro_t *m = &state.macro[0]; + config.ucode->combine_fn(m, state.n_gfx); + + const gfxd_macro_type_t *t = &config.ucode->macro_tbl[m->id]; + if (t->ext != 0 && config.emit_ext_macro == 0) + { + Gfx gfx = state.gfx[0]; + swap_words(&gfx); + + t = &config.ucode->macro_tbl[gfxd_Invalid]; + t->disas_fn(m, gfx.hi, gfx.lo); + } + + int ret = config.macro_fn(); + if (ret != 0) + { + state.ret = ret; + break; + } + + if (config.stop_on_end != 0 + && (m->id == gfxd_SPBranchList + || m->id == gfxd_SPEndDisplayList)) + { + break; + } + + int n_pop = config.ucode->macro_tbl[m->id].n_gfx; + int n_rem = state.n_gfx - n_pop; + { + int n_byte = n_rem * sizeof(gfxd_macro_t); + memmove(&state.macro[0], &state.macro[n_pop], n_byte); + state.n_gfx = n_rem; + } + { + int n_byte = n_rem * sizeof(Gfx); + memmove(&state.gfx[0], &state.gfx[n_pop], n_byte); + state.n_byte = n_byte; + } + state.macro_offset += n_pop * sizeof(Gfx); + } + + return state.ret; +} + +int gfxd_macro_offset(void) +{ + return state.macro_offset; +} + +int gfxd_macro_packets(void) +{ + return config.ucode->macro_tbl[state.macro[0].id].n_gfx; +} + +const void *gfxd_macro_data(void) +{ + return state.gfx; +} + +int gfxd_macro_id(void) +{ + return state.macro[0].id; +} + +const char *gfxd_macro_name(void) +{ + int id = state.macro[0].id; + const gfxd_macro_type_t *t = &config.ucode->macro_tbl[id]; + + if (t->prefix == NULL && t->suffix == NULL) + { + return NULL; + } + else + { + static TLOCAL char buf[32]; + + char *p = buf; + if (t->prefix != NULL) + { + const char *s = t->prefix; + while (*s != '\0') + *p++ = *s++; + } + *p++ = 'g'; + if (config.arg == NULL) + *p++ = 's'; + if (t->suffix != NULL) + { + const char *s = t->suffix; + while (*s != '\0') + *p++ = *s++; + } + *p++ = '\0'; + + return buf; + } +} + +int gfxd_arg_count(void) +{ + return config.ucode->macro_tbl[state.macro[0].id].n_arg; +} + +int gfxd_arg_type(int arg_num) +{ + return state.macro[0].arg[arg_num].type; +} + +const char *gfxd_arg_name(int arg_num) +{ + return state.macro[0].arg[arg_num].name; +} + +int gfxd_arg_fmt(int arg_num) +{ + return config.ucode->arg_tbl[state.macro[0].arg[arg_num].type].fmt; +} + +const gfxd_value_t *gfxd_arg_value(int arg_num) +{ + return &state.macro[0].arg[arg_num].value; +} + +const gfxd_value_t *gfxd_value_by_type(int type, int idx) +{ + gfxd_macro_t *m = &state.macro[0]; + const gfxd_macro_type_t *t = &config.ucode->macro_tbl[m->id]; + + for (int i = 0; i < t->n_arg; i++) + { + gfxd_arg_t *a = &m->arg[i]; + if (a->type == type) + { + if (idx == 0) + return &a->value; + else + idx--; + } + } + + return NULL; +} + +int gfxd_arg_valid(int arg_num) +{ + return state.macro[0].arg[arg_num].bad == 0; +} diff --git a/ZAPDTR/lib/libgfxd/gfxd.h b/ZAPDTR/lib/libgfxd/gfxd.h new file mode 100644 index 000000000..268bbfa10 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/gfxd.h @@ -0,0 +1,387 @@ +#ifndef GFXD_H +#define GFXD_H +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +enum +{ + gfxd_Word, /* generic word */ + gfxd_Opcode, /* command opcode (G_*) */ + gfxd_Coordi, /* integer coordinate */ + gfxd_Coordq, /* fractional (q10.2) coordinate */ + gfxd_Pal, /* palette index */ + gfxd_Tlut, /* tlut pointer */ + gfxd_Timg, /* texture image pointer */ + gfxd_Tmem, /* tmem address */ + gfxd_Tile, /* tile index */ + gfxd_Fmt, /* texture format */ + gfxd_Siz, /* texture pixel size */ + gfxd_Dim, /* integer dimension (width / height) */ + gfxd_Cm, /* clamp and mirror flags */ + gfxd_Tm, /* tile mask */ + gfxd_Ts, /* tile shift */ + gfxd_Dxt, /* texture dxt */ + gfxd_Tag, /* generic tag */ + gfxd_Pm, /* pipeline mode */ + gfxd_Colorpart, /* color component */ + gfxd_Color, /* color */ + gfxd_Lodfrac, /* lod fraction (q0.8) */ + gfxd_Cimg, /* color image pointer */ + gfxd_Zimg, /* depth image pointer */ + gfxd_Ac, /* alpha compare mode */ + gfxd_Ad, /* alpha dither mode */ + gfxd_Cd, /* color dither mode */ + gfxd_Ccpre, /* color combiner preset index */ + gfxd_Ccmuxa, /* color mux operand (a) */ + gfxd_Ccmuxb, /* color mux operand (b) */ + gfxd_Ccmuxc, /* color mux operand (c) */ + gfxd_Ccmuxd, /* color mux operand (d) */ + gfxd_Acmuxabd, /* alpha mux operand (a, b, or d) */ + gfxd_Acmuxc, /* alpha mux operand (c) */ + gfxd_Cv, /* color convert operand */ + gfxd_Tc, /* texture convert mode */ + gfxd_Cyc, /* cycle type */ + gfxd_Zs, /* depth source mode */ + gfxd_Ck, /* combine key mode */ + gfxd_Keyscale, /* combine key scale */ + gfxd_Keywidth, /* combine key width */ + gfxd_Zi, /* integer depth */ + gfxd_Rm1, /* cycle 1 render mode */ + gfxd_Rm2, /* cycle 2 render mode */ + gfxd_Sc, /* scissor mode */ + gfxd_Td, /* texture detail mode */ + gfxd_Tf, /* texture filter mode */ + gfxd_Tl, /* texture LOD mode */ + gfxd_Tt, /* textuure LUT mode */ + gfxd_Tp, /* texture perspective mode */ + gfxd_Line, /* texture line size */ + gfxd_Vtx, /* vertex index */ + gfxd_Vtxflag, /* vertex flag */ + gfxd_Dl, /* display list pointer */ + gfxd_Zraw, /* raw depth value (q16.16) */ + gfxd_Dlflag, /* display list flag */ + gfxd_Cr, /* clip ratio */ + gfxd_Num, /* element count */ + gfxd_Fogz, /* fog factor */ + gfxd_Fogp, /* fog position (0 - 1000) */ + gfxd_Mtxptr, /* matrix pointer */ + gfxd_Gm, /* geometry mode */ + gfxd_Mwo_matrix, /* matrix moveword offset */ + gfxd_Linewd, /* line width (1.5 + q7.1) */ + gfxd_Uctext, /* microcode text pointer */ + gfxd_Ucdata, /* microcode data pointer */ + gfxd_Size, /* data size */ + gfxd_Lookatptr, /* lookat pointer */ + gfxd_Mtxparam, /* matrix param */ + gfxd_Mtxstack, /* matrix param (stack select only) */ + gfxd_Mwo_point, /* vertex moveword offset */ + gfxd_Wscale, /* w-component scale (perspnorm) */ + gfxd_Seg, /* segment number */ + gfxd_Segptr, /* segment pointer */ + gfxd_Lightsn, /* dereferenced Lighstn pointer */ + gfxd_Numlights, /* light count (NUMLIGHTS_*) */ + gfxd_Lightnum, /* light number (LIGHT_*) */ + gfxd_Lightptr, /* light pointer */ + gfxd_Tcscale, /* texture coordinate scale */ + gfxd_Switch, /* on-off value */ + gfxd_St, /* vertex coordinate (q10.5) */ + gfxd_Stdelta, /* vertex coordinate delta (q5.10) */ + gfxd_Vtxptr, /* vertex pointer */ + gfxd_Vpptr, /* viewport pointer */ + gfxd_Dram, /* generic dram address */ + gfxd_Sftlo, /* othermode lo shift */ + gfxd_Othermodelo, /* othermode lo value */ + gfxd_Sfthi, /* othermode hi shift */ + gfxd_Othermodehi, /* othermode hi value */ + gfxd_Mw, /* moveword index */ + gfxd_Mwo, /* moveword offset */ + gfxd_Mwo_clip, /* clip ratio moveword offset */ + gfxd_Mwo_lightcol, /* light color moveword offset */ + gfxd_Mv, /* movemem index */ + gfxd_Mvo, /* movemem offset */ + gfxd_Dmem, /* dmem address */ + gfxd_Dmaflag, /* dma io flag */ +}; + +enum +{ + gfxd_Invalid, + gfxd_DPFillRectangle, + gfxd_DPFullSync, + gfxd_DPLoadSync, + gfxd_DPTileSync, + gfxd_DPPipeSync, + gfxd_DPLoadTLUT_pal16, + gfxd_DPLoadTLUT_pal256, + gfxd_DPLoadMultiBlockYuvS, + gfxd_DPLoadMultiBlockYuv, + gfxd_DPLoadMultiBlock_4bS, + gfxd_DPLoadMultiBlock_4b, + gfxd_DPLoadMultiBlockS, + gfxd_DPLoadMultiBlock, + gfxd__DPLoadTextureBlockYuvS, + gfxd__DPLoadTextureBlockYuv, + gfxd__DPLoadTextureBlock_4bS, + gfxd__DPLoadTextureBlock_4b, + gfxd__DPLoadTextureBlockS, + gfxd__DPLoadTextureBlock, + gfxd_DPLoadTextureBlockYuvS, + gfxd_DPLoadTextureBlockYuv, + gfxd_DPLoadTextureBlock_4bS, + gfxd_DPLoadTextureBlock_4b, + gfxd_DPLoadTextureBlockS, + gfxd_DPLoadTextureBlock, + gfxd_DPLoadMultiTileYuv, + gfxd_DPLoadMultiTile_4b, + gfxd_DPLoadMultiTile, + gfxd__DPLoadTextureTileYuv, + gfxd__DPLoadTextureTile_4b, + gfxd__DPLoadTextureTile, + gfxd_DPLoadTextureTileYuv, + gfxd_DPLoadTextureTile_4b, + gfxd_DPLoadTextureTile, + gfxd_DPLoadBlock, + gfxd_DPNoOp, + gfxd_DPNoOpTag, + gfxd_DPPipelineMode, + gfxd_DPSetBlendColor, + gfxd_DPSetEnvColor, + gfxd_DPSetFillColor, + gfxd_DPSetFogColor, + gfxd_DPSetPrimColor, + gfxd_DPSetColorImage, + gfxd_DPSetDepthImage, + gfxd_DPSetTextureImage, + gfxd_DPSetAlphaCompare, + gfxd_DPSetAlphaDither, + gfxd_DPSetColorDither, + gfxd_DPSetCombineMode, + gfxd_DPSetCombineLERP, + gfxd_DPSetConvert, + gfxd_DPSetTextureConvert, + gfxd_DPSetCycleType, + gfxd_DPSetDepthSource, + gfxd_DPSetCombineKey, + gfxd_DPSetKeyGB, + gfxd_DPSetKeyR, + gfxd_DPSetPrimDepth, + gfxd_DPSetRenderMode, + gfxd_DPSetScissor, + gfxd_DPSetScissorFrac, + gfxd_DPSetTextureDetail, + gfxd_DPSetTextureFilter, + gfxd_DPSetTextureLOD, + gfxd_DPSetTextureLUT, + gfxd_DPSetTexturePersp, + gfxd_DPSetTile, + gfxd_DPSetTileSize, + gfxd_SP1Triangle, + gfxd_SP2Triangles, + gfxd_SP1Quadrangle, + gfxd_SPBranchLessZraw, + gfxd_SPBranchList, + gfxd_SPClipRatio, + gfxd_SPCullDisplayList, + gfxd_SPDisplayList, + gfxd_SPEndDisplayList, + gfxd_SPFogFactor, + gfxd_SPFogPosition, + gfxd_SPForceMatrix, + gfxd_SPSetGeometryMode, + gfxd_SPClearGeometryMode, + gfxd_SPLoadGeometryMode, + gfxd_SPInsertMatrix, + gfxd_SPLine3D, + gfxd_SPLineW3D, + gfxd_SPLoadUcode, + gfxd_SPLookAtX, + gfxd_SPLookAtY, + gfxd_SPLookAt, + gfxd_SPMatrix, + gfxd_SPModifyVertex, + gfxd_SPPerspNormalize, + gfxd_SPPopMatrix, + gfxd_SPPopMatrixN, + gfxd_SPSegment, + gfxd_SPSetLights1, + gfxd_SPSetLights2, + gfxd_SPSetLights3, + gfxd_SPSetLights4, + gfxd_SPSetLights5, + gfxd_SPSetLights6, + gfxd_SPSetLights7, + gfxd_SPNumLights, + gfxd_SPLight, + gfxd_SPLightColor, + gfxd_SPTexture, + gfxd_SPTextureRectangle, + gfxd_SPTextureRectangleFlip, + gfxd_SPVertex, + gfxd_SPViewport, + gfxd_DPLoadTLUTCmd, + gfxd_DPLoadTLUT, + gfxd_BranchZ, + gfxd_DisplayList, + gfxd_DPHalf1, + gfxd_DPHalf2, + gfxd_DPWord, + gfxd_DPLoadTile, + gfxd_SPGeometryMode, + gfxd_SPSetOtherMode, + gfxd_SPSetOtherModeLo, + gfxd_SPSetOtherModeHi, + gfxd_DPSetOtherMode, + gfxd_MoveWd, + gfxd_MoveMem, + gfxd_SPDma_io, + gfxd_SPDmaRead, + gfxd_SPDmaWrite, + gfxd_LoadUcode, + gfxd_SPLoadUcodeEx, + gfxd_TexRect, + gfxd_TexRectFlip, + gfxd_SPNoOp, + gfxd_Special3, + gfxd_Special2, + gfxd_Special1, +}; + +enum +{ + gfxd_stop_on_invalid, + gfxd_stop_on_end, + gfxd_emit_dec_color, + gfxd_emit_q_macro, + gfxd_emit_ext_macro, +}; + +enum +{ + gfxd_endian_big, + gfxd_endian_little, + gfxd_endian_host, +}; + +enum +{ + gfxd_argfmt_i, + gfxd_argfmt_u, + gfxd_argfmt_f, +}; + +typedef union +{ + int32_t i; + uint32_t u; + float f; +} gfxd_value_t; + +typedef const struct gfxd_ucode *gfxd_ucode_t; + +typedef int gfxd_input_fn_t(void *buf, int count); +void gfxd_input_buffer(const void *buf, int size); +void gfxd_input_fd(int fd); +void gfxd_input_callback(gfxd_input_fn_t *fn); + +typedef int gfxd_output_fn_t(const char *buf, int count); +void gfxd_output_buffer(char *buf, int size); +void gfxd_output_fd(int fd); +void gfxd_output_callback(gfxd_output_fn_t *fn); + +typedef int gfxd_macro_fn_t(void); +void gfxd_macro_fn(gfxd_macro_fn_t *fn); +gfxd_macro_fn_t gfxd_macro_dflt; + +typedef void gfxd_arg_fn_t(int arg_num); +void gfxd_arg_fn(gfxd_arg_fn_t *fn); +gfxd_arg_fn_t gfxd_arg_dflt; + +typedef int gfxd_tlut_fn_t(uint32_t tlut, int32_t idx, int32_t count); +void gfxd_tlut_callback(gfxd_tlut_fn_t *fn); + +typedef int gfxd_timg_fn_t(uint32_t timg, int32_t fmt, int32_t siz, + int32_t width, int32_t height, int32_t pal); +void gfxd_timg_callback(gfxd_timg_fn_t *fn); + +typedef int gfxd_cimg_fn_t(uint32_t cimg, int32_t fmt, int32_t siz, + int32_t width); +void gfxd_cimg_callback(gfxd_cimg_fn_t *fn); + +typedef int gfxd_zimg_fn_t(uint32_t zimg); +void gfxd_zimg_callback(gfxd_zimg_fn_t *fn); + +typedef int gfxd_dl_fn_t(uint32_t dl); +void gfxd_dl_callback(gfxd_dl_fn_t *fn); + +typedef int gfxd_mtx_fn_t(uint32_t mtx); +void gfxd_mtx_callback(gfxd_mtx_fn_t *fn); + +typedef int gfxd_lookat_fn_t(uint32_t lookat, int32_t count); +void gfxd_lookat_callback(gfxd_lookat_fn_t *fn); + +typedef int gfxd_light_fn_t(uint32_t light, int32_t count); +void gfxd_light_callback(gfxd_light_fn_t *fn); + +typedef int gfxd_seg_fn_t(uint32_t seg, int32_t num); +void gfxd_seg_callback(gfxd_seg_fn_t *fn); + +typedef int gfxd_vtx_fn_t(uint32_t vtx, int32_t num); +void gfxd_vtx_callback(gfxd_vtx_fn_t *fn); + +typedef int gfxd_vp_fn_t(uint32_t vp); +void gfxd_vp_callback(gfxd_vp_fn_t *fn); + +typedef int gfxd_uctext_fn_t(uint32_t text, uint32_t size); +void gfxd_uctext_callback(gfxd_uctext_fn_t *fn); + +typedef int gfxd_ucdata_fn_t(uint32_t data, uint32_t size); +void gfxd_ucdata_callback(gfxd_ucdata_fn_t *fn); + +typedef int gfxd_dram_fn_t(uint32_t dram, uint32_t size); +void gfxd_dram_callback(gfxd_dram_fn_t *fn); + +int gfxd_write(const void *buf, int count); +int gfxd_puts(const char *str); +int gfxd_printf(const char *fmt, ...); +int gfxd_print_value(int type, const gfxd_value_t *value); + +void gfxd_target(gfxd_ucode_t ucode); +void gfxd_endian(int endian, int wordsize); +void gfxd_dynamic(const char *arg); +void gfxd_enable(int cap); +void gfxd_disable(int cap); +void gfxd_udata_set(void *ptr); +void *gfxd_udata_get(void); + +int gfxd_execute(void); + +int gfxd_macro_offset(void); +int gfxd_macro_packets(void); +const void *gfxd_macro_data(void); +int gfxd_macro_id(void); +const char *gfxd_macro_name(void); + +int gfxd_arg_count(void); +int gfxd_arg_type(int arg_num); +const char *gfxd_arg_name(int arg_num); +int gfxd_arg_fmt(int arg_num); +const gfxd_value_t *gfxd_arg_value(int arg_num); +const gfxd_value_t *gfxd_value_by_type(int type, int idx); +int gfxd_arg_valid(int arg_num); +int gfxd_arg_callbacks(int arg_num); + +extern const gfxd_ucode_t gfxd_f3d; +extern const gfxd_ucode_t gfxd_f3db; +extern const gfxd_ucode_t gfxd_f3dex; +extern const gfxd_ucode_t gfxd_f3dexb; +extern const gfxd_ucode_t gfxd_f3dex2; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ZAPDTR/lib/libgfxd/priv.h b/ZAPDTR/lib/libgfxd/priv.h new file mode 100644 index 000000000..37cb66b68 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/priv.h @@ -0,0 +1,123 @@ +#ifndef GFXD_PRIV_H +#define GFXD_PRIV_H +#include "gfxd.h" + +#ifdef CONFIG_MT +# ifdef _MSC_VER +# define TLOCAL __declspec(thread) +# else +# define TLOCAL _Thread_local +# endif +#else +# define TLOCAL +#endif + +#define UCFUNC static inline + +#define config gfxd_config__ + +typedef int gfxd_argfn_t(const gfxd_value_t *v); + +typedef struct +{ + int fmt; + gfxd_argfn_t * fn; +} gfxd_arg_type_t; + +typedef struct +{ + int type; + const char * name; + gfxd_value_t value; + int bad; +} gfxd_arg_t; + +typedef struct +{ + int id; + gfxd_arg_t arg[18]; +} gfxd_macro_t; + +typedef int gfxd_disas_fn_t(gfxd_macro_t *macro, uint32_t hi, uint32_t lo); +typedef int gfxd_combine_fn_t(gfxd_macro_t *macro, int n_macro); + +typedef struct +{ + const char * prefix; + const char * suffix; + int opcode; + int n_arg; + int n_gfx; + gfxd_disas_fn_t * disas_fn; + gfxd_combine_fn_t * combine_fn; + int alias; + int ext; +} gfxd_macro_type_t; + +struct gfxd_ucode +{ + gfxd_disas_fn_t * disas_fn; + gfxd_combine_fn_t * combine_fn; + const gfxd_arg_type_t * arg_tbl; + const gfxd_macro_type_t * macro_tbl; +}; + +struct gfxd_state +{ + int macro_offset; + + Gfx gfx[9]; + int n_byte; + int n_gfx; + gfxd_macro_t macro[9]; + + int end_input; + int ret; +}; + +struct gfxd_config +{ + gfxd_ucode_t ucode; + int endian; + int wordsize; + const char * arg; + void * udata; + + int stop_on_invalid; + int stop_on_end; + int emit_dec_color; + int emit_q_macro; + int emit_ext_macro; + + const char * input_buf; + int input_buf_size; + int input_fd; + gfxd_input_fn_t * input_fn; + + char * output_buf; + int output_buf_size; + int output_fd; + gfxd_output_fn_t * output_fn; + + gfxd_macro_fn_t * macro_fn; + gfxd_arg_fn_t * arg_fn; + + gfxd_tlut_fn_t * tlut_fn; + gfxd_timg_fn_t * timg_fn; + gfxd_cimg_fn_t * cimg_fn; + gfxd_zimg_fn_t * zimg_fn; + gfxd_dl_fn_t * dl_fn; + gfxd_mtx_fn_t * mtx_fn; + gfxd_lookat_fn_t * lookat_fn; + gfxd_light_fn_t * light_fn; + gfxd_seg_fn_t * seg_fn; + gfxd_vtx_fn_t * vtx_fn; + gfxd_vp_fn_t * vp_fn; + gfxd_uctext_fn_t * uctext_fn; + gfxd_ucdata_fn_t * ucdata_fn; + gfxd_dram_fn_t * dram_fn; +}; + +extern TLOCAL struct gfxd_config gfxd_config__; + +#endif diff --git a/ZAPDTR/lib/libgfxd/uc.c b/ZAPDTR/lib/libgfxd/uc.c new file mode 100644 index 000000000..7efb09105 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include "gbi.h" +#include "gfxd.h" +#include "priv.h" + +#include "uc_argfn.c" +#include "uc_argtbl.c" +#include "uc_macrofn.c" +#include "uc_macrotbl.c" + +UCFUNC int disas(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int opcode = (hi >> 24) & 0xFF; + + for (int i = 0; i < sizeof(macro_tbl) / sizeof(macro_tbl[0]); i++) + { + const gfxd_macro_type_t *t = ¯o_tbl[i]; + if (t->disas_fn != NULL && t->opcode == opcode) + return t->disas_fn(m, hi, lo); + } + + return d_Invalid(m, hi, lo); +} + +UCFUNC int combine(gfxd_macro_t *m, int num) +{ + int opcode = macro_tbl[m->id].opcode; + + for (int i = 0; i < sizeof(macro_tbl) / sizeof(macro_tbl[0]); i++) + { + const gfxd_macro_type_t *t = ¯o_tbl[i]; + if (t->combine_fn != NULL + && t->opcode == opcode + && (t->ext == 0 || config.emit_ext_macro != 0)) + { + if (t->combine_fn(m, num) == 0) + return 0; + } + } + + return -1; +} + +static const struct gfxd_ucode uc = +{ + .disas_fn = disas, + .combine_fn = combine, + .arg_tbl = arg_tbl, + .macro_tbl = macro_tbl, +}; + +const gfxd_ucode_t uc_name = &uc; diff --git a/ZAPDTR/lib/libgfxd/uc_argfn.c b/ZAPDTR/lib/libgfxd/uc_argfn.c new file mode 100644 index 000000000..f65feb60f --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_argfn.c @@ -0,0 +1,1814 @@ +#define MDMASK(md) ((((uint32_t)1 << G_MDSIZ_##md) - 1) << G_MDSFT_##md) +#define MDMASK_RM_C1 ((uint32_t)0xCCCC0000) +#define MDMASK_RM_C2 ((uint32_t)0x33330000) +#define MDMASK_RM_LO ((uint32_t)0x0000FFF8) + +UCFUNC int argfn_i(const gfxd_value_t *v) +{ + return gfxd_printf("%" PRIi32, v->i); +} + +UCFUNC int argfn_u(const gfxd_value_t *v) +{ + return gfxd_printf("%" PRIu32, v->u); +} + +UCFUNC int argfn_x8(const gfxd_value_t *v) +{ + return gfxd_printf("0x%02" PRIX32, v->u); +} + +UCFUNC int argfn_x16(const gfxd_value_t *v) +{ + return gfxd_printf("0x%04" PRIX32, v->u); +} + +UCFUNC int argfn_x32(const gfxd_value_t *v) +{ + return gfxd_printf("0x%08" PRIX32, v->u); +} + +UCFUNC int argfn_color(const gfxd_value_t *v) +{ + if (config.emit_dec_color) + return gfxd_printf("%" PRIu32, v->u); + else + return gfxd_printf("0x%02" PRIX32, v->u); +} + +UCFUNC int argfn_qu08(const gfxd_value_t *v) +{ + if (v->u == 0) + return gfxd_puts("0"); + else if (config.emit_q_macro) + return gfxd_printf("qu08(%.16g)", v->u / 256.f); + else + return gfxd_printf("0x%02" PRIX32, v->u); +} + +UCFUNC int argfn_qu016(const gfxd_value_t *v) +{ + if (v->u == 0) + return gfxd_puts("0"); + else if (config.emit_q_macro) + return gfxd_printf("qu016(%.16g)", v->u / 65536.f); + else + return gfxd_printf("0x%04" PRIX32, v->u); +} + +UCFUNC int argfn_qs48(const gfxd_value_t *v) +{ + if (v->i == 0) + return gfxd_puts("0"); + else if (config.emit_q_macro) + return gfxd_printf("qs48(%.16g)", v->i / 256.f); + else + { + if (v->i < 0) + return gfxd_printf("-0x%04" PRIX32, (uint32_t)-v->i); + else + return gfxd_printf("0x%04" PRIX32, (uint32_t)v->i); + } +} + +UCFUNC int argfn_qs510(const gfxd_value_t *v) +{ + if (v->i == 0) + return gfxd_puts("0"); + else if (config.emit_q_macro) + return gfxd_printf("qs510(%.16g)", v->i / 1024.f); + else + { + if (v->i < 0) + return gfxd_printf("-0x%04" PRIX32, (uint32_t)-v->i); + else + return gfxd_printf("0x%04" PRIX32, (uint32_t)v->i); + } +} + +UCFUNC int argfn_qu102(const gfxd_value_t *v) +{ + if (v->u == 0) + return gfxd_puts("0"); + else if (config.emit_q_macro) + return gfxd_printf("qu102(%.16g)", v->u / 4.f); + else + return gfxd_printf("0x%04" PRIX32, v->u); +} + +UCFUNC int argfn_qs105(const gfxd_value_t *v) +{ + if (v->i == 0) + return gfxd_puts("0"); + else if (config.emit_q_macro) + return gfxd_printf("qs105(%.16g)", v->i / 32.f); + else + { + if (v->i < 0) + return gfxd_printf("-0x%04" PRIX32, (uint32_t)-v->i); + else + return gfxd_printf("0x%04" PRIX32, (uint32_t)v->i); + } +} + +UCFUNC int argfn_qs1616(const gfxd_value_t *v) +{ + if (v->i == 0) + return gfxd_puts("0"); + else if (config.emit_q_macro) + return gfxd_printf("qs1616(%.16g)", v->i / 65536.f); + else + { + if (v->i < 0) + return gfxd_printf("-0x%08" PRIX32, (uint32_t)-v->i); + else + return gfxd_printf("0x%08" PRIX32, (uint32_t)v->i); + } +} + +UCFUNC int argfn_opc(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_SPNOOP: + return gfxd_puts("G_SPNOOP"); + case G_MTX: + return gfxd_puts("G_MTX"); + case G_MOVEMEM: + return gfxd_puts("G_MOVEMEM"); + case G_VTX: + return gfxd_puts("G_VTX"); + case G_DL: + return gfxd_puts("G_DL"); + case G_RDPHALF_2: + return gfxd_puts("G_RDPHALF_2"); + case G_RDPHALF_1: + return gfxd_puts("G_RDPHALF_1"); +#if defined(F3D_BETA) && (defined(F3D_GBI) || defined(F3DEX_GBI)) + case G_PERSPNORM: + return gfxd_puts("G_PERSPNORM"); +#endif + case G_LINE3D: + return gfxd_puts("G_LINE3D"); +#if defined(F3D_GBI) || defined(F3DEX_GBI) + case G_CLEARGEOMETRYMODE: + return gfxd_puts("G_CLEARGEOMETRYMODE"); + case G_SETGEOMETRYMODE: + return gfxd_puts("G_SETGEOMETRYMODE"); +#endif + case G_ENDDL: + return gfxd_puts("G_ENDDL"); + case G_SETOTHERMODE_L: + return gfxd_puts("G_SETOTHERMODE_L"); + case G_SETOTHERMODE_H: + return gfxd_puts("G_SETOTHERMODE_H"); + case G_TEXTURE: + return gfxd_puts("G_TEXTURE"); + case G_MOVEWORD: + return gfxd_puts("G_MOVEWORD"); + case G_POPMTX: + return gfxd_puts("G_POPMTX"); + case G_CULLDL: + return gfxd_puts("G_CULLDL"); + case G_TRI1: + return gfxd_puts("G_TRI1"); + case G_NOOP: + return gfxd_puts("G_NOOP"); +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + case G_LOAD_UCODE: + return gfxd_puts("G_LOAD_UCODE"); + case G_BRANCH_Z: + return gfxd_puts("G_BRANCH_Z"); + case G_TRI2: + return gfxd_puts("G_TRI2"); +# if !(defined(F3D_BETA) && defined(F3DEX_GBI)) + case G_MODIFYVTX: + return gfxd_puts("G_MODIFYVTX"); +# endif +#endif +#if defined(F3DEX_GBI_2) + case G_QUAD: + return gfxd_puts("G_QUAD"); + case G_SPECIAL_3: + return gfxd_puts("G_SPECIAL_3"); + case G_SPECIAL_2: + return gfxd_puts("G_SPECIAL_2"); + case G_SPECIAL_1: + return gfxd_puts("G_SPECIAL_1"); + case G_DMA_IO: + return gfxd_puts("G_DMA_IO"); + case G_GEOMETRYMODE: + return gfxd_puts("G_GEOMETRYMODE"); +#endif + case G_TEXRECT: + return gfxd_puts("G_TEXRECT"); + case G_TEXRECTFLIP: + return gfxd_puts("G_TEXRECTFLIP"); + case G_RDPLOADSYNC: + return gfxd_puts("G_RDPLOADSYNC"); + case G_RDPPIPESYNC: + return gfxd_puts("G_RDPPIPESYNC"); + case G_RDPTILESYNC: + return gfxd_puts("G_RDPTILESYNC"); + case G_RDPFULLSYNC: + return gfxd_puts("G_RDPFULLSYNC"); + case G_SETKEYGB: + return gfxd_puts("G_SETKEYGB"); + case G_SETKEYR: + return gfxd_puts("G_SETKEYR"); + case G_SETCONVERT: + return gfxd_puts("G_SETCONVERT"); + case G_SETSCISSOR: + return gfxd_puts("G_SETSCISSOR"); + case G_SETPRIMDEPTH: + return gfxd_puts("G_SETPRIMDEPTH"); + case G_RDPSETOTHERMODE: + return gfxd_puts("G_RDPSETOTHERMODE"); + case G_LOADTLUT: + return gfxd_puts("G_LOADTLUT"); + case G_SETTILESIZE: + return gfxd_puts("G_SETTILESIZE"); + case G_LOADBLOCK: + return gfxd_puts("G_LOADBLOCK"); + case G_LOADTILE: + return gfxd_puts("G_LOADTILE"); + case G_SETTILE: + return gfxd_puts("G_SETTILE"); + case G_FILLRECT: + return gfxd_puts("G_FILLRECT"); + case G_SETFILLCOLOR: + return gfxd_puts("G_SETFILLCOLOR"); + case G_SETFOGCOLOR: + return gfxd_puts("G_SETFOGCOLOR"); + case G_SETBLENDCOLOR: + return gfxd_puts("G_SETBLENDCOLOR"); + case G_SETPRIMCOLOR: + return gfxd_puts("G_SETPRIMCOLOR"); + case G_SETENVCOLOR: + return gfxd_puts("G_SETENVCOLOR"); + case G_SETCOMBINE: + return gfxd_puts("G_SETCOMBINE"); + case G_SETTIMG: + return gfxd_puts("G_SETTIMG"); + case G_SETZIMG: + return gfxd_puts("G_SETZIMG"); + case G_SETCIMG: + return gfxd_puts("G_SETCIMG"); + default: + return gfxd_printf("0x%02" PRIX32, (uint32_t)v->i); + } +} + +UCFUNC int argfn_fmt(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_IM_FMT_RGBA: + return gfxd_puts("G_IM_FMT_RGBA"); + case G_IM_FMT_YUV: + return gfxd_puts("G_IM_FMT_YUV"); + case G_IM_FMT_CI: + return gfxd_puts("G_IM_FMT_CI"); + case G_IM_FMT_IA: + return gfxd_puts("G_IM_FMT_IA"); + case G_IM_FMT_I: + return gfxd_puts("G_IM_FMT_I"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int argfn_siz(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_IM_SIZ_4b: + return gfxd_puts("G_IM_SIZ_4b"); + case G_IM_SIZ_8b: + return gfxd_puts("G_IM_SIZ_8b"); + case G_IM_SIZ_16b: + return gfxd_puts("G_IM_SIZ_16b"); + case G_IM_SIZ_32b: + return gfxd_puts("G_IM_SIZ_32b"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int argfn_cm(const gfxd_value_t *v) +{ + int n = 0; + if (v->u & G_TX_MIRROR) + n += gfxd_puts("G_TX_MIRROR"); + else + n += gfxd_puts("G_TX_NOMIRROR"); + if (v->u & G_TX_CLAMP) + n += gfxd_puts(" | G_TX_CLAMP"); + else + n += gfxd_puts(" | G_TX_WRAP"); + return n; +} + +UCFUNC int argfn_tm(const gfxd_value_t *v) +{ + if (v->i == 0) + return gfxd_puts("G_TX_NOMASK"); + else + return gfxd_printf("%" PRIi32, v->i); +} + +UCFUNC int argfn_ts(const gfxd_value_t *v) +{ + if (v->i == 0) + return gfxd_puts("G_TX_NOLOD"); + else + return gfxd_printf("%" PRIi32, v->i); +} + +UCFUNC int argfn_switch(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_ON: + return gfxd_puts("G_ON"); + case G_OFF: + return gfxd_puts("G_OFF"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int argfn_tile(const gfxd_value_t *v) +{ + if (v->i == G_TX_LOADTILE) + return gfxd_puts("G_TX_LOADTILE"); + else if (v->i == G_TX_RENDERTILE) + return gfxd_puts("G_TX_RENDERTILE"); + else + return gfxd_printf("%" PRIi32, v->i); +} + +UCFUNC int argfn_gm(const gfxd_value_t *v) +{ + int n = 0; + uint32_t arg = v->u; + if (arg & G_ZBUFFER) + n += gfxd_puts("G_ZBUFFER"); + if (arg & G_TEXTURE_ENABLE) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_TEXTURE_ENABLE"); + } + if (arg & G_SHADE) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_SHADE"); + } + if ((arg & G_CULL_BOTH) == G_CULL_BOTH) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_CULL_BOTH"); + } + else + { + if (arg & G_CULL_FRONT) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_CULL_FRONT"); + } + if (arg & G_CULL_BACK) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_CULL_BACK"); + } + } + if (arg & G_FOG) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_FOG"); + } + if (arg & G_LIGHTING) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_LIGHTING"); + } + if (arg & G_TEXTURE_GEN) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_TEXTURE_GEN"); + } + if (arg & G_TEXTURE_GEN_LINEAR) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_TEXTURE_GEN_LINEAR"); + } + if (arg & G_LOD) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_LOD"); + } + if (arg & G_SHADING_SMOOTH) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_SHADING_SMOOTH"); + } + if (arg & G_CLIPPING) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("G_CLIPPING"); + } + arg = arg & ~(G_ZBUFFER | G_TEXTURE_ENABLE | G_SHADE | G_CULL_BOTH | + G_FOG | G_LIGHTING | G_TEXTURE_GEN | + G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH | + G_CLIPPING); + if (arg) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_printf("0x%08" PRIX32, arg); + } + return n; +} + +UCFUNC int argfn_sftlo(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_MDSFT_ALPHACOMPARE: + return gfxd_puts("G_MDSFT_ALPHACOMPARE"); + case G_MDSFT_ZSRCSEL: + return gfxd_puts("G_MDSFT_ZSRCSEL"); + case G_MDSFT_RENDERMODE: + return gfxd_puts("G_MDSFT_RENDERMODE"); + case G_MDSFT_BLENDER: + return gfxd_puts("G_MDSFT_BLENDER"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int rm_mode_str(uint32_t arg) +{ + int n = 0; + if (arg & AA_EN) + n += gfxd_puts("AA_EN"); + if (arg & Z_CMP) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("Z_CMP"); + } + if (arg & Z_UPD) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("Z_UPD"); + } + if (arg & IM_RD) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("IM_RD"); + } + if (arg & CLR_ON_CVG) + { + if (n > 0) + n += gfxd_puts(" | "); + n += gfxd_puts("CLR_ON_CVG"); + } + if (n > 0) + n += gfxd_puts(" | "); + int cvg = arg & 0x00000300; + switch (cvg) + { + case CVG_DST_CLAMP: + n += gfxd_puts("CVG_DST_CLAMP"); + break; + case CVG_DST_WRAP: + n += gfxd_puts("CVG_DST_WRAP"); + break; + case CVG_DST_FULL: + n += gfxd_puts("CVG_DST_FULL"); + break; + case CVG_DST_SAVE: + n += gfxd_puts("CVG_DST_SAVE"); + break; + } + int zmode = arg & 0x00000C00; + switch (zmode) + { + case ZMODE_OPA: + n += gfxd_puts(" | ZMODE_OPA"); + break; + case ZMODE_INTER: + n += gfxd_puts(" | ZMODE_INTER"); + break; + case ZMODE_XLU: + n += gfxd_puts(" | ZMODE_XLU"); + break; + case ZMODE_DEC: + n += gfxd_puts(" | ZMODE_DEC"); + break; + } + if (arg & CVG_X_ALPHA) + n += gfxd_puts(" | CVG_X_ALPHA"); + if (arg & ALPHA_CVG_SEL) + n += gfxd_puts(" | ALPHA_CVG_SEL"); + if (arg & FORCE_BL) + n += gfxd_puts(" | FORCE_BL"); + return n; +} + +UCFUNC int rm_cbl_str(uint32_t arg, int c) +{ + int n = 0; + if (c == 2) + arg <<= 2; + int bp = (arg >> 30) & 0b11; + switch (bp) + { + case G_BL_CLR_IN: + n += gfxd_printf("GBL_c%i(G_BL_CLR_IN", c); + break; + case G_BL_CLR_MEM: + n += gfxd_printf("GBL_c%i(G_BL_CLR_MEM", c); + break; + case G_BL_CLR_BL: + n += gfxd_printf("GBL_c%i(G_BL_CLR_BL", c); + break; + case G_BL_CLR_FOG: + n += gfxd_printf("GBL_c%i(G_BL_CLR_FOG", c); + break; + } + int ba = (arg >> 26) & 0b11; + switch (ba) + { + case G_BL_A_IN: + n += gfxd_puts(", G_BL_A_IN"); + break; + case G_BL_A_FOG: + n += gfxd_puts(", G_BL_A_FOG"); + break; + case G_BL_A_SHADE: + n += gfxd_puts(", G_BL_A_SHADE"); + break; + case G_BL_0: + n += gfxd_puts(", G_BL_0"); + break; + } + int bm = (arg >> 22) & 0b11; + switch (bm) + { + case G_BL_CLR_IN: + n += gfxd_puts(", G_BL_CLR_IN"); + break; + case G_BL_CLR_MEM: + n += gfxd_puts(", G_BL_CLR_MEM"); + break; + case G_BL_CLR_BL: + n += gfxd_puts(", G_BL_CLR_BL"); + break; + case G_BL_CLR_FOG: + n += gfxd_puts(", G_BL_CLR_FOG"); + break; + } + int bb = (arg >> 18) & 0b11; + switch (bb) + { + case G_BL_1MA: + n += gfxd_puts(", G_BL_1MA)"); + break; + case G_BL_A_MEM: + n += gfxd_puts(", G_BL_A_MEM)"); + break; + case G_BL_1: + n += gfxd_puts(", G_BL_1)"); + break; + case G_BL_0: + n += gfxd_puts(", G_BL_0)"); + break; + } + return n; +} + +struct rm_preset +{ + uint32_t rm; + const char * name; +}; + +static const struct rm_preset rm_presets[] = +{ + {G_RM_OPA_SURF, "G_RM_OPA_SURF"}, + {G_RM_OPA_SURF2, "G_RM_OPA_SURF2"}, + {G_RM_AA_OPA_SURF, "G_RM_AA_OPA_SURF"}, + {G_RM_AA_OPA_SURF2, "G_RM_AA_OPA_SURF2"}, + {G_RM_RA_OPA_SURF, "G_RM_RA_OPA_SURF"}, + {G_RM_RA_OPA_SURF2, "G_RM_RA_OPA_SURF2"}, + {G_RM_ZB_OPA_SURF, "G_RM_ZB_OPA_SURF"}, + {G_RM_ZB_OPA_SURF2, "G_RM_ZB_OPA_SURF2"}, + {G_RM_AA_ZB_OPA_SURF, "G_RM_AA_ZB_OPA_SURF"}, + {G_RM_AA_ZB_OPA_SURF2, "G_RM_AA_ZB_OPA_SURF2"}, + {G_RM_RA_ZB_OPA_SURF, "G_RM_RA_ZB_OPA_SURF"}, + {G_RM_RA_ZB_OPA_SURF2, "G_RM_RA_ZB_OPA_SURF2"}, + {G_RM_XLU_SURF, "G_RM_XLU_SURF"}, + {G_RM_XLU_SURF2, "G_RM_XLU_SURF2"}, + {G_RM_AA_XLU_SURF, "G_RM_AA_XLU_SURF"}, + {G_RM_AA_XLU_SURF2, "G_RM_AA_XLU_SURF2"}, + {G_RM_ZB_XLU_SURF, "G_RM_ZB_XLU_SURF"}, + {G_RM_ZB_XLU_SURF2, "G_RM_ZB_XLU_SURF2"}, + {G_RM_AA_ZB_XLU_SURF, "G_RM_AA_ZB_XLU_SURF"}, + {G_RM_AA_ZB_XLU_SURF2, "G_RM_AA_ZB_XLU_SURF2"}, + {G_RM_ZB_OPA_DECAL, "G_RM_ZB_OPA_DECAL"}, + {G_RM_ZB_OPA_DECAL2, "G_RM_ZB_OPA_DECAL2"}, + {G_RM_AA_ZB_OPA_DECAL, "G_RM_AA_ZB_OPA_DECAL"}, + {G_RM_AA_ZB_OPA_DECAL2, "G_RM_AA_ZB_OPA_DECAL2"}, + {G_RM_RA_ZB_OPA_DECAL, "G_RM_RA_ZB_OPA_DECAL"}, + {G_RM_RA_ZB_OPA_DECAL2, "G_RM_RA_ZB_OPA_DECAL2"}, + {G_RM_ZB_XLU_DECAL, "G_RM_ZB_XLU_DECAL"}, + {G_RM_ZB_XLU_DECAL2, "G_RM_ZB_XLU_DECAL2"}, + {G_RM_AA_ZB_XLU_DECAL, "G_RM_AA_ZB_XLU_DECAL"}, + {G_RM_AA_ZB_XLU_DECAL2, "G_RM_AA_ZB_XLU_DECAL2"}, + {G_RM_AA_ZB_OPA_INTER, "G_RM_AA_ZB_OPA_INTER"}, + {G_RM_AA_ZB_OPA_INTER2, "G_RM_AA_ZB_OPA_INTER2"}, + {G_RM_RA_ZB_OPA_INTER, "G_RM_RA_ZB_OPA_INTER"}, + {G_RM_RA_ZB_OPA_INTER2, "G_RM_RA_ZB_OPA_INTER2"}, + {G_RM_AA_ZB_XLU_INTER, "G_RM_AA_ZB_XLU_INTER"}, + {G_RM_AA_ZB_XLU_INTER2, "G_RM_AA_ZB_XLU_INTER2"}, + {G_RM_AA_XLU_LINE, "G_RM_AA_XLU_LINE"}, + {G_RM_AA_XLU_LINE2, "G_RM_AA_XLU_LINE2"}, + {G_RM_AA_ZB_XLU_LINE, "G_RM_AA_ZB_XLU_LINE"}, + {G_RM_AA_ZB_XLU_LINE2, "G_RM_AA_ZB_XLU_LINE2"}, + {G_RM_AA_DEC_LINE, "G_RM_AA_DEC_LINE"}, + {G_RM_AA_DEC_LINE2, "G_RM_AA_DEC_LINE2"}, + {G_RM_AA_ZB_DEC_LINE, "G_RM_AA_ZB_DEC_LINE"}, + {G_RM_AA_ZB_DEC_LINE2, "G_RM_AA_ZB_DEC_LINE2"}, + {G_RM_TEX_EDGE, "G_RM_TEX_EDGE"}, + {G_RM_TEX_EDGE2, "G_RM_TEX_EDGE2"}, + {G_RM_AA_TEX_EDGE, "G_RM_AA_TEX_EDGE"}, + {G_RM_AA_TEX_EDGE2, "G_RM_AA_TEX_EDGE2"}, + {G_RM_AA_ZB_TEX_EDGE, "G_RM_AA_ZB_TEX_EDGE"}, + {G_RM_AA_ZB_TEX_EDGE2, "G_RM_AA_ZB_TEX_EDGE2"}, + {G_RM_AA_ZB_TEX_INTER, "G_RM_AA_ZB_TEX_INTER"}, + {G_RM_AA_ZB_TEX_INTER2, "G_RM_AA_ZB_TEX_INTER2"}, + {G_RM_AA_SUB_SURF, "G_RM_AA_SUB_SURF"}, + {G_RM_AA_SUB_SURF2, "G_RM_AA_SUB_SURF2"}, + {G_RM_AA_ZB_SUB_SURF, "G_RM_AA_ZB_SUB_SURF"}, + {G_RM_AA_ZB_SUB_SURF2, "G_RM_AA_ZB_SUB_SURF2"}, + {G_RM_PCL_SURF, "G_RM_PCL_SURF"}, + {G_RM_PCL_SURF2, "G_RM_PCL_SURF2"}, + {G_RM_AA_PCL_SURF, "G_RM_AA_PCL_SURF"}, + {G_RM_AA_PCL_SURF2, "G_RM_AA_PCL_SURF2"}, + {G_RM_ZB_PCL_SURF, "G_RM_ZB_PCL_SURF"}, + {G_RM_ZB_PCL_SURF2, "G_RM_ZB_PCL_SURF2"}, + {G_RM_AA_ZB_PCL_SURF, "G_RM_AA_ZB_PCL_SURF"}, + {G_RM_AA_ZB_PCL_SURF2, "G_RM_AA_ZB_PCL_SURF2"}, + {G_RM_AA_OPA_TERR, "G_RM_AA_OPA_TERR"}, + {G_RM_AA_OPA_TERR2, "G_RM_AA_OPA_TERR2"}, + {G_RM_AA_ZB_OPA_TERR, "G_RM_AA_ZB_OPA_TERR"}, + {G_RM_AA_ZB_OPA_TERR2, "G_RM_AA_ZB_OPA_TERR2"}, + {G_RM_AA_TEX_TERR, "G_RM_AA_TEX_TERR"}, + {G_RM_AA_TEX_TERR2, "G_RM_AA_TEX_TERR2"}, + {G_RM_AA_ZB_TEX_TERR, "G_RM_AA_ZB_TEX_TERR"}, + {G_RM_AA_ZB_TEX_TERR2, "G_RM_AA_ZB_TEX_TERR2"}, + {G_RM_AA_SUB_TERR, "G_RM_AA_SUB_TERR"}, + {G_RM_AA_SUB_TERR2, "G_RM_AA_SUB_TERR2"}, + {G_RM_AA_ZB_SUB_TERR, "G_RM_AA_ZB_SUB_TERR"}, + {G_RM_AA_ZB_SUB_TERR2, "G_RM_AA_ZB_SUB_TERR2"}, + {G_RM_CLD_SURF, "G_RM_CLD_SURF"}, + {G_RM_CLD_SURF2, "G_RM_CLD_SURF2"}, + {G_RM_ZB_CLD_SURF, "G_RM_ZB_CLD_SURF"}, + {G_RM_ZB_CLD_SURF2, "G_RM_ZB_CLD_SURF2"}, + {G_RM_ZB_OVL_SURF, "G_RM_ZB_OVL_SURF"}, + {G_RM_ZB_OVL_SURF2, "G_RM_ZB_OVL_SURF2"}, + {G_RM_ADD, "G_RM_ADD"}, + {G_RM_ADD2, "G_RM_ADD2"}, + {G_RM_VISCVG, "G_RM_VISCVG"}, + {G_RM_VISCVG2, "G_RM_VISCVG2"}, + {G_RM_OPA_CI, "G_RM_OPA_CI"}, + {G_RM_OPA_CI2, "G_RM_OPA_CI2"}, + {G_RM_RA_SPRITE, "G_RM_RA_SPRITE"}, + {G_RM_RA_SPRITE2, "G_RM_RA_SPRITE2"}, +}; + +static const struct rm_preset bl1_presets[] = +{ + {G_RM_FOG_SHADE_A, "G_RM_FOG_SHADE_A"}, + {G_RM_FOG_PRIM_A, "G_RM_FOG_PRIM_A"}, + {G_RM_PASS, "G_RM_PASS"}, + {G_RM_NOOP, "G_RM_NOOP"}, +}; + +static const struct rm_preset bl2_presets[] = +{ + {G_RM_NOOP2, "G_RM_NOOP2"}, +}; + +UCFUNC int othermodelo_str(uint32_t arg, uint32_t which) +{ + int n = 0; + uint32_t rm_c1_mask = MDMASK_RM_C1; + uint32_t rm_c2_mask = MDMASK_RM_C2; + uint32_t rm_mode_lo = MDMASK_RM_LO; + uint32_t rm_mask = rm_c1_mask | rm_c2_mask | rm_mode_lo; + const struct rm_preset *pre_c1 = NULL; + const struct rm_preset *pre_c2 = NULL; + int n_rm_presets = sizeof(rm_presets) / sizeof(*rm_presets); + for (int i = 0; i < n_rm_presets; i++) + { + const struct rm_preset *pre = &rm_presets[i]; + uint32_t pre_extra = pre->rm & ~rm_mask; + uint32_t rm_c1 = arg & (rm_c1_mask | rm_mode_lo | pre_extra); + if (!pre_c1 && rm_c1 == pre->rm) + pre_c1 = pre; + uint32_t rm_c2 = arg & (rm_c2_mask | rm_mode_lo | pre_extra); + if (!pre_c2 && rm_c2 == pre->rm) + pre_c2 = pre; + } + if (!pre_c1 || !pre_c2 || pre_c1 + 1 != pre_c2) + { + int n_bl1_presets = sizeof(bl1_presets) / sizeof(*bl1_presets); + for (int i = 0; i < n_bl1_presets; i++) + { + const struct rm_preset *pre = &bl1_presets[i]; + uint32_t pre_extra = pre->rm & ~rm_mask; + uint32_t rm_c1 = arg & (rm_c1_mask | pre_extra); + if (rm_c1 == pre->rm) + { + pre_c1 = pre; + break; + } + } + int n_bl2_presets = sizeof(bl2_presets) / sizeof(*bl2_presets); + for (int i = 0; i < n_bl2_presets; i++) + { + const struct rm_preset *pre = &bl2_presets[i]; + uint32_t pre_extra = pre->rm & ~rm_mask; + uint32_t rm_c2 = arg & (rm_c2_mask | pre_extra); + if (rm_c2 == pre->rm) + { + pre_c2 = pre; + break; + } + } + } + uint32_t pre_rm = 0; + if (pre_c1) + pre_rm |= pre_c1->rm; + if (pre_c2) + pre_rm |= pre_c2->rm; + uint32_t ac_mask = MDMASK(ALPHACOMPARE); + if (((arg & ~pre_rm) | which) & ac_mask) + { + uint32_t ac = arg & ac_mask; + switch (ac) + { + case G_AC_NONE: + n += gfxd_puts("G_AC_NONE"); + break; + case G_AC_THRESHOLD: + n += gfxd_puts("G_AC_THRESHOLD"); + break; + case G_AC_DITHER: + n += gfxd_puts("G_AC_DITHER"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, ac); + break; + } + } + uint32_t zs_mask = MDMASK(ZSRCSEL); + if (((arg & ~pre_rm) | which) & zs_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t zs = arg & zs_mask; + switch (zs) + { + case G_ZS_PIXEL: + n += gfxd_puts("G_ZS_PIXEL"); + break; + case G_ZS_PRIM: + n += gfxd_puts("G_ZS_PRIM"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, zs); + break; + } + } + uint32_t rm = arg & (rm_mask | pre_rm); + if (((arg & ~pre_rm) | which) & rm_mode_lo) + { + if (n > 0) + n += gfxd_puts(" | "); + n += rm_mode_str(rm); + } + int c = 0; + if (which & rm_c1_mask) + c |= 1; + if (which & rm_c2_mask) + c |= 2; + if (c & 1 || (c == 0 && arg & rm_c1_mask)) + { + if (n > 0) + n += gfxd_puts(" | "); + if (pre_c1) + n += gfxd_printf("%s", pre_c1->name); + else + n += rm_cbl_str(rm, 1); + } + if (c & 2 || (c == 0 && arg & rm_c2_mask)) + { + if (n > 0) + n += gfxd_puts(" | "); + if (pre_c2) + n += gfxd_printf("%s", pre_c2->name); + else + n += rm_cbl_str(rm, 2); + } + uint32_t unk_mask = ~(rm_mask | ac_mask | zs_mask); + if (arg & unk_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t unk = arg & unk_mask; + n += gfxd_printf("0x%08" PRIX32, unk); + } + return n; +} + +UCFUNC int argfn_ac(const gfxd_value_t *v) +{ + return othermodelo_str(v->u, MDMASK(ALPHACOMPARE)); +} + +UCFUNC int argfn_zs(const gfxd_value_t *v) +{ + return othermodelo_str(v->u, MDMASK(ZSRCSEL)); +} + +UCFUNC int argfn_rm1(const gfxd_value_t *v) +{ + return othermodelo_str(v->u, MDMASK_RM_C1); +} + +UCFUNC int argfn_rm2(const gfxd_value_t *v) +{ + return othermodelo_str(v->u, MDMASK_RM_C2); +} + +UCFUNC int argfn_othermodelo(const gfxd_value_t *v) +{ + uint32_t mask = MDMASK(ALPHACOMPARE) | MDMASK(ZSRCSEL) | MDMASK_RM_C1 | + MDMASK_RM_C2; + return othermodelo_str(v->u, mask); +} + +UCFUNC int argfn_sfthi(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_MDSFT_ALPHADITHER: + return gfxd_puts("G_MDSFT_ALPHADITHER"); + case G_MDSFT_RGBDITHER: + return gfxd_puts("G_MDSFT_RGBDITHER"); + case G_MDSFT_COMBKEY: + return gfxd_puts("G_MDSFT_COMBKEY"); + case G_MDSFT_TEXTCONV: + return gfxd_puts("G_MDSFT_TEXTCONV"); + case G_MDSFT_TEXTFILT: + return gfxd_puts("G_MDSFT_TEXTFILT"); + case G_MDSFT_TEXTLUT: + return gfxd_puts("G_MDSFT_TEXTLUT"); + case G_MDSFT_TEXTLOD: + return gfxd_puts("G_MDSFT_TEXTLOD"); + case G_MDSFT_TEXTDETAIL: + return gfxd_puts("G_MDSFT_TEXTDETAIL"); + case G_MDSFT_TEXTPERSP: + return gfxd_puts("G_MDSFT_TEXTPERSP"); + case G_MDSFT_CYCLETYPE: + return gfxd_puts("G_MDSFT_CYCLETYPE"); + case G_MDSFT_PIPELINE: + return gfxd_puts("G_MDSFT_PIPELINE"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int othermodehi_str(uint32_t arg, uint32_t which) +{ + int n = 0; + uint32_t ad_mask = MDMASK(ALPHADITHER); + if ((arg | which) & ad_mask) + { + uint32_t ad = arg & ad_mask; + switch (ad) + { + case G_AD_PATTERN: + n += gfxd_puts("G_AD_PATTERN"); + break; + case G_AD_NOTPATTERN: + n += gfxd_puts("G_AD_NOTPATTERN"); + break; + case G_AD_NOISE: + n += gfxd_puts("G_AD_NOISE"); + break; + case G_AD_DISABLE: + n += gfxd_puts("G_AD_DISABLE"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, ad); + break; + } + } + uint32_t cd_mask = MDMASK(RGBDITHER); + if ((arg | which) & cd_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t cd = arg & cd_mask; + switch (cd) + { + case G_CD_MAGICSQ: + n += gfxd_puts("G_CD_MAGICSQ"); + break; + case G_CD_BAYER: + n += gfxd_puts("G_CD_BAYER"); + break; + case G_CD_NOISE: + n += gfxd_puts("G_CD_NOISE"); + break; + case G_CD_DISABLE: + n += gfxd_puts("G_CD_DISABLE"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, cd); + break; + } + } + uint32_t ck_mask = MDMASK(COMBKEY); + if ((arg | which) & ck_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t ck = arg & ck_mask; + switch (ck) + { + case G_CK_NONE: + n += gfxd_puts("G_CK_NONE"); + break; + case G_CK_KEY: + n += gfxd_puts("G_CK_KEY"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, ck); + break; + } + } + uint32_t tc_mask = MDMASK(TEXTCONV); + if ((arg | which) & tc_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t tc = arg & tc_mask; + switch (tc) + { + case G_TC_CONV: + n += gfxd_puts("G_TC_CONV"); + break; + case G_TC_FILTCONV: + n += gfxd_puts("G_TC_FILTCONV"); + break; + case G_TC_FILT: + n += gfxd_puts("G_TC_FILT"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, tc); + break; + } + } + uint32_t tf_mask = MDMASK(TEXTFILT); + if ((arg | which) & tf_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t tf = arg & tf_mask; + switch (tf) + { + case G_TF_POINT: + n += gfxd_puts("G_TF_POINT"); + break; + case G_TF_BILERP: + n += gfxd_puts("G_TF_BILERP"); + break; + case G_TF_AVERAGE: + n += gfxd_puts("G_TF_AVERAGE"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, tf); + break; + } + } + uint32_t tt_mask = MDMASK(TEXTLUT); + if ((arg | which) & tt_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t tt = arg & tt_mask; + switch (tt) + { + case G_TT_NONE: + n += gfxd_puts("G_TT_NONE"); + break; + case G_TT_RGBA16: + n += gfxd_puts("G_TT_RGBA16"); + break; + case G_TT_IA16: + n += gfxd_puts("G_TT_IA16"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, tt); + break; + } + } + uint32_t tl_mask = MDMASK(TEXTLOD); + if ((arg | which) & tl_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t tl = arg & tl_mask; + switch (tl) + { + case G_TL_TILE: + n += gfxd_puts("G_TL_TILE"); + break; + case G_TL_LOD: + n += gfxd_puts("G_TL_LOD"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, tl); + break; + } + } + uint32_t td_mask = MDMASK(TEXTDETAIL); + if ((arg | which) & td_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t td = arg & td_mask; + switch (td) + { + case G_TD_CLAMP: + n += gfxd_puts("G_TD_CLAMP"); + break; + case G_TD_SHARPEN: + n += gfxd_puts("G_TD_SHARPEN"); + break; + case G_TD_DETAIL: + n += gfxd_puts("G_TD_DETAIL"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, td); + break; + } + } + uint32_t tp_mask = MDMASK(TEXTPERSP); + if ((arg | which) & tp_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t tp = arg & tp_mask; + switch (tp) + { + case G_TP_NONE: + n += gfxd_puts("G_TP_NONE"); + break; + case G_TP_PERSP: + n += gfxd_puts("G_TP_PERSP"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, tp); + break; + } + } + uint32_t cyc_mask = MDMASK(CYCLETYPE); + if ((arg | which) & cyc_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t cyc = arg & cyc_mask; + switch (cyc) + { + case G_CYC_1CYCLE: + n += gfxd_puts("G_CYC_1CYCLE"); + break; + case G_CYC_2CYCLE: + n += gfxd_puts("G_CYC_2CYCLE"); + break; + case G_CYC_COPY: + n += gfxd_puts("G_CYC_COPY"); + break; + case G_CYC_FILL: + n += gfxd_puts("G_CYC_FILL"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, cyc); + break; + } + } + uint32_t pm_mask = MDMASK(PIPELINE); + if ((arg | which) & pm_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t pm = arg & pm_mask; + switch (pm) + { + case G_PM_NPRIMITIVE: + n += gfxd_puts("G_PM_NPRIMITIVE"); + break; + case G_PM_1PRIMITIVE: + n += gfxd_puts("G_PM_1PRIMITIVE"); + break; + default: + n += gfxd_printf("0x%08" PRIX32, pm); + break; + } + } + uint32_t unk_mask = ~(ad_mask | cd_mask | ck_mask | tc_mask | tf_mask | + tt_mask | tl_mask | td_mask | tp_mask | + cyc_mask | pm_mask); + if (arg & unk_mask) + { + if (n > 0) + n += gfxd_puts(" | "); + uint32_t unk = arg & unk_mask; + n += gfxd_printf("0x%08" PRIX32, unk); + } + return n; +} + +UCFUNC int argfn_ad(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(ALPHADITHER)); +} + +UCFUNC int argfn_cd(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(RGBDITHER)); +} + +UCFUNC int argfn_ck(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(COMBKEY)); +} + +UCFUNC int argfn_tc(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(TEXTCONV)); +} + +UCFUNC int argfn_tf(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(TEXTFILT)); +} + +UCFUNC int argfn_tt(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(TEXTLUT)); +} + +UCFUNC int argfn_tl(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(TEXTLOD)); +} + +UCFUNC int argfn_td(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(TEXTDETAIL)); +} + +UCFUNC int argfn_tp(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(TEXTPERSP)); +} + +UCFUNC int argfn_cyc(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(CYCLETYPE)); +} + +UCFUNC int argfn_pm(const gfxd_value_t *v) +{ + return othermodehi_str(v->u, MDMASK(PIPELINE)); +} + +UCFUNC int argfn_othermodehi(const gfxd_value_t *v) +{ + uint32_t mask = MDMASK(ALPHADITHER) | + MDMASK(RGBDITHER) | + MDMASK(COMBKEY) | + MDMASK(TEXTCONV) | + MDMASK(TEXTFILT) | + MDMASK(TEXTLUT) | + MDMASK(TEXTLOD) | + MDMASK(TEXTDETAIL) | + MDMASK(TEXTPERSP) | + MDMASK(CYCLETYPE) | + MDMASK(PIPELINE); + return othermodehi_str(v->u, mask); +} + +UCFUNC int argfn_cv(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_CV_K0: + return gfxd_puts("G_CV_K0"); + case G_CV_K1: + return gfxd_puts("G_CV_K1"); + case G_CV_K2: + return gfxd_puts("G_CV_K2"); + case G_CV_K3: + return gfxd_puts("G_CV_K3"); + case G_CV_K4: + return gfxd_puts("G_CV_K4"); + case G_CV_K5: + return gfxd_puts("G_CV_K5"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int argfn_ccmuxa(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_CCMUX_COMBINED: + return gfxd_puts("COMBINED"); + case G_CCMUX_TEXEL0: + return gfxd_puts("TEXEL0"); + case G_CCMUX_TEXEL1: + return gfxd_puts("TEXEL1"); + case G_CCMUX_PRIMITIVE: + return gfxd_puts("PRIMITIVE"); + case G_CCMUX_SHADE: + return gfxd_puts("SHADE"); + case G_CCMUX_ENVIRONMENT: + return gfxd_puts("ENVIRONMENT"); + case G_CCMUX_1: + return gfxd_puts("1"); + case G_CCMUX_NOISE: + return gfxd_puts("NOISE"); + default: + return gfxd_puts("0"); + } +} + +UCFUNC int argfn_ccmuxb(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_CCMUX_COMBINED: + return gfxd_puts("COMBINED"); + case G_CCMUX_TEXEL0: + return gfxd_puts("TEXEL0"); + case G_CCMUX_TEXEL1: + return gfxd_puts("TEXEL1"); + case G_CCMUX_PRIMITIVE: + return gfxd_puts("PRIMITIVE"); + case G_CCMUX_SHADE: + return gfxd_puts("SHADE"); + case G_CCMUX_ENVIRONMENT: + return gfxd_puts("ENVIRONMENT"); + case G_CCMUX_CENTER: + return gfxd_puts("CENTER"); + case G_CCMUX_K4: + return gfxd_puts("K4"); + default: + return gfxd_puts("0"); + } +} + +UCFUNC int argfn_ccmuxc(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_CCMUX_COMBINED: + return gfxd_puts("COMBINED"); + case G_CCMUX_TEXEL0: + return gfxd_puts("TEXEL0"); + case G_CCMUX_TEXEL1: + return gfxd_puts("TEXEL1"); + case G_CCMUX_PRIMITIVE: + return gfxd_puts("PRIMITIVE"); + case G_CCMUX_SHADE: + return gfxd_puts("SHADE"); + case G_CCMUX_ENVIRONMENT: + return gfxd_puts("ENVIRONMENT"); + case G_CCMUX_SCALE: + return gfxd_puts("SCALE"); + case G_CCMUX_COMBINED_ALPHA: + return gfxd_puts("COMBINED_ALPHA"); + case G_CCMUX_TEXEL0_ALPHA: + return gfxd_puts("TEXEL0_ALPHA"); + case G_CCMUX_TEXEL1_ALPHA: + return gfxd_puts("TEXEL1_ALPHA"); + case G_CCMUX_PRIMITIVE_ALPHA: + return gfxd_puts("PRIMITIVE_ALPHA"); + case G_CCMUX_SHADE_ALPHA: + return gfxd_puts("SHADE_ALPHA"); + case G_CCMUX_ENV_ALPHA: + return gfxd_puts("ENV_ALPHA"); + case G_CCMUX_LOD_FRACTION: + return gfxd_puts("LOD_FRACTION"); + case G_CCMUX_PRIM_LOD_FRAC: + return gfxd_puts("PRIM_LOD_FRAC"); + case G_CCMUX_K5: + return gfxd_puts("K5"); + default: + return gfxd_puts("0"); + } +} + +UCFUNC int argfn_ccmuxd(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_CCMUX_COMBINED: + return gfxd_puts("COMBINED"); + case G_CCMUX_TEXEL0: + return gfxd_puts("TEXEL0"); + case G_CCMUX_TEXEL1: + return gfxd_puts("TEXEL1"); + case G_CCMUX_PRIMITIVE: + return gfxd_puts("PRIMITIVE"); + case G_CCMUX_SHADE: + return gfxd_puts("SHADE"); + case G_CCMUX_ENVIRONMENT: + return gfxd_puts("ENVIRONMENT"); + case G_CCMUX_1: + return gfxd_puts("1"); + default: + return gfxd_puts("0"); + } +} + +UCFUNC int argfn_acmuxabd(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_ACMUX_COMBINED: + return gfxd_puts("COMBINED"); + case G_ACMUX_TEXEL0: + return gfxd_puts("TEXEL0"); + case G_ACMUX_TEXEL1: + return gfxd_puts("TEXEL1"); + case G_ACMUX_PRIMITIVE: + return gfxd_puts("PRIMITIVE"); + case G_ACMUX_SHADE: + return gfxd_puts("SHADE"); + case G_ACMUX_ENVIRONMENT: + return gfxd_puts("ENVIRONMENT"); + case G_ACMUX_1: + return gfxd_puts("1"); + default: + return gfxd_puts("0"); + } +} + +UCFUNC int argfn_acmuxc(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_ACMUX_LOD_FRACTION: + return gfxd_puts("LOD_FRACTION"); + case G_ACMUX_TEXEL0: + return gfxd_puts("TEXEL0"); + case G_ACMUX_TEXEL1: + return gfxd_puts("TEXEL1"); + case G_ACMUX_PRIMITIVE: + return gfxd_puts("PRIMITIVE"); + case G_ACMUX_SHADE: + return gfxd_puts("SHADE"); + case G_ACMUX_ENVIRONMENT: + return gfxd_puts("ENVIRONMENT"); + case G_ACMUX_PRIM_LOD_FRAC: + return gfxd_puts("PRIM_LOD_FRAC"); + default: + return gfxd_puts("0"); + } +} + +struct cc_mode +{ + int a; + int b; + int c; + int d; + int Aa; + int Ab; + int Ac; + int Ad; +}; + +struct cc_preset +{ + struct cc_mode mode; + const char * name; +}; + +#define CC_(a,b,c,d,Aa,Ab,Ac,Ad) \ + { \ + G_CCMUX_##a, G_CCMUX_##b, \ + G_CCMUX_##c, G_CCMUX_##d, \ + G_ACMUX_##Aa, G_ACMUX_##Ab, \ + G_ACMUX_##Ac, G_ACMUX_##Ad \ + } +#define CC(m) CC_(m) +static const struct cc_preset cc_presets[] = +{ + {CC(G_CC_MODULATEI), "G_CC_MODULATEI"}, + {CC(G_CC_MODULATEIA), "G_CC_MODULATEIA"}, + {CC(G_CC_MODULATEIDECALA), "G_CC_MODULATEIDECALA"}, + {CC(G_CC_MODULATERGB), "G_CC_MODULATERGB"}, + {CC(G_CC_MODULATERGBA), "G_CC_MODULATERGBA"}, + {CC(G_CC_MODULATERGBDECALA), "G_CC_MODULATERGBDECALA"}, + {CC(G_CC_MODULATEI_PRIM), "G_CC_MODULATEI_PRIM"}, + {CC(G_CC_MODULATEIA_PRIM), "G_CC_MODULATEIA_PRIM"}, + {CC(G_CC_MODULATEIDECALA_PRIM), "G_CC_MODULATEIDECALA_PRIM"}, + {CC(G_CC_MODULATERGB_PRIM), "G_CC_MODULATERGB_PRIM"}, + {CC(G_CC_MODULATERGBA_PRIM), "G_CC_MODULATERGBA_PRIM"}, + {CC(G_CC_MODULATERGBDECALA_PRIM), "G_CC_MODULATERGBDECALA_PRIM"}, + {CC(G_CC_DECALRGB), "G_CC_DECALRGB"}, + {CC(G_CC_DECALRGBA), "G_CC_DECALRGBA"}, + {CC(G_CC_BLENDI), "G_CC_BLENDI"}, + {CC(G_CC_BLENDIA), "G_CC_BLENDIA"}, + {CC(G_CC_BLENDIDECALA), "G_CC_BLENDIDECALA"}, + {CC(G_CC_BLENDRGBA), "G_CC_BLENDRGBA"}, + {CC(G_CC_BLENDRGBDECALA), "G_CC_BLENDRGBDECALA"}, + {CC(G_CC_REFLECTRGB), "G_CC_REFLECTRGB"}, + {CC(G_CC_REFLECTRGBDECALA), "G_CC_REFLECTRGBDECALA"}, + {CC(G_CC_HILITERGB), "G_CC_HILITERGB"}, + {CC(G_CC_HILITERGBA), "G_CC_HILITERGBA"}, + {CC(G_CC_HILITERGBDECALA), "G_CC_HILITERGBDECALA"}, + {CC(G_CC_1CYUV2RGB), "G_CC_1CYUV2RGB"}, + {CC(G_CC_PRIMITIVE), "G_CC_PRIMITIVE"}, + {CC(G_CC_SHADE), "G_CC_SHADE"}, + {CC(G_CC_ADDRGB), "G_CC_ADDRGB"}, + {CC(G_CC_ADDRGBDECALA), "G_CC_ADDRGBDECALA"}, + {CC(G_CC_SHADEDECALA), "G_CC_SHADEDECALA"}, + {CC(G_CC_BLENDPE), "G_CC_BLENDPE"}, + {CC(G_CC_BLENDPEDECALA), "G_CC_BLENDPEDECALA"}, + {CC(G_CC_TRILERP), "G_CC_TRILERP"}, + {CC(G_CC_TEMPLERP), "G_CC_TEMPLERP"}, + {CC(G_CC_INTERFERENCE), "G_CC_INTERFERENCE"}, + {CC(_G_CC_BLENDPE), "_G_CC_BLENDPE"}, + {CC(_G_CC_BLENDPEDECALA), "_G_CC_BLENDPEDECALA"}, + {CC(_G_CC_SPARSEST), "_G_CC_SPARSEST"}, + {CC(_G_CC_TWOCOLORTEX), "_G_CC_TWOCOLORTEX"}, + {CC(G_CC_MODULATEI2), "G_CC_MODULATEI2"}, + {CC(G_CC_MODULATEIA2), "G_CC_MODULATEIA2"}, + {CC(G_CC_MODULATERGB2), "G_CC_MODULATERGB2"}, + {CC(G_CC_MODULATERGBA2), "G_CC_MODULATERGBA2"}, + {CC(G_CC_MODULATEI_PRIM2), "G_CC_MODULATEI_PRIM2"}, + {CC(G_CC_MODULATEIA_PRIM2), "G_CC_MODULATEIA_PRIM2"}, + {CC(G_CC_MODULATERGB_PRIM2), "G_CC_MODULATERGB_PRIM2"}, + {CC(G_CC_MODULATERGBA_PRIM2), "G_CC_MODULATERGBA_PRIM2"}, + {CC(G_CC_DECALRGB2), "G_CC_DECALRGB2"}, + {CC(G_CC_BLENDI2), "G_CC_BLENDI2"}, + {CC(G_CC_BLENDIA2), "G_CC_BLENDIA2"}, + {CC(G_CC_HILITERGB2), "G_CC_HILITERGB2"}, + {CC(G_CC_HILITERGBA2), "G_CC_HILITERGBA2"}, + {CC(G_CC_HILITERGBDECALA2), "G_CC_HILITERGBDECALA2"}, + {CC(G_CC_HILITERGBPASSA2), "G_CC_HILITERGBPASSA2"}, + {CC(G_CC_CHROMA_KEY2), "G_CC_CHROMA_KEY2"}, + {CC(G_CC_YUV2RGB), "G_CC_YUV2RGB"}, + {CC(G_CC_PASS2), "G_CC_PASS2"}, +}; +#undef CC_ +#undef CC + +UCFUNC int argfn_ccpre(const gfxd_value_t *v) +{ + return gfxd_printf("%s", cc_presets[v->i].name); +} + +UCFUNC int argfn_sc(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_SC_NON_INTERLACE: + return gfxd_puts("G_SC_NON_INTERLACE"); + case G_SC_EVEN_INTERLACE: + return gfxd_puts("G_SC_EVEN_INTERLACE"); + case G_SC_ODD_INTERLACE: + return gfxd_puts("G_SC_ODD_INTERLACE"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int argfn_bz(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_BZ_PERSP: + return gfxd_puts("G_BZ_PERSP"); + default: + return gfxd_puts("G_BZ_ORTHO"); + } +} +#endif + +UCFUNC int argfn_dlf(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_DL_PUSH: + return gfxd_puts("G_DL_PUSH"); + case G_DL_NOPUSH: + return gfxd_puts("G_DL_NOPUSH"); + default: + return gfxd_printf("%" PRIi32, v->i);; + } +} + +UCFUNC int argfn_mp(const gfxd_value_t *v) +{ + int n = 0; + if (v->u & G_MTX_PUSH) + n += gfxd_puts("G_MTX_PUSH"); + else + n += gfxd_puts("G_MTX_NOPUSH"); + if (v->u & G_MTX_LOAD) + n += gfxd_puts(" | G_MTX_LOAD"); + else + n += gfxd_puts(" | G_MTX_MUL"); + if (v->u & G_MTX_PROJECTION) + n += gfxd_puts(" | G_MTX_PROJECTION"); + else + n += gfxd_puts(" | G_MTX_MODELVIEW"); + for (int i = 3; i < 8; i++) + if (v->u & (1 << i)) + n += gfxd_printf(" | 0x%02x", 1 << i); + return n; +} + +UCFUNC int argfn_ms(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_MTX_MODELVIEW: + return gfxd_puts("G_MTX_MODELVIEW"); + case G_MTX_PROJECTION: + return gfxd_puts("G_MTX_PROJECTION"); + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int argfn_mw(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_MW_MATRIX: + return gfxd_puts("G_MW_MATRIX"); + case G_MW_NUMLIGHT: + return gfxd_puts("G_MW_NUMLIGHT"); + case G_MW_CLIP: + return gfxd_puts("G_MW_CLIP"); + case G_MW_SEGMENT: + return gfxd_puts("G_MW_SEGMENT"); + case G_MW_FOG: + return gfxd_puts("G_MW_FOG"); + case G_MW_LIGHTCOL: + return gfxd_puts("G_MW_LIGHTCOL"); + case G_MW_PERSPNORM: + return gfxd_puts("G_MW_PERSPNORM"); +#if defined(F3D_GBI) || defined(F3DEX_GBI) + case G_MW_POINTS: + return gfxd_puts("G_MW_POINTS"); +#endif +#if defined(F3DEX_GBI_2) + case G_MW_FORCEMTX: + return gfxd_puts("G_MW_FORCEMTX"); +#endif + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int argfn_mwo_clip(const gfxd_value_t *v) +{ + switch (v->u) + { + case G_MWO_CLIP_RNX: + return gfxd_puts("G_MWO_CLIP_RNX"); + case G_MWO_CLIP_RNY: + return gfxd_puts("G_MWO_CLIP_RNY"); + case G_MWO_CLIP_RPX: + return gfxd_puts("G_MWO_CLIP_RPX"); + case G_MWO_CLIP_RPY: + return gfxd_puts("G_MWO_CLIP_RPY"); + default: + return gfxd_printf("0x%04" PRIX32, v->u); + } +} + +UCFUNC int argfn_mwo_lightcol(const gfxd_value_t *v) +{ + switch (v->u) + { + case G_MWO_aLIGHT_1: + return gfxd_puts("G_MWO_aLIGHT_1"); + case G_MWO_bLIGHT_1: + return gfxd_puts("G_MWO_bLIGHT_1"); + case G_MWO_aLIGHT_2: + return gfxd_puts("G_MWO_aLIGHT_2"); + case G_MWO_bLIGHT_2: + return gfxd_puts("G_MWO_bLIGHT_2"); + case G_MWO_aLIGHT_3: + return gfxd_puts("G_MWO_aLIGHT_3"); + case G_MWO_bLIGHT_3: + return gfxd_puts("G_MWO_bLIGHT_3"); + case G_MWO_aLIGHT_4: + return gfxd_puts("G_MWO_aLIGHT_4"); + case G_MWO_bLIGHT_4: + return gfxd_puts("G_MWO_bLIGHT_4"); + case G_MWO_aLIGHT_5: + return gfxd_puts("G_MWO_aLIGHT_5"); + case G_MWO_bLIGHT_5: + return gfxd_puts("G_MWO_bLIGHT_5"); + case G_MWO_aLIGHT_6: + return gfxd_puts("G_MWO_aLIGHT_6"); + case G_MWO_bLIGHT_6: + return gfxd_puts("G_MWO_bLIGHT_6"); + case G_MWO_aLIGHT_7: + return gfxd_puts("G_MWO_aLIGHT_7"); + case G_MWO_bLIGHT_7: + return gfxd_puts("G_MWO_bLIGHT_7"); + case G_MWO_aLIGHT_8: + return gfxd_puts("G_MWO_aLIGHT_8"); + case G_MWO_bLIGHT_8: + return gfxd_puts("G_MWO_bLIGHT_8"); + default: + return gfxd_printf("0x%04" PRIX32, v->u); + } +} + +UCFUNC int argfn_lightnum(const gfxd_value_t *v) +{ + return gfxd_printf("LIGHT_%" PRIi32, v->i); +} + +UCFUNC int argfn_lightsn(const gfxd_value_t *v) +{ + return gfxd_printf("*(Lightsn *)0x%08" PRIX32, v->u); +} + +UCFUNC int argfn_mwo_matrix(const gfxd_value_t *v) +{ + switch (v->u) + { + case G_MWO_MATRIX_XX_XY_I: + return gfxd_puts("G_MWO_MATRIX_XX_XY_I"); + case G_MWO_MATRIX_XZ_XW_I: + return gfxd_puts("G_MWO_MATRIX_XZ_XW_I"); + case G_MWO_MATRIX_YX_YY_I: + return gfxd_puts("G_MWO_MATRIX_YX_YY_I"); + case G_MWO_MATRIX_YZ_YW_I: + return gfxd_puts("G_MWO_MATRIX_YZ_YW_I"); + case G_MWO_MATRIX_ZX_ZY_I: + return gfxd_puts("G_MWO_MATRIX_ZX_ZY_I"); + case G_MWO_MATRIX_ZZ_ZW_I: + return gfxd_puts("G_MWO_MATRIX_ZZ_ZW_I"); + case G_MWO_MATRIX_WX_WY_I: + return gfxd_puts("G_MWO_MATRIX_WX_WY_I"); + case G_MWO_MATRIX_WZ_WW_I: + return gfxd_puts("G_MWO_MATRIX_WZ_WW_I"); + case G_MWO_MATRIX_XX_XY_F: + return gfxd_puts("G_MWO_MATRIX_XX_XY_F"); + case G_MWO_MATRIX_XZ_XW_F: + return gfxd_puts("G_MWO_MATRIX_XZ_XW_F"); + case G_MWO_MATRIX_YX_YY_F: + return gfxd_puts("G_MWO_MATRIX_YX_YY_F"); + case G_MWO_MATRIX_YZ_YW_F: + return gfxd_puts("G_MWO_MATRIX_YZ_YW_F"); + case G_MWO_MATRIX_ZX_ZY_F: + return gfxd_puts("G_MWO_MATRIX_ZX_ZY_F"); + case G_MWO_MATRIX_ZZ_ZW_F: + return gfxd_puts("G_MWO_MATRIX_ZZ_ZW_F"); + case G_MWO_MATRIX_WX_WY_F: + return gfxd_puts("G_MWO_MATRIX_WX_WY_F"); + case G_MWO_MATRIX_WZ_WW_F: + return gfxd_puts("G_MWO_MATRIX_WZ_WW_F"); + default: + return gfxd_printf("0x%04" PRIX32, v->u); + } +} + +UCFUNC int argfn_mwo_point(const gfxd_value_t *v) +{ + switch (v->u) + { + case G_MWO_POINT_RGBA: + return gfxd_puts("G_MWO_POINT_RGBA"); + case G_MWO_POINT_ST: + return gfxd_puts("G_MWO_POINT_ST"); + case G_MWO_POINT_XYSCREEN: + return gfxd_puts("G_MWO_POINT_XYSCREEN"); + case G_MWO_POINT_ZSCREEN: + return gfxd_puts("G_MWO_POINT_ZSCREEN"); + default: + return gfxd_printf("0x%04" PRIX32, v->u); + } +} + +UCFUNC int argfn_mv(const gfxd_value_t *v) +{ + switch (v->i) + { + case G_MV_VIEWPORT: + return gfxd_puts("G_MV_VIEWPORT"); +#if defined(F3D_GBI) || defined(F3DEX_GBI) + case G_MV_LOOKATY: + return gfxd_puts("G_MV_LOOKATY"); + case G_MV_LOOKATX: + return gfxd_puts("G_MV_LOOKATX"); + case G_MV_L0: + return gfxd_puts("G_MV_L0"); + case G_MV_L1: + return gfxd_puts("G_MV_L1"); + case G_MV_L2: + return gfxd_puts("G_MV_L2"); + case G_MV_L3: + return gfxd_puts("G_MV_L3"); + case G_MV_L4: + return gfxd_puts("G_MV_L4"); + case G_MV_L5: + return gfxd_puts("G_MV_L5"); + case G_MV_L6: + return gfxd_puts("G_MV_L6"); + case G_MV_L7: + return gfxd_puts("G_MV_L7"); + case G_MV_TXTATT: + return gfxd_puts("G_MV_TXTATT"); + case G_MV_MATRIX_2: + return gfxd_puts("G_MV_MATRIX_2"); + case G_MV_MATRIX_3: + return gfxd_puts("G_MV_MATRIX_3"); + case G_MV_MATRIX_4: + return gfxd_puts("G_MV_MATRIX_4"); + case G_MV_MATRIX_1: + return gfxd_puts("G_MV_MATRIX_1"); +#elif defined(F3DEX_GBI_2) + case G_MV_MMTX: + return gfxd_puts("G_MV_MMTX"); + case G_MV_PMTX: + return gfxd_puts("G_MV_PMTX"); + case G_MV_LIGHT: + return gfxd_puts("G_MV_LIGHT"); + case G_MV_POINT: + return gfxd_puts("G_MV_POINT"); + case G_MV_MATRIX: + return gfxd_puts("G_MV_MATRIX"); +#endif + default: + return gfxd_printf("%" PRIi32, v->i); + } +} + +UCFUNC int argfn_cr(const gfxd_value_t *v) +{ + switch (v->u) + { + case FRUSTRATIO_1: + return gfxd_puts("FRUSTRATIO_1"); + case FRUSTRATIO_2: + return gfxd_puts("FRUSTRATIO_2"); + case FRUSTRATIO_3: + return gfxd_puts("FRUSTRATIO_3"); + case FRUSTRATIO_4: + return gfxd_puts("FRUSTRATIO_4"); + case FRUSTRATIO_5: + return gfxd_puts("FRUSTRATIO_5"); + case FRUSTRATIO_6: + return gfxd_puts("FRUSTRATIO_6"); + default: + return gfxd_printf("%" PRIu32, v->u); + } +} diff --git a/ZAPDTR/lib/libgfxd/uc_argtbl.c b/ZAPDTR/lib/libgfxd/uc_argtbl.c new file mode 100644 index 000000000..22a0b6500 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_argtbl.c @@ -0,0 +1,485 @@ +static const gfxd_arg_type_t arg_tbl[] = +{ + [gfxd_Word] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Opcode] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_opc, + }, + [gfxd_Coordi] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_u, + }, + [gfxd_Coordq] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_qu102, + }, + [gfxd_Pal] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Tlut] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Timg] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Tmem] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x16, + }, + [gfxd_Tile] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_tile, + }, + [gfxd_Fmt] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_fmt, + }, + [gfxd_Siz] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_siz, + }, + [gfxd_Dim] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Cm] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_cm, + }, + [gfxd_Tm] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_tm, + }, + [gfxd_Ts] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_ts, + }, + [gfxd_Dxt] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_u, + }, + [gfxd_Tag] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Pm] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_pm, + }, + [gfxd_Colorpart] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_color, + }, + [gfxd_Color] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Lodfrac] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_qu08, + }, + [gfxd_Cimg] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Zimg] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Ac] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_ac, + }, + [gfxd_Ad] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_ad, + }, + [gfxd_Cd] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_cd, + }, + [gfxd_Ccpre] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_ccpre, + }, + [gfxd_Ccmuxa] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_ccmuxa, + }, + [gfxd_Ccmuxb] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_ccmuxb, + }, + [gfxd_Ccmuxc] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_ccmuxc, + }, + [gfxd_Ccmuxd] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_ccmuxd, + }, + [gfxd_Acmuxabd] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_acmuxabd, + }, + [gfxd_Acmuxc] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_acmuxc, + }, + [gfxd_Cv] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_cv, + }, + [gfxd_Tc] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_tc, + }, + [gfxd_Cyc] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_cyc, + }, + [gfxd_Zs] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_zs, + }, + [gfxd_Ck] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_ck, + }, + [gfxd_Keyscale] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_color, + }, + [gfxd_Keywidth] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_qs48, + }, + [gfxd_Zi] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Rm1] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_rm1, + }, + [gfxd_Rm2] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_rm2, + }, + [gfxd_Sc] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_sc, + }, + [gfxd_Td] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_td, + }, + [gfxd_Tf] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_tf, + }, + [gfxd_Tl] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_tl, + }, + [gfxd_Tt] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_tt, + }, + [gfxd_Tp] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_tp, + }, + [gfxd_Line] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Vtx] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Vtxflag] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Dl] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + [gfxd_Zraw] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_qs1616, + }, +#endif + [gfxd_Dlflag] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_dlf, + }, + [gfxd_Cr] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_cr, + }, + [gfxd_Num] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Fogz] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Fogp] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Mtxptr] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Gm] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_gm, + }, + [gfxd_Mwo_matrix] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_mwo_matrix, + }, + [gfxd_Linewd] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Uctext] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Ucdata] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Size] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x16, + }, + [gfxd_Lookatptr] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Mtxparam] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_mp, + }, + [gfxd_Mtxstack] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_ms, + }, + [gfxd_Mwo_point] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_mwo_point, + }, + [gfxd_Wscale] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_qu016, + }, + [gfxd_Seg] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x8, + }, + [gfxd_Segptr] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Lightsn] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_lightsn, + }, + [gfxd_Numlights] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, + [gfxd_Lightnum] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_lightnum, + }, + [gfxd_Lightptr] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Tcscale] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_qu016, + }, + [gfxd_Switch] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_switch, + }, + [gfxd_St] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_qs105, + }, + [gfxd_Stdelta] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_qs510, + }, + [gfxd_Vtxptr] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Vpptr] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Dram] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x32, + }, + [gfxd_Sftlo] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_sftlo, + }, + [gfxd_Othermodelo] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_othermodelo, + }, + [gfxd_Sfthi] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_sfthi, + }, + [gfxd_Othermodehi] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_othermodehi, + }, + [gfxd_Mw] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_mw, + }, + [gfxd_Mwo] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x16, + }, + [gfxd_Mwo_clip] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_mwo_clip, + }, + [gfxd_Mwo_lightcol] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_mwo_lightcol, + }, + [gfxd_Mv] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_mv, + }, + [gfxd_Mvo] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x16, + }, + [gfxd_Dmem] = + { + .fmt = gfxd_argfmt_u, + .fn = argfn_x16, + }, + [gfxd_Dmaflag] = + { + .fmt = gfxd_argfmt_i, + .fn = argfn_i, + }, +}; diff --git a/ZAPDTR/lib/libgfxd/uc_f3d.c b/ZAPDTR/lib/libgfxd/uc_f3d.c new file mode 100644 index 000000000..946551510 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_f3d.c @@ -0,0 +1,4 @@ +#define uc_name gfxd_f3d +#define F3D_GBI + +#include "uc.c" diff --git a/ZAPDTR/lib/libgfxd/uc_f3db.c b/ZAPDTR/lib/libgfxd/uc_f3db.c new file mode 100644 index 000000000..cd4990412 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_f3db.c @@ -0,0 +1,5 @@ +#define uc_name gfxd_f3db +#define F3D_GBI +#define F3D_BETA + +#include "uc.c" diff --git a/ZAPDTR/lib/libgfxd/uc_f3dex.c b/ZAPDTR/lib/libgfxd/uc_f3dex.c new file mode 100644 index 000000000..2ec70d8ab --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_f3dex.c @@ -0,0 +1,4 @@ +#define uc_name gfxd_f3dex +#define F3DEX_GBI + +#include "uc.c" diff --git a/ZAPDTR/lib/libgfxd/uc_f3dex2.c b/ZAPDTR/lib/libgfxd/uc_f3dex2.c new file mode 100644 index 000000000..9a19c9903 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_f3dex2.c @@ -0,0 +1,4 @@ +#define uc_name gfxd_f3dex2 +#define F3DEX_GBI_2 + +#include "uc.c" diff --git a/ZAPDTR/lib/libgfxd/uc_f3dexb.c b/ZAPDTR/lib/libgfxd/uc_f3dexb.c new file mode 100644 index 000000000..2b5c30a4a --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_f3dexb.c @@ -0,0 +1,5 @@ +#define uc_name gfxd_f3dexb +#define F3DEX_GBI +#define F3D_BETA + +#include "uc.c" diff --git a/ZAPDTR/lib/libgfxd/uc_macrofn.c b/ZAPDTR/lib/libgfxd/uc_macrofn.c new file mode 100644 index 000000000..46d4b4ee8 --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_macrofn.c @@ -0,0 +1,2507 @@ +static inline uint32_t getfield(uint32_t w, int n, int s) +{ + return (w >> s) & (((uint32_t)1 << n) - 1); +} + +static inline int32_t argvi(gfxd_macro_t *m, int idx) +{ + return m->arg[idx].value.i; +} + +static inline uint32_t argvu(gfxd_macro_t *m, int idx) +{ + return m->arg[idx].value.u; +} + +static inline float argvf(gfxd_macro_t *m, int idx) +{ + return m->arg[idx].value.f; +} + +static inline void argi(gfxd_macro_t *m, int idx, const char *name, + int32_t value, int type) +{ + m->arg[idx].type = type; + m->arg[idx].name = name; + m->arg[idx].value.i = value; + m->arg[idx].bad = 0; +} + +static inline void argu(gfxd_macro_t *m, int idx, const char *name, + uint32_t value, int type) +{ + m->arg[idx].type = type; + m->arg[idx].name = name; + m->arg[idx].value.u = value; + m->arg[idx].bad = 0; +} + +static inline void argf(gfxd_macro_t *m, int idx, const char *name, + float value, int type) +{ + m->arg[idx].type = type; + m->arg[idx].name = name; + m->arg[idx].value.f = value; + m->arg[idx].bad = 0; +} + +static inline void badarg(gfxd_macro_t *m, int idx) +{ + m->arg[idx].bad = 1; +} + +UCFUNC int32_t sx(uint32_t n, int bits) +{ + int32_t smin = (int32_t)1 << (bits - 1); + int32_t smax = (int32_t)1 << bits; + int32_t i = n; + if (i < smin) + return i; + else + return i - smax; +} + +UCFUNC int d_Invalid(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_Invalid; + argu(m, 0, "hi", hi, gfxd_Word); + argu(m, 1, "lo", lo, gfxd_Word); + return -1; +} + +UCFUNC int d_DPFillRectangle(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPFillRectangle; + argu(m, 0, "ulx", getfield(lo, 10, 14), gfxd_Coordi); + argu(m, 1, "uly", getfield(lo, 10, 2), gfxd_Coordi); + argu(m, 2, "lrx", getfield(hi, 10, 14), gfxd_Coordi); + argu(m, 3, "lry", getfield(hi, 10, 2), gfxd_Coordi); + return 0; +} + +UCFUNC int d_DPFullSync(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPFullSync; + return 0; +} + +UCFUNC int d_DPLoadSync(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPLoadSync; + return 0; +} + +UCFUNC int d_DPTileSync(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPTileSync; + return 0; +} + +UCFUNC int d_DPPipeSync(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPPipeSync; + return 0; +} + +UCFUNC int c_DPLoadTLUT_pal16(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 6) + return -1; + if (m[0].id != gfxd_DPSetTextureImage + || argvi(&m[0], 0) != G_IM_FMT_RGBA + || argvi(&m[0], 1) != G_IM_SIZ_16b + || argvi(&m[0], 2) != 1) + { + return -1; + } + uint32_t dram = argvu(&m[0], 3); + if (m[1].id != gfxd_DPTileSync) + return -1; + if (m[2].id != gfxd_DPSetTile + || argvi(&m[2], 0) != 0 + || argvi(&m[2], 1) != 0 + || argvi(&m[2], 2) != 0 + || argvu(&m[2], 3) < 0x100 + || argvu(&m[2], 3) % 0x10 != 0 + || argvi(&m[2], 4) != G_TX_LOADTILE + || argvi(&m[2], 5) != 0 + || argvu(&m[2], 6) != 0 + || argvi(&m[2], 7) != 0 + || argvi(&m[2], 8) != 0 + || argvu(&m[2], 9) != 0 + || argvi(&m[2], 10) != 0 + || argvi(&m[2], 11) != 0) + { + return -1; + } + int pal = (argvu(&m[2], 3) - 0x100) / 0x10; + if (m[3].id != gfxd_DPLoadSync) + return -1; + if (m[4].id != gfxd_DPLoadTLUTCmd + || argvi(&m[4], 0) != G_TX_LOADTILE + || argvi(&m[4], 1) != 15) + { + return -1; + } + if (m[5].id != gfxd_DPPipeSync) + return -1; + m->id = gfxd_DPLoadTLUT_pal16; + argi(m, 0, "pal", pal, gfxd_Pal); + argu(m, 1, "dram", dram, gfxd_Tlut); + return 0; +} + +UCFUNC int c_DPLoadTLUT_pal256(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 6) + return -1; + if (m[0].id != gfxd_DPSetTextureImage + || argvi(&m[0], 0) != G_IM_FMT_RGBA + || argvi(&m[0], 1) != G_IM_SIZ_16b + || argvi(&m[0], 2) != 1) + { + return -1; + } + uint32_t dram = argvu(&m[0], 3); + if (m[1].id != gfxd_DPTileSync) + return -1; + if (m[2].id != gfxd_DPSetTile + || argvi(&m[2], 0) != 0 + || argvi(&m[2], 1) != 0 + || argvi(&m[2], 2) != 0 + || argvu(&m[2], 3) != 0x100 + || argvi(&m[2], 4) != G_TX_LOADTILE + || argvi(&m[2], 5) != 0 + || argvu(&m[2], 6) != 0 + || argvi(&m[2], 7) != 0 + || argvi(&m[2], 8) != 0 + || argvu(&m[2], 9) != 0 + || argvi(&m[2], 10) != 0 + || argvi(&m[2], 11) != 0) + { + return -1; + } + if (m[3].id != gfxd_DPLoadSync) + return -1; + if (m[4].id != gfxd_DPLoadTLUTCmd + || argvi(&m[4], 0) != G_TX_LOADTILE + || argvi(&m[4], 1) != 255) + { + return -1; + } + if (m[5].id != gfxd_DPPipeSync) + return -1; + m->id = gfxd_DPLoadTLUT_pal256; + argu(m, 0, "dram", dram, gfxd_Tlut); + return 0; +} + +UCFUNC int c_ltb(gfxd_macro_t *m, int n_macro, int id, int mdxt, int mtmem, + int mrt, int myuv, int m4b) +{ + if (n_macro < 7) + return -1; + if (m[0].id != gfxd_DPSetTextureImage || argvi(&m[0], 2) != 1) + return -1; + g_ifmt_t fmt = argvi(&m[0], 0); + g_isiz_t ldsiz = argvi(&m[0], 1); + uint32_t timg = argvu(&m[0], 3); + if (myuv && fmt != G_IM_FMT_YUV) + return -1; + if (m[1].id != gfxd_DPSetTile + || argvi(&m[1], 0) != fmt + || argvi(&m[1], 1) != ldsiz + || argvi(&m[1], 2) != 0 + || argvi(&m[1], 4) != G_TX_LOADTILE + || argvi(&m[1], 5) != 0) + { + return -1; + } + uint32_t tmem = argvu(&m[1], 3); + unsigned cms = argvu(&m[1], 9); + unsigned cmt = argvu(&m[1], 6); + int masks = argvi(&m[1], 10); + int maskt = argvi(&m[1], 7); + int shifts = argvi(&m[1], 11); + int shiftt = argvi(&m[1], 8); + if (m[2].id != gfxd_DPLoadSync) + return -1; + if (m[3].id != gfxd_DPLoadBlock + || argvi(&m[3], 0) != G_TX_LOADTILE + || argvu(&m[3], 1) != 0 + || argvu(&m[3], 2) != 0) + { + return -1; + } + qu102_t ldlrs = argvu(&m[3], 3); + unsigned lddxt = argvu(&m[3], 4); + if (m[4].id != gfxd_DPPipeSync) + return -1; + if (m[5].id != gfxd_DPSetTile + || argvi(&m[5], 0) != fmt + || G_SIZ_LDSIZ(argvi(&m[5], 1)) != ldsiz + || argvu(&m[5], 3) != tmem + || argvu(&m[5], 6) != cmt + || argvi(&m[5], 7) != maskt + || argvi(&m[5], 8) != shiftt + || argvu(&m[5], 9) != cms + || argvi(&m[5], 10) != masks + || argvi(&m[5], 11) != shifts) + { + return -1; + } + int siz = argvi(&m[5], 1); + int rdline = argvi(&m[5], 2); + int rt = argvi(&m[5], 4); + int pal = argvi(&m[5], 5); + if (m4b && siz != G_IM_SIZ_4b) + return -1; + if (!(mrt && rt != G_TX_RENDERTILE && tmem == 0) + && (tmem != 0) != mtmem) + { + return -1; + } + if ((rt != G_TX_RENDERTILE) != mrt) + return -1; + if (m[6].id != gfxd_DPSetTileSize + || argvi(&m[6], 0) != rt + || argvu(&m[6], 1) != 0 + || argvu(&m[6], 2) != 0 + || (argvu(&m[6], 3) & 3) + || (argvu(&m[6], 4) & 3)) + { + return -1; + } + int width = (argvu(&m[6], 3) >> 2) + 1; + int height = (argvu(&m[6], 4) >> 2) + 1; + unsigned lrs = G_LDBLK_TXL(G_LTB_LRS(width, height, siz)); + unsigned dxt = 0; + if (!mdxt) + dxt = G_DXT(siz, width); + int line; + if (myuv) + line = (width + 7) / 8; + else + line = (width * G_SIZ_LDBITS(siz) + 63) / 64; + if (ldlrs != lrs || lddxt != dxt || rdline != line) + return -1; + m->id = id; + int i = 0; + argu(m, i++, "timg", timg, gfxd_Timg); + if (mtmem) + argu(m, i++, "tmem", tmem, gfxd_Tmem); + if (mrt) + argi(m, i++, "rtile", rt, gfxd_Tile); + argi(m, i++, "fmt", fmt, gfxd_Fmt); + if (!m4b) + argi(m, i++, "siz", siz, gfxd_Siz); + argi(m, i++, "width", width, gfxd_Dim); + argi(m, i++, "height", height, gfxd_Dim); + argi(m, i++, "pal", pal, gfxd_Pal); + argu(m, i++, "cms", cms, gfxd_Cm); + argu(m, i++, "cmt", cmt, gfxd_Cm); + argi(m, i++, "masks", masks, gfxd_Tm); + argi(m, i++, "maskt", maskt, gfxd_Tm); + argi(m, i++, "shifts", shifts, gfxd_Ts); + argi(m, i++, "shiftt", shiftt, gfxd_Ts); + return 0; +} + +UCFUNC int c_DPLoadMultiBlockYuvS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadMultiBlockYuvS, 1, 1, 1, 1, 0); +} + +UCFUNC int c_DPLoadMultiBlockYuv(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadMultiBlockYuv, 0, 1, 1, 1, 0); +} + +UCFUNC int c_DPLoadMultiBlock_4bS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadMultiBlock_4bS, 1, 1, 1, 0, 1); +} + +UCFUNC int c_DPLoadMultiBlock_4b(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadMultiBlock_4b, 0, 1, 1, 0, 1); +} + +UCFUNC int c_DPLoadMultiBlockS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadMultiBlockS, 1, 1, 1, 0, 0); +} + +UCFUNC int c_DPLoadMultiBlock(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadMultiBlock, 0, 1, 1, 0, 0); +} + +UCFUNC int c__DPLoadTextureBlockYuvS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd__DPLoadTextureBlockYuvS, 1, 1, 0, 1, 0); +} + +UCFUNC int c__DPLoadTextureBlockYuv(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd__DPLoadTextureBlockYuv, 0, 1, 0, 1, 0); +} + +UCFUNC int c__DPLoadTextureBlock_4bS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd__DPLoadTextureBlock_4bS, 1, 1, 0, 0, 1); +} + +UCFUNC int c__DPLoadTextureBlock_4b(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd__DPLoadTextureBlock_4b, 0, 1, 0, 0, 1); +} + +UCFUNC int c__DPLoadTextureBlockS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd__DPLoadTextureBlockS, 1, 1, 0, 0, 0); +} + +UCFUNC int c__DPLoadTextureBlock(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd__DPLoadTextureBlock, 0, 1, 0, 0, 0); +} + +UCFUNC int c_DPLoadTextureBlockYuvS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadTextureBlockYuvS, 1, 0, 0, 1, 0); +} + +UCFUNC int c_DPLoadTextureBlockYuv(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadTextureBlockYuv, 0, 0, 0, 1, 0); +} + +UCFUNC int c_DPLoadTextureBlock_4bS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadTextureBlock_4bS, 1, 0, 0, 0, 1); +} + +UCFUNC int c_DPLoadTextureBlock_4b(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadTextureBlock_4b, 0, 0, 0, 0, 1); +} + +UCFUNC int c_DPLoadTextureBlockS(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadTextureBlockS, 1, 0, 0, 0, 0); +} + +UCFUNC int c_DPLoadTextureBlock(gfxd_macro_t *m, int n_macro) +{ + return c_ltb(m, n_macro, gfxd_DPLoadTextureBlock, 0, 0, 0, 0, 0); +} + +UCFUNC int c_ltt(gfxd_macro_t *m, int n_macro, int id, int mtmem, int mrt, + int myuv, int m4b) +{ + if (n_macro < 7) + return -1; + if (m[0].id != gfxd_DPSetTextureImage) + return -1; + g_ifmt_t fmt = argvi(&m[0], 0); + g_isiz_t ldsiz = argvi(&m[0], 1); + int width = argvi(&m[0], 2); + if (m4b) + { + if (ldsiz != G_IM_SIZ_8b) + return -1; + width *= 2; + } + uint32_t timg = argvu(&m[0], 3); + if (myuv && fmt != G_IM_FMT_YUV) + return -1; + if (m[1].id != gfxd_DPSetTile + || argvi(&m[1], 0) != fmt + || argvi(&m[1], 1) != ldsiz + || argvi(&m[1], 4) != G_TX_LOADTILE + || argvi(&m[1], 5) != 0) + { + return -1; + } + int ldline = argvi(&m[1], 2); + uint32_t tmem = argvu(&m[1], 3); + unsigned cms = argvu(&m[1], 9); + unsigned cmt = argvu(&m[1], 6); + int masks = argvi(&m[1], 10); + int maskt = argvi(&m[1], 7); + int shifts = argvi(&m[1], 11); + int shiftt = argvi(&m[1], 8); + if (m[2].id != gfxd_DPLoadSync) + return -1; + if (m[3].id != gfxd_DPLoadTile + || argvi(&m[3], 0) != G_TX_LOADTILE + || (argvu(&m[3], 1) & 1) + || (argvu(&m[3], 2) & 3) + || (argvu(&m[3], 3) & 1) + || (argvu(&m[3], 4) & 3)) + { + return -1; + } + qu102_t lduls = argvu(&m[3], 1); + qu102_t ldult = argvu(&m[3], 2); + qu102_t ldlrs = argvu(&m[3], 3); + qu102_t ldlrt = argvu(&m[3], 4); + if (m[4].id != gfxd_DPPipeSync) + return -1; + if (m[5].id != gfxd_DPSetTile + || argvi(&m[5], 0) != fmt + || argvi(&m[5], 2) != ldline + || argvu(&m[5], 3) != tmem + || argvu(&m[5], 6) != cmt + || argvi(&m[5], 7) != maskt + || argvi(&m[5], 8) != shiftt + || argvu(&m[5], 9) != cms + || argvi(&m[5], 10) != masks + || argvi(&m[5], 11) != shifts) + { + return -1; + } + int siz = argvi(&m[5], 1); + int rt = argvi(&m[5], 4); + int pal = argvi(&m[5], 5); + if (m4b) + { + if (siz != G_IM_SIZ_4b) + return -1; + } + else if (siz != ldsiz) + return -1; + if (!(mrt && rt != G_TX_RENDERTILE && tmem == 0) + && (tmem != 0) != mtmem) + { + return -1; + } + if ((rt != G_TX_RENDERTILE) != mrt) + return -1; + if (m[6].id != gfxd_DPSetTileSize + || argvi(&m[6], 0) != rt + || (argvu(&m[6], 1) & 3) + || (argvu(&m[6], 2) & 3) + || (argvu(&m[6], 3) & 3) + || (argvu(&m[6], 4) & 3)) + { + return -1; + } + unsigned uls = argvu(&m[6], 1) >> 2; + unsigned ult = argvu(&m[6], 2) >> 2; + unsigned lrs = argvu(&m[6], 3) >> 2; + unsigned lrt = argvu(&m[6], 4) >> 2; + int line; + if (myuv) + line = ((lrs - uls + 1) + 7) / 8; + else if (m4b) + line = ((lrs - uls + 1) / 2 + 7) / 8; + else + line = ((lrs - uls + 1) * G_SIZ_LDBITS(siz) + 63) / 64; + if (m4b) + { + if (lduls != qu102(uls) / 2 || ldlrs != qu102(lrs) / 2) + return -1; + } + else if (lduls != qu102(uls) || ldlrs != qu102(lrs)) + return -1; + if (ldult != qu102(ult) || ldlrt != qu102(lrt) || ldline != line) + return -1; + m->id = id; + int i = 0; + argu(m, i++, "timg", timg, gfxd_Timg); + if (mtmem) + argu(m, i++, "tmem", tmem, gfxd_Tmem); + if (mrt) + argi(m, i++, "rtile", rt, gfxd_Tile); + argi(m, i++, "fmt", fmt, gfxd_Fmt); + if (!m4b) + argi(m, i++, "siz", siz, gfxd_Siz); + argi(m, i++, "width", width, gfxd_Dim); + argi(m, i++, "height", 0, gfxd_Dim); + argu(m, i++, "uls", uls, gfxd_Coordi); + argu(m, i++, "ult", ult, gfxd_Coordi); + argu(m, i++, "lrs", lrs, gfxd_Coordi); + argu(m, i++, "lrt", lrt, gfxd_Coordi); + argi(m, i++, "pal", pal, gfxd_Pal); + argu(m, i++, "cms", cms, gfxd_Cm); + argu(m, i++, "cmt", cmt, gfxd_Cm); + argi(m, i++, "masks", masks, gfxd_Tm); + argi(m, i++, "maskt", maskt, gfxd_Tm); + argi(m, i++, "shifts", shifts, gfxd_Ts); + argi(m, i++, "shiftt", shiftt, gfxd_Ts); + return 0; +} + +UCFUNC int c_DPLoadMultiTileYuv(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd_DPLoadMultiTileYuv, 1, 1, 1, 0); +} + +UCFUNC int c_DPLoadMultiTile_4b(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd_DPLoadMultiTile_4b, 1, 1, 0, 1); +} + +UCFUNC int c_DPLoadMultiTile(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd_DPLoadMultiTile, 1, 1, 0, 0); +} + +UCFUNC int c__DPLoadTextureTileYuv(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd__DPLoadTextureTileYuv, 1, 0, 1, 0); +} + +UCFUNC int c__DPLoadTextureTile_4b(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd__DPLoadTextureTile_4b, 1, 0, 0, 1); +} + +UCFUNC int c__DPLoadTextureTile(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd__DPLoadTextureTile, 1, 0, 0, 0); +} + +UCFUNC int c_DPLoadTextureTileYuv(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd_DPLoadTextureTileYuv, 0, 0, 1, 0); +} + +UCFUNC int c_DPLoadTextureTile_4b(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd_DPLoadTextureTile_4b, 0, 0, 0, 1); +} + +UCFUNC int c_DPLoadTextureTile(gfxd_macro_t *m, int n_macro) +{ + return c_ltt(m, n_macro, gfxd_DPLoadTextureTile, 0, 0, 0, 0); +} + +UCFUNC int d_DPLoadBlock(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPLoadBlock; + argi(m, 0, "tile", getfield(lo, 3, 24), gfxd_Tile); + argu(m, 1, "uls", getfield(hi, 12, 12), gfxd_Coordi); + argu(m, 2, "ult", getfield(hi, 12, 0), gfxd_Coordi); + argu(m, 3, "lrs", getfield(lo, 12, 12), gfxd_Coordi); + argu(m, 4, "dxt", getfield(lo, 12, 0), gfxd_Dxt); + if (argvu(m, 3) > G_TX_LDBLK_MAX_TXL) { + badarg(m, 3); + return -1; + } + else { + return 0; + } +} + +UCFUNC int d_DPNoOp(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPNoOp; + return 0; +} + +UCFUNC int d_DPNoOpTag(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + if (lo == 0) + return d_DPNoOp(m, hi, lo); + else + { + m->id = gfxd_DPNoOpTag; + argu(m, 0, "tag", lo, gfxd_Tag); + return 0; + } +} + +UCFUNC int d_DPPipelineMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPPipelineMode; + argu(m, 0, "mode", lo, gfxd_Pm); + return 0; +} + +UCFUNC int d_DPSetBlendColor(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetBlendColor; + argu(m, 0, "r", getfield(lo, 8, 24), gfxd_Colorpart); + argu(m, 1, "g", getfield(lo, 8, 16), gfxd_Colorpart); + argu(m, 2, "b", getfield(lo, 8, 8), gfxd_Colorpart); + argu(m, 3, "a", getfield(lo, 8, 0), gfxd_Colorpart); + return 0; +} + +UCFUNC int d_DPSetEnvColor(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetEnvColor; + argu(m, 0, "r", getfield(lo, 8, 24), gfxd_Colorpart); + argu(m, 1, "g", getfield(lo, 8, 16), gfxd_Colorpart); + argu(m, 2, "b", getfield(lo, 8, 8), gfxd_Colorpart); + argu(m, 3, "a", getfield(lo, 8, 0), gfxd_Colorpart); + return 0; +} + +UCFUNC int d_DPSetFillColor(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetFillColor; + argu(m, 0, "c", lo, gfxd_Color); + return 0; +} + +UCFUNC int d_DPSetFogColor(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetFogColor; + argu(m, 0, "r", getfield(lo, 8, 24), gfxd_Colorpart); + argu(m, 1, "g", getfield(lo, 8, 16), gfxd_Colorpart); + argu(m, 2, "b", getfield(lo, 8, 8), gfxd_Colorpart); + argu(m, 3, "a", getfield(lo, 8, 0), gfxd_Colorpart); + return 0; +} + +UCFUNC int d_DPSetPrimColor(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetPrimColor; + argu(m, 0, "m", getfield(hi, 8, 8), gfxd_Lodfrac); + argu(m, 1, "l", getfield(hi, 8, 0), gfxd_Lodfrac); + argu(m, 2, "r", getfield(lo, 8, 24), gfxd_Colorpart); + argu(m, 3, "g", getfield(lo, 8, 16), gfxd_Colorpart); + argu(m, 4, "b", getfield(lo, 8, 8), gfxd_Colorpart); + argu(m, 5, "a", getfield(lo, 8, 0), gfxd_Colorpart); + return 0; +} + +UCFUNC int d_DPSetColorImage(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetColorImage; + argi(m, 0, "fmt", getfield(hi, 3, 21), gfxd_Fmt); + argi(m, 1, "siz", getfield(hi, 2, 19), gfxd_Siz); + argi(m, 2, "width", getfield(hi, 12, 0) + 1, gfxd_Dim); + argu(m, 3, "cimg", lo, gfxd_Cimg); + return 0; +} + +UCFUNC int d_DPSetDepthImage(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetDepthImage; + argu(m, 0, "zimg", lo, gfxd_Zimg); + return 0; +} + +UCFUNC int d_DPSetTextureImage(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTextureImage; + argi(m, 0, "fmt", getfield(hi, 3, 21), gfxd_Fmt); + argi(m, 1, "siz", getfield(hi, 2, 19), gfxd_Siz); + argi(m, 2, "width", getfield(hi, 12, 0) + 1, gfxd_Dim); + argu(m, 3, "timg", lo, gfxd_Timg); + return 0; +} + +UCFUNC int d_DPSetAlphaCompare(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetAlphaCompare; + argu(m, 0, "mode", lo, gfxd_Ac); + return 0; +} + +UCFUNC int d_DPSetAlphaDither(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetAlphaDither; + argu(m, 0, "mode", lo, gfxd_Ad); + return 0; +} + +UCFUNC int d_DPSetColorDither(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetColorDither; + argu(m, 0, "mode", lo, gfxd_Cd); + return 0; +} + +UCFUNC void cc_unpack(struct cc_mode *m0, struct cc_mode *m1, uint32_t hi, + uint32_t lo) +{ + m0->a = getfield(hi, 4, 20); + m0->b = getfield(lo, 4, 28); + m0->c = getfield(hi, 5, 15); + m0->d = getfield(lo, 3, 15); + m0->Aa = getfield(hi, 3, 12); + m0->Ab = getfield(lo, 3, 12); + m0->Ac = getfield(hi, 3, 9); + m0->Ad = getfield(lo, 3, 9); + m1->a = getfield(hi, 4, 5); + m1->b = getfield(lo, 4, 24); + m1->c = getfield(hi, 5, 0); + m1->d = getfield(lo, 3, 6); + m1->Aa = getfield(lo, 3, 21); + m1->Ab = getfield(lo, 3, 3); + m1->Ac = getfield(lo, 3, 18); + m1->Ad = getfield(lo, 3, 0); +} + +UCFUNC int cc_lookup(const struct cc_mode *m) +{ + struct cc_mode m_norm = *m; + if (m_norm.a > 0x7) m_norm.a = G_CCMUX_0; + if (m_norm.b > 0x7) m_norm.b = G_CCMUX_0; + if (m_norm.c > 0xF) m_norm.c = G_CCMUX_0; + if (m_norm.d > 0x6) m_norm.d = G_CCMUX_0; + m = &m_norm; + int n_presets = sizeof(cc_presets) / sizeof(*cc_presets); + for (int i = 0; i < n_presets; i++) + { + const struct cc_mode *p = &cc_presets[i].mode; + if (m->a == p->a + && m->b == p->b + && m->c == p->c + && m->d == p->d + && m->Aa == p->Aa + && m->Ab == p->Ab + && m->Ac == p->Ac + && m->Ad == p->Ad) + { + return i; + } + } + return -1; +} + +UCFUNC int d_DPSetCombineMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetCombineMode; + struct cc_mode m0; + struct cc_mode m1; + cc_unpack(&m0, &m1, hi, lo); + int p0 = cc_lookup(&m0); + int p1 = cc_lookup(&m1); + argi(m, 0, "mode1", p0, gfxd_Ccpre); + argi(m, 1, "mode2", p1, gfxd_Ccpre); + int ret = 0; + if (p0 == -1) + { + badarg(m, 0); + ret = -1; + } + if (p1 == -1) + { + badarg(m, 1); + ret = -1; + } + return ret; +} + +UCFUNC int d_DPSetCombineLERP(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + struct cc_mode m0; + struct cc_mode m1; + cc_unpack(&m0, &m1, hi, lo); + int p0 = cc_lookup(&m0); + int p1 = cc_lookup(&m1); + if (p0 != -1 && p1 != -1) + return d_DPSetCombineMode(m, hi, lo); + else + { + m->id = gfxd_DPSetCombineLERP; + argi(m, 0, "a0", m0.a, gfxd_Ccmuxa); + argi(m, 1, "b0", m0.b, gfxd_Ccmuxb); + argi(m, 2, "c0", m0.c, gfxd_Ccmuxc); + argi(m, 3, "d0", m0.d, gfxd_Ccmuxd); + argi(m, 4, "Aa0", m0.Aa, gfxd_Acmuxabd); + argi(m, 5, "Ab0", m0.Ab, gfxd_Acmuxabd); + argi(m, 6, "Ac0", m0.Ac, gfxd_Acmuxc); + argi(m, 7, "Ad0", m0.Ad, gfxd_Acmuxabd); + argi(m, 8, "a1", m1.a, gfxd_Ccmuxa); + argi(m, 9, "b1", m1.b, gfxd_Ccmuxb); + argi(m, 10, "c1", m1.c, gfxd_Ccmuxc); + argi(m, 11, "d1", m1.d, gfxd_Ccmuxd); + argi(m, 12, "Aa1", m1.Aa, gfxd_Acmuxabd); + argi(m, 13, "Ab1", m1.Ab, gfxd_Acmuxabd); + argi(m, 14, "Ac1", m1.Ac, gfxd_Acmuxc); + argi(m, 15, "Ad1", m1.Ad, gfxd_Acmuxabd); + return 0; + } +} + +UCFUNC int d_DPSetConvert(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetConvert; + argi(m, 0, "k0", sx(getfield(hi, 9, 13), 9), gfxd_Cv); + argi(m, 1, "k1", sx(getfield(hi, 9, 4), 9), gfxd_Cv); + argi(m, 2, "k2", sx((getfield(hi, 4, 0) << 5) | getfield(lo, 5, 27), 9), + gfxd_Cv); + argi(m, 3, "k3", sx(getfield(lo, 9, 18), 9), gfxd_Cv); + argi(m, 4, "k4", sx(getfield(lo, 9, 9), 9), gfxd_Cv); + argi(m, 5, "k5", sx(getfield(lo, 9, 0), 9), gfxd_Cv); + return 0; +} + +UCFUNC int d_DPSetTextureConvert(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTextureConvert; + argu(m, 0, "mode", lo, gfxd_Tc); + return 0; +} + +UCFUNC int d_DPSetCycleType(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetCycleType; + argu(m, 0, "mode", lo, gfxd_Cyc); + return 0; +} + +UCFUNC int d_DPSetDepthSource(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetDepthSource; + argu(m, 0, "mode", lo, gfxd_Zs); + return 0; +} + +UCFUNC int d_DPSetCombineKey(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetCombineKey; + argu(m, 0, "mode", lo, gfxd_Ck); + return 0; +} + +UCFUNC int d_DPSetKeyGB(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetKeyGB; + argu(m, 0, "cG", getfield(lo, 8, 24), gfxd_Color); + argu(m, 1, "sG", getfield(lo, 8, 16), gfxd_Keyscale); + argi(m, 2, "wG", sx(getfield(hi, 12, 12), 12), gfxd_Keywidth); + argu(m, 3, "cB", getfield(lo, 8, 8), gfxd_Color); + argu(m, 4, "sB", getfield(lo, 8, 0), gfxd_Keyscale); + argi(m, 5, "wB", sx(getfield(hi, 12, 0), 12), gfxd_Keywidth); + return 0; +} + +UCFUNC int d_DPSetKeyR(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetKeyR; + argu(m, 0, "cR", getfield(lo, 8, 8), gfxd_Color); + argu(m, 1, "sR", getfield(lo, 8, 0), gfxd_Keyscale); + argi(m, 2, "wR", sx(getfield(lo, 12, 16), 12), gfxd_Keywidth); + return 0; +} + +UCFUNC int d_DPSetPrimDepth(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetPrimDepth; + argi(m, 0, "z", sx(getfield(lo, 16, 16), 16), gfxd_Zi); + argi(m, 1, "dz", sx(getfield(lo, 16, 0), 16), gfxd_Zi); + return 0; +} + +UCFUNC int d_DPSetRenderMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetRenderMode; + argu(m, 0, "mode1", lo, gfxd_Rm1); + argu(m, 1, "mode2", lo, gfxd_Rm2); + return 0; +} + +UCFUNC int d_DPSetScissor(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetScissor; + argi(m, 0, "mode", getfield(lo, 2, 24), gfxd_Sc); + argu(m, 1, "ulx", getfield(hi, 10, 14), gfxd_Coordi); + argu(m, 2, "uly", getfield(hi, 10, 2), gfxd_Coordi); + argu(m, 3, "lrx", getfield(lo, 10, 14), gfxd_Coordi); + argu(m, 4, "lry", getfield(lo, 10, 2), gfxd_Coordi); + return 0; +} + +UCFUNC int d_DPSetScissorFrac(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + qu102_t ulx = getfield(hi, 12, 12); + qu102_t uly = getfield(hi, 12, 0); + qu102_t lrx = getfield(lo, 12, 12); + qu102_t lry = getfield(lo, 12, 0); + if ((ulx & 3) || (uly & 3) || (lrx & 3) || (lry & 3)) + { + m->id = gfxd_DPSetScissorFrac; + argi(m, 0, "mode", getfield(lo, 2, 24), gfxd_Sc); + argu(m, 1, "ulx", ulx, gfxd_Coordq); + argu(m, 2, "uly", uly, gfxd_Coordq); + argu(m, 3, "lrx", lrx, gfxd_Coordq); + argu(m, 4, "lry", lry, gfxd_Coordq); + return 0; + } + else + return d_DPSetScissor(m, hi, lo); +} + +UCFUNC int d_DPSetTextureDetail(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTextureDetail; + argu(m, 0, "mode", lo, gfxd_Td); + return 0; +} + +UCFUNC int d_DPSetTextureFilter(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTextureFilter; + argu(m, 0, "mode", lo, gfxd_Tf); + return 0; +} + +UCFUNC int d_DPSetTextureLOD(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTextureLOD; + argu(m, 0, "mode", lo, gfxd_Tl); + return 0; +} + +UCFUNC int d_DPSetTextureLUT(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTextureLUT; + argu(m, 0, "mode", lo, gfxd_Tt); + return 0; +} + +UCFUNC int d_DPSetTexturePersp(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTexturePersp; + argu(m, 0, "mode", lo, gfxd_Tp); + return 0; +} + +UCFUNC int d_DPSetTile(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTile; + argi(m, 0, "fmt", getfield(hi, 3, 21), gfxd_Fmt); + argi(m, 1, "siz", getfield(hi, 2, 19), gfxd_Siz); + argi(m, 2, "line", getfield(hi, 9, 9), gfxd_Line); + argu(m, 3, "tmem", getfield(hi, 9, 0), gfxd_Tmem); + argi(m, 4, "tile", getfield(lo, 3, 24), gfxd_Tile); + argi(m, 5, "pal", getfield(lo, 4, 20), gfxd_Pal); + argu(m, 6, "cmt", getfield(lo, 2, 18), gfxd_Cm); + argi(m, 7, "maskt", getfield(lo, 4, 14), gfxd_Tm); + argi(m, 8, "shiftt", getfield(lo, 4, 10), gfxd_Ts); + argu(m, 9, "cms", getfield(lo, 2, 8), gfxd_Cm); + argi(m, 10, "masks", getfield(lo, 4, 4), gfxd_Tm); + argi(m, 11, "shifts", getfield(lo, 4, 0), gfxd_Ts); + return 0; +} + +UCFUNC int d_DPSetTileSize(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetTileSize; + argi(m, 0, "tile", getfield(lo, 3, 24), gfxd_Tile); + argu(m, 1, "uls", getfield(hi, 12, 12), gfxd_Coordq); + argu(m, 2, "ult", getfield(hi, 12, 0), gfxd_Coordq); + argu(m, 3, "lrs", getfield(lo, 12, 12), gfxd_Coordq); + argu(m, 4, "lrt", getfield(lo, 12, 0), gfxd_Coordq); + return 0; +} + +#if defined(F3D_GBI) +UCFUNC int d_SP1Triangle(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SP1Triangle; + int n0 = getfield(lo, 8, 16); + int n1 = getfield(lo, 8, 8); + int n2 = getfield(lo, 8, 0); + argi(m, 0, "v0", n0 / 10, gfxd_Vtx); + argi(m, 1, "v1", n1 / 10, gfxd_Vtx); + argi(m, 2, "v2", n2 / 10, gfxd_Vtx); + argi(m, 3, "flag", getfield(lo, 8, 24), gfxd_Vtxflag); + int ret = 0; + if (n0 % 10 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 10 != 0) + { + badarg(m, 1); + ret = -1; + } + if (n2 % 10 != 0) + { + badarg(m, 2); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI) +UCFUNC int d_SP1Triangle(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SP1Triangle; + int n0 = getfield(lo, 8, 16); + int n1 = getfield(lo, 8, 8); + int n2 = getfield(lo, 8, 0); + argi(m, 0, "v0", n0 / 2, gfxd_Vtx); + argi(m, 1, "v1", n1 / 2, gfxd_Vtx); + argi(m, 2, "v2", n2 / 2, gfxd_Vtx); + argi(m, 3, "flag", 0, gfxd_Vtxflag); + int ret = 0; + if (n0 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + if (n2 % 2 != 0) + { + badarg(m, 2); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_SP1Triangle(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SP1Triangle; + int n0 = getfield(hi, 8, 16); + int n1 = getfield(hi, 8, 8); + int n2 = getfield(hi, 8, 0); + argi(m, 0, "v0", n0 / 2, gfxd_Vtx); + argi(m, 1, "v1", n1 / 2, gfxd_Vtx); + argi(m, 2, "v2", n2 / 2, gfxd_Vtx); + argi(m, 3, "flag", 0, gfxd_Vtxflag); + int ret = 0; + if (n0 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + if (n2 % 2 != 0) + { + badarg(m, 2); + ret = -1; + } + return ret; +} +#endif + +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int d_SP1Quadrangle(gfxd_macro_t *m, uint32_t hi, uint32_t lo); +UCFUNC int d_SP2Triangles(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int n00 = getfield(hi, 8, 16); + int n01 = getfield(hi, 8, 8); + int n02 = getfield(hi, 8, 0); + int n10 = getfield(lo, 8, 16); + int n11 = getfield(lo, 8, 8); + int n12 = getfield(lo, 8, 0); +#if defined(F3DEX_GBI) + if (n00 == n10 && n02 == n11) + return d_SP1Quadrangle(m, hi, lo); +#endif + m->id = gfxd_SP2Triangles; + argi(m, 0, "v00", n00 / 2, gfxd_Vtx); + argi(m, 1, "v01", n01 / 2, gfxd_Vtx); + argi(m, 2, "v02", n02 / 2, gfxd_Vtx); + argi(m, 3, "flag0", 0, gfxd_Vtxflag); + argi(m, 4, "v10", n10 / 2, gfxd_Vtx); + argi(m, 5, "v11", n11 / 2, gfxd_Vtx); + argi(m, 6, "v12", n12 / 2, gfxd_Vtx); + argi(m, 7, "flag1", 0, gfxd_Vtxflag); + int ret = 0; + if (n00 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n01 % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + if (n02 % 2 != 0) + { + badarg(m, 2); + ret = -1; + } + if (n10 % 2 != 0) + { + badarg(m, 4); + ret = -1; + } + if (n11 % 2 != 0) + { + badarg(m, 5); + ret = -1; + } + if (n12 % 2 != 0) + { + badarg(m, 6); + ret = -1; + } + return ret; +} + +UCFUNC int d_SP1Quadrangle(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SP1Quadrangle; + int n00 = getfield(hi, 8, 16); + int n01 = getfield(hi, 8, 8); + int n02 = getfield(hi, 8, 0); + int n10 = getfield(lo, 8, 16); + int n11 = getfield(lo, 8, 8); + int n12 = getfield(lo, 8, 0); + int v00 = n00 / 2; + int v01 = n01 / 2; + int v02 = n02 / 2; + int v10 = n10 / 2; + int v11 = n11 / 2; + int v12 = n12 / 2; + argi(m, 0, "v0", v00, gfxd_Vtx); + argi(m, 1, "v1", v01, gfxd_Vtx); + argi(m, 2, "v2", v11, gfxd_Vtx); + argi(m, 3, "v3", v12, gfxd_Vtx); + argi(m, 4, "flag", 0, gfxd_Vtxflag); + int ret = 0; + if (v00 != v10 || n00 % 2 != 0 || n10 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n01 % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + if (v02 != v11 || n02 % 2 != 0 || n11 % 2 != 0) + { + badarg(m, 2); + ret = -1; + } + if (n12 % 2 != 0) + { + badarg(m, 3); + ret = -1; + } + return ret; +} + +UCFUNC int c_SPBranchLessZraw(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_DPHalf1) + return -1; + uint32_t branchdl = argvu(&m[0], 0); + if (m[1].id != gfxd_BranchZ) + return -1; + int32_t vtx = argvi(&m[1], 0); + int32_t zval = argvi(&m[1], 1); + m->id = gfxd_SPBranchLessZraw; + argu(m, 0, "dl", branchdl, gfxd_Dl); + argi(m, 1, "vtx", vtx, gfxd_Vtx); + argi(m, 2, "zval", zval, gfxd_Zraw); + return 0; +} +#endif + +UCFUNC int d_SPBranchList(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPBranchList; + argu(m, 0, "dl", lo, gfxd_Dl); + return 0; +} + +UCFUNC int c_SPClipRatio(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 4) + return -1; + if (m[0].id != gfxd_MoveWd + || argvi(&m[0], 0) != G_MW_CLIP + || argvu(&m[0], 1) != G_MWO_CLIP_RNX) + { + return -1; + } + uint32_t r = argvu(&m[0], 2); + if (m[1].id != gfxd_MoveWd + || argvi(&m[1], 0) != G_MW_CLIP + || argvu(&m[1], 1) != G_MWO_CLIP_RNY + || argvu(&m[1], 2) != r) + { + return -1; + } + if (m[2].id != gfxd_MoveWd + || argvi(&m[2], 0) != G_MW_CLIP + || argvu(&m[2], 1) != G_MWO_CLIP_RPX + || ((uint32_t)1 << 16) - argvu(&m[2], 2) != r) + { + return -1; + } + if (m[3].id != gfxd_MoveWd + || argvi(&m[3], 0) != G_MW_CLIP + || argvu(&m[3], 1) != G_MWO_CLIP_RPY + || ((uint32_t)1 << 16) - argvu(&m[3], 2) != r) + { + return -1; + } + m->id = gfxd_SPClipRatio; + argi(m, 0, "r", r, gfxd_Cr); + return 0; +} + +#if defined(F3D_GBI) +UCFUNC int d_SPCullDisplayList(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPCullDisplayList; + int n0 = getfield(hi, 24, 0); + int nn = getfield(lo, 16, 0); + argi(m, 0, "v0", n0 / 40, gfxd_Vtx); + argi(m, 1, "vn", nn / 40 - 1, gfxd_Num); + int ret = 0; + if (n0 % 40 != 0) + { + badarg(m, 0); + ret = -1; + } + if (nn % 40 != 0) + { + badarg(m, 1); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int d_SPCullDisplayList(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPCullDisplayList; + int n0 = getfield(hi, 16, 0); + int nn = getfield(lo, 16, 0); + argi(m, 0, "v0", n0 / 2, gfxd_Vtx); + argi(m, 1, "vn", nn / 2, gfxd_Num); + int ret = 0; + if (n0 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (nn % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + return ret; +} +#endif + +UCFUNC int d_SPDisplayList(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPDisplayList; + argu(m, 0, "dl", lo, gfxd_Dl); + return 0; +} + +UCFUNC int d_SPEndDisplayList(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPEndDisplayList; + return 0; +} + +UCFUNC int d_SPFogFactor(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPFogFactor; + argi(m, 0, "fm", sx(getfield(lo, 16, 16), 16), gfxd_Fogz); + argi(m, 1, "fo", sx(getfield(lo, 16, 0), 16), gfxd_Fogz); + return 0; +} + +UCFUNC int d_SPFogPosition(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int x = sx(getfield(lo, 16, 16), 16); + int y = sx(getfield(lo, 16, 0), 16); + if (x == 0) + return d_SPFogFactor(m, hi, lo); + else + { + int d = 128000 / x; + int yd = y * d; + if (yd > 0) + yd += 255; + else if (yd < 0) + yd -= 255; + int min = 500 - yd / 256; + int max = d + min; + + if (min >= 0 && min <= 1000 && max >= 0 && max <= 1000) + { + m->id = gfxd_SPFogPosition; + argi(m, 0, "min", min, gfxd_Fogp); + argi(m, 1, "max", max, gfxd_Fogp); + return 0; + } + else + return d_SPFogFactor(m, hi, lo); + } +} + +#if defined(F3D_GBI) || defined(F3DEX_GBI) +UCFUNC int c_SPForceMatrix(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 4) + return -1; + for (int i = 0; i < 4; i++) + if (m[i].id != gfxd_MoveMem + || argvu(&m[i], 0) != 16 + || argvu(&m[i], 2) != argvu(&m[0], 2) + i * 16) + { + return -1; + } + if (argvi(&m[0], 1) != G_MV_MATRIX_1 + || argvi(&m[1], 1) != G_MV_MATRIX_2 + || argvi(&m[2], 1) != G_MV_MATRIX_3 + || argvi(&m[3], 1) != G_MV_MATRIX_4) + { + return -1; + } + uint32_t mptr = argvu(&m[0], 2); + m->id = gfxd_SPForceMatrix; + argu(m, 0, "mptr", mptr, gfxd_Mtxptr); + return 0; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int c_SPForceMatrix(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_MoveMem + || argvu(&m[0], 0) != sizeof(Mtx) + || argvi(&m[0], 1) != G_MV_MATRIX + || argvu(&m[0], 2) != 0) + { + return -1; + } + uint32_t mptr = argvu(&m[0], 3); + if (m[1].id != gfxd_MoveWd + || argvi(&m[1], 0) != G_MW_FORCEMTX + || argvu(&m[1], 1) != 0 + || argvu(&m[1], 2) != 0x10000) + { + return -1; + } + m->id = gfxd_SPForceMatrix; + argu(m, 0, "mptr", mptr, gfxd_Mtxptr); + return 0; +} +#endif + +UCFUNC int d_SPSetGeometryMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPSetGeometryMode; + argu(m, 0, "mode", lo, gfxd_Gm); + return 0; +} + +UCFUNC int d_SPClearGeometryMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPClearGeometryMode; +#if defined(F3D_GBI) || defined(F3DEX_GBI) + argu(m, 0, "mode", lo, gfxd_Gm); +#elif defined(F3DEX_GBI_2) + argu(m, 0, "mode", getfield(~hi, 24, 0), gfxd_Gm); +#endif + return 0; +} + +#if defined(F3D_GBI) || defined(F3DEX_GBI) +UCFUNC int c_SPLoadGeometryMode(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_SPClearGeometryMode + || argvu(&m[0], 0) != 0xFFFFFFFF + || m[1].id != gfxd_SPSetGeometryMode) + { + return -1; + } + uint32_t mode = argvu(&m[1], 0); + m->id = gfxd_SPLoadGeometryMode; + argu(m, 0, "mode", mode, gfxd_Gm); + return 0; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_SPLoadGeometryMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPLoadGeometryMode; + argu(m, 0, "mode", lo, gfxd_Gm); + return 0; +} +#endif + +#if defined(F3D_GBI) || defined(F3DEX_GBI) +UCFUNC int d_SPInsertMatrix(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPInsertMatrix; + argu(m, 0, "where", getfield(hi, 16, 8), gfxd_Mwo_matrix); + argu(m, 1, "val", lo, gfxd_Word); + return 0; +} +#endif + +#if defined(F3D_GBI) +UCFUNC int d_SPLine3D(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPLine3D; + int n0 = getfield(lo, 8, 16); + int n1 = getfield(lo, 8, 8); + argi(m, 0, "v0", n0 / 10, gfxd_Vtx); + argi(m, 1, "v1", n1 / 10, gfxd_Vtx); + argi(m, 2, "flag", getfield(lo, 8, 24), gfxd_Vtxflag); + int ret = 0; + if (n0 % 10 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 10 != 0) + { + badarg(m, 1); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI) +UCFUNC int d_SPLine3D(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPLine3D; + int n0 = getfield(lo, 8, 16); + int n1 = getfield(lo, 8, 8); + argi(m, 0, "v0", n0 / 2, gfxd_Vtx); + argi(m, 1, "v1", n1 / 2, gfxd_Vtx); + argi(m, 2, "flag", 0, gfxd_Vtxflag); + int ret = 0; + if (n0 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_SPLine3D(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPLine3D; + int n0 = getfield(hi, 8, 16); + int n1 = getfield(hi, 8, 8); + argi(m, 0, "v0", n0 / 2, gfxd_Vtx); + argi(m, 1, "v1", n1 / 2, gfxd_Vtx); + argi(m, 2, "flag", 0, gfxd_Vtxflag); + int ret = 0; + if (n0 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + return ret; +} +#endif + +#if defined(F3D_GBI) +UCFUNC int d_SPLineW3D(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int wd = getfield(lo, 8, 0); + if (wd == 0) + return d_SPLine3D(m, hi, lo); + else + { + m->id = gfxd_SPLineW3D; + int n0 = getfield(lo, 8, 16); + int n1 = getfield(lo, 8, 8); + argi(m, 0, "v0", n0 / 10, gfxd_Vtx); + argi(m, 1, "v1", n1 / 10, gfxd_Vtx); + argi(m, 2, "wd", wd, gfxd_Linewd); + argi(m, 3, "flag", getfield(lo, 8, 24), gfxd_Vtxflag); + int ret = 0; + if (n0 % 10 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 10 != 0) + { + badarg(m, 1); + ret = -1; + } + return ret; + } +} +#elif defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int d_SPLineW3D(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int wd = getfield(hi, 8, 0); + if (wd == 0) + return d_SPLine3D(m, hi, lo); + else + { + m->id = gfxd_SPLineW3D; + int n0 = getfield(hi, 8, 16); + int n1 = getfield(hi, 8, 8); + argi(m, 0, "v0", n0 / 2, gfxd_Vtx); + argi(m, 1, "v1", n1 / 2, gfxd_Vtx); + argi(m, 2, "wd", wd, gfxd_Linewd); + argi(m, 3, "flag", 0, gfxd_Vtxflag); + int ret = 0; + if (n0 % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + if (n1 % 2 != 0) + { + badarg(m, 1); + ret = -1; + } + return ret; + } +} +#endif + +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int c_SPLoadUcode(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_DPHalf1) + return -1; + uint32_t uc_dstart = argvu(&m[0], 0); + if (m[1].id != gfxd_LoadUcode) + return -1; + uint32_t uc_start = argvu(&m[1], 0); + uint32_t uc_dsize = argvu(&m[1], 1); + if (uc_dsize != 0x800) + return -1; + m->id = gfxd_SPLoadUcode; + argu(m, 0, "uc_start", uc_start, gfxd_Uctext); + argu(m, 1, "uc_dstart", uc_dstart, gfxd_Ucdata); + return 0; +} +#endif + +UCFUNC int d_SPLookAtX(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPLookAtX; + argu(m, 0, "l", lo, gfxd_Lookatptr); + return 0; +} + +UCFUNC int d_SPLookAtY(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPLookAtY; + argu(m, 0, "l", lo, gfxd_Lookatptr); + return 0; +} + +UCFUNC int c_SPLookAt(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_SPLookAtX) + return -1; + uint32_t l = argvu(&m[0], 0); + if (m[1].id != gfxd_SPLookAtY || argvu(&m[1], 0) != l + 0x10) + return -1; + m->id = gfxd_SPLookAt; + argu(m, 0, "l", l, gfxd_Lookatptr); + return 0; +} + +#if defined(F3D_GBI) || defined(F3DEX_GBI) +UCFUNC int d_SPMatrix(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPMatrix; + int x = getfield(hi, 16, 0); + argu(m, 0, "matrix", lo, gfxd_Mtxptr); + argi(m, 1, "param", getfield(hi, 8, 16), gfxd_Mtxparam); + if (x != sizeof(Mtx)) + return -1; + else + return 0; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_SPMatrix(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPMatrix; + int x = getfield(hi, 5, 19); + argu(m, 0, "matrix", lo, gfxd_Mtxptr); + argi(m, 1, "param", getfield(hi, 8, 0) ^ G_MTX_PUSH, gfxd_Mtxparam); + if (x != (sizeof(Mtx) - 1) / 8) + return -1; + else + return 0; +} +#endif + +#if defined(F3D_GBI) || (defined(F3D_BETA) && defined(F3DEX_GBI)) +UCFUNC int d_SPModifyVertex(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPModifyVertex; + int offset = getfield(hi, 16, 8); + argi(m, 0, "vtx", offset / 40, gfxd_Vtx); + argu(m, 1, "where", offset % 40, gfxd_Mwo_point); + argu(m, 2, "val", lo, gfxd_Word); + return 0; +} +#elif defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int d_SPModifyVertex(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPModifyVertex; + int vtx = getfield(hi, 16, 0); + argi(m, 0, "vtx", vtx / 2, gfxd_Vtx); + argu(m, 1, "where", getfield(hi, 8, 16), gfxd_Mwo_point); + argu(m, 2, "val", lo, gfxd_Word); + int ret = 0; + if (vtx % 2 != 0) + { + badarg(m, 0); + ret = -1; + } + return ret; +} +#endif + +UCFUNC int d_SPPerspNormalize(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPPerspNormalize; + argu(m, 0, "scale", getfield(lo, 16, 0), gfxd_Wscale); + return 0; +} + +UCFUNC int d_SPPopMatrix(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPPopMatrix; +#if defined(F3D_GBI) || defined(F3DEX_GBI) + argi(m, 0, "param", lo, gfxd_Mtxstack); +#elif defined(F3DEX_GBI_2) + argi(m, 0, "param", G_MTX_MODELVIEW, gfxd_Mtxstack); +#endif + return 0; +} + +#if defined(F3DEX_GBI_2) +UCFUNC int d_SPPopMatrixN(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int len = (getfield(hi, 5, 19) + 1) * 8; + int ofs = getfield(hi, 8, 8) * 8; + int idx = getfield(hi, 8, 0); + int n = lo / sizeof(Mtx); + if (lo % sizeof(Mtx) == 0 + && len == sizeof(Mtx) + && ofs == 0 + && idx == 2 + && n == 1) + { + return d_SPPopMatrix(m, hi, lo); + } + m->id = gfxd_SPPopMatrixN; + argi(m, 0, "param", G_MTX_MODELVIEW, gfxd_Mtxstack); + argi(m, 1, "num", n, gfxd_Num); + int ret = 0; + if (lo % sizeof(Mtx) != 0) + { + badarg(m, 1); + ret = -1; + } + if (len != sizeof(Mtx) || ofs != 0 || idx != 2) + ret = -1; + return ret; +} +#endif + +UCFUNC int d_SPSegment(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPSegment; +#if defined(F3D_GBI) || defined(F3DEX_GBI) + int offset = getfield(hi, 16, 8); +#elif defined(F3DEX_GBI_2) + int offset = getfield(hi, 16, 0); +#endif + argu(m, 0, "seg", offset / 4, gfxd_Seg); + argu(m, 1, "base", lo, gfxd_Segptr); + int ret = 0; + if (offset % 4 != 0) + { + badarg(m, 0); + ret = -1; + } + return ret; +} + +UCFUNC int c_SPSetLightsN(gfxd_macro_t *m, int n_macro, int id, int numlights) +{ + if (n_macro < 2 + numlights) + return -1; + if (m[0].id != gfxd_SPNumLights || argvi(&m[0], 0) != numlights) + return -1; + int a = 1 + numlights; + if (m[a].id != gfxd_SPLight || argvi(&m[a], 1) != a) + return -1; + uint32_t l = argvu(&m[a], 0); + for (int i = 1; i <= numlights; i++) + { + int offset = sizeof(Ambient) + sizeof(Light) * (i - 1); + if (m[i].id != gfxd_SPLight + || argvu(&m[i], 0) != l + offset + || argvi(&m[i], 1) != i) + { + return -1; + } + } + m->id = id; + argu(m, 0, "l", l, gfxd_Lightsn); + return 0; +} + +UCFUNC int c_SPSetLights1(gfxd_macro_t *m, int n_macro) +{ + return c_SPSetLightsN(m, n_macro, gfxd_SPSetLights1, NUMLIGHTS_1); +} + +UCFUNC int c_SPSetLights2(gfxd_macro_t *m, int n_macro) +{ + return c_SPSetLightsN(m, n_macro, gfxd_SPSetLights2, NUMLIGHTS_2); +} + +UCFUNC int c_SPSetLights3(gfxd_macro_t *m, int n_macro) +{ + return c_SPSetLightsN(m, n_macro, gfxd_SPSetLights3, NUMLIGHTS_3); +} + +UCFUNC int c_SPSetLights4(gfxd_macro_t *m, int n_macro) +{ + return c_SPSetLightsN(m, n_macro, gfxd_SPSetLights4, NUMLIGHTS_4); +} + +UCFUNC int c_SPSetLights5(gfxd_macro_t *m, int n_macro) +{ + return c_SPSetLightsN(m, n_macro, gfxd_SPSetLights5, NUMLIGHTS_5); +} + +UCFUNC int c_SPSetLights6(gfxd_macro_t *m, int n_macro) +{ + return c_SPSetLightsN(m, n_macro, gfxd_SPSetLights6, NUMLIGHTS_6); +} + +UCFUNC int c_SPSetLights7(gfxd_macro_t *m, int n_macro) +{ + return c_SPSetLightsN(m, n_macro, gfxd_SPSetLights7, NUMLIGHTS_7); +} + +#if defined(F3D_GBI) || defined(F3DEX_GBI) +UCFUNC int d_SPNumLights(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPNumLights; + argi(m, 0, "n", (lo - 0x80000000) / 32 - 1, gfxd_Numlights); + int ret = 0; + if (lo < 0x80000040 || lo % 32 != 0) + { + badarg(m, 0); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_SPNumLights(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPNumLights; + argi(m, 0, "n", lo / 24, gfxd_Numlights); + int ret = 0; + if (lo < 24 || lo % 24 != 0) + { + badarg(m, 0); + ret = -1; + } + return ret; +} +#endif + +#if defined(F3D_GBI) || defined(F3DEX_GBI) +UCFUNC int d_SPLight(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int n = (getfield(hi, 8, 16) - G_MV_L0) / 2 + 1; + m->id = gfxd_SPLight; + argu(m, 0, "l", lo, gfxd_Lightptr); + argi(m, 1, "n", n, gfxd_Num); + return 0; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_SPLight(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int n = (getfield(hi, 8, 8) * 8 / 24) - 1; + m->id = gfxd_SPLight; + argu(m, 0, "l", lo, gfxd_Lightptr); + argi(m, 1, "n", n, gfxd_Num); + return 0; +} +#endif + +UCFUNC int c_SPLightColor(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_MoveWd + || argvi(&m[0], 0) != G_MW_LIGHTCOL + || argvu(&m[0], 1) % 0x18 != 0 + || argvu(&m[0], 1) > G_MWO_aLIGHT_8) + { + return -1; + } + uint32_t offset = argvu(&m[0], 1); + uint32_t packedcolor = argvu(&m[0], 2); + if (m[1].id != gfxd_MoveWd + || argvi(&m[1], 0) != G_MW_LIGHTCOL + || argvu(&m[1], 1) != offset + 4 + || argvu(&m[1], 2) != packedcolor) + { + return -1; + } + m->id = gfxd_SPLightColor; + argi(m, 0, "n", offset / 0x18 + 1, gfxd_Lightnum); + argu(m, 1, "c", packedcolor, gfxd_Color); + return 0; +} + +UCFUNC int d_SPTexture(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPTexture; + argu(m, 0, "sc", getfield(lo, 16, 16), gfxd_Tcscale); + argu(m, 1, "tc", getfield(lo, 16, 0), gfxd_Tcscale); + argi(m, 2, "level", getfield(hi, 3, 11), gfxd_Num); + argi(m, 3, "tile", getfield(hi, 3, 8), gfxd_Tile); +#if defined(F3D_GBI) || defined(F3DEX_GBI) + argi(m, 4, "on", getfield(hi, 8, 0), gfxd_Switch); +#elif defined(F3DEX_GBI_2) + argi(m, 4, "on", getfield(hi, 7, 1), gfxd_Switch); +#endif + return 0; +} + +UCFUNC int c_SPTextureRectangle(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 3) + return -1; + if (m[0].id != gfxd_TexRect) + return -1; + qu102_t ulx = argvu(&m[0], 0); + qu102_t uly = argvu(&m[0], 1); + qu102_t lrx = argvu(&m[0], 2); + qu102_t lry = argvu(&m[0], 3); + int tile = argvi(&m[0], 4); + if (m[1].id != gfxd_DPHalf1) + return -1; + qs105_t s = sx(getfield(argvu(&m[1], 0), 16, 16), 16); + qs105_t t = sx(getfield(argvu(&m[1], 0), 16, 0), 16); + if (m[2].id != gfxd_DPHalf2) + return -1; + qs510_t dsdx = sx(getfield(argvu(&m[2], 0), 16, 16), 16); + qs510_t dtdy = sx(getfield(argvu(&m[2], 0), 16, 0), 16); + m->id = gfxd_SPTextureRectangle; + argu(m, 0, "ulx", ulx, gfxd_Coordq); + argu(m, 1, "uly", uly, gfxd_Coordq); + argu(m, 2, "lrx", lrx, gfxd_Coordq); + argu(m, 3, "lry", lry, gfxd_Coordq); + argi(m, 4, "tile", tile, gfxd_Tile); + argi(m, 5, "s", s, gfxd_St); + argi(m, 6, "t", t, gfxd_St); + argi(m, 7, "dsdx", dsdx, gfxd_Stdelta); + argi(m, 8, "dtdy", dtdy, gfxd_Stdelta); + return 0; +} + +UCFUNC int c_SPTextureRectangleFlip(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 3) + return -1; + if (m[0].id != gfxd_TexRectFlip) + return -1; + qu102_t ulx = argvu(&m[0], 0); + qu102_t uly = argvu(&m[0], 1); + qu102_t lrx = argvu(&m[0], 2); + qu102_t lry = argvu(&m[0], 3); + int tile = argvi(&m[0], 4); + if (m[1].id != gfxd_DPHalf1) + return -1; + qs105_t s = sx(getfield(argvu(&m[1], 0), 16, 16), 16); + qs105_t t = sx(getfield(argvu(&m[1], 0), 16, 0), 16); + if (m[2].id != gfxd_DPHalf2) + return -1; + qs510_t dsdx = sx(getfield(argvu(&m[2], 0), 16, 16), 16); + qs510_t dtdy = sx(getfield(argvu(&m[2], 0), 16, 0), 16); + m->id = gfxd_SPTextureRectangleFlip; + argu(m, 0, "ulx", ulx, gfxd_Coordq); + argu(m, 1, "uly", uly, gfxd_Coordq); + argu(m, 2, "lrx", lrx, gfxd_Coordq); + argu(m, 3, "lry", lry, gfxd_Coordq); + argi(m, 4, "tile", tile, gfxd_Tile); + argi(m, 5, "s", s, gfxd_St); + argi(m, 6, "t", t, gfxd_St); + argi(m, 7, "dsdx", dsdx, gfxd_Stdelta); + argi(m, 8, "dtdy", dtdy, gfxd_Stdelta); + return 0; +} + +#if defined(F3D_GBI) +UCFUNC int d_SPVertex(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPVertex; + int n = getfield(hi, 4, 20) + 1; + int v0 = getfield(hi, 4, 16); + int size = getfield(hi, 16, 0); + argu(m, 0, "v", lo, gfxd_Vtxptr); + argi(m, 1, "n", n, gfxd_Num); + argi(m, 2, "v0", v0, gfxd_Vtx); + int ret = 0; + if (size != sizeof(Vtx) * n) + { + badarg(m, 1); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI) +UCFUNC int d_SPVertex(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPVertex; + int n = getfield(hi, 6, 10); + int v0 = getfield(hi, 8, 16); + int size = getfield(hi, 10, 0); + argu(m, 0, "v", lo, gfxd_Vtxptr); + argi(m, 1, "n", n, gfxd_Num); + argi(m, 2, "v0", v0 / 2, gfxd_Vtx); + int ret = 0; + if (size != sizeof(Vtx) * n - 1) + { + badarg(m, 1); + ret = -1; + } + if (v0 % 2 != 0) + { + badarg(m, 2); + ret = -1; + } + return ret; +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_SPVertex(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPVertex; + int n = getfield(hi, 8, 12); + int v0 = getfield(hi, 7, 1) - n; + argu(m, 0, "v", lo, gfxd_Vtxptr); + argi(m, 1, "n", n, gfxd_Num); + argi(m, 2, "v0", v0, gfxd_Vtx); + return 0; +} +#endif + +UCFUNC int d_SPViewport(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPViewport; + argu(m, 0, "v", lo, gfxd_Vpptr); + return 0; +} + +UCFUNC int d_DPLoadTLUTCmd(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPLoadTLUTCmd; + argi(m, 0, "tile", getfield(lo, 3, 24), gfxd_Tile); + argi(m, 1, "count", getfield(lo, 10, 14), gfxd_Num); + return 0; +} + +UCFUNC int c_DPLoadTLUT(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 6) + return -1; + if (m[0].id != gfxd_DPSetTextureImage + || argvi(&m[0], 0) != G_IM_FMT_RGBA + || argvi(&m[0], 1) != G_IM_SIZ_16b + || argvi(&m[0], 2) != 1) + { + return -1; + } + uint32_t dram = argvu(&m[0], 3); + if (m[1].id != gfxd_DPTileSync) + return -1; + if (m[2].id != gfxd_DPSetTile + || argvi(&m[2], 0) != 0 + || argvi(&m[2], 1) != 0 + || argvi(&m[2], 2) != 0 + || argvi(&m[2], 4) != G_TX_LOADTILE + || argvi(&m[2], 5) != 0 + || argvu(&m[2], 6) != 0 + || argvi(&m[2], 7) != 0 + || argvi(&m[2], 8) != 0 + || argvu(&m[2], 9) != 0 + || argvi(&m[2], 10) != 0 + || argvi(&m[2], 11) != 0) + { + return -1; + } + uint32_t tmem = argvu(&m[2], 3); + if (m[3].id != gfxd_DPLoadSync) + return -1; + if (m[4].id != gfxd_DPLoadTLUTCmd || argvi(&m[4], 0) != G_TX_LOADTILE) + return -1; + int count = argvi(&m[4], 1) + 1; + if (m[5].id != gfxd_DPPipeSync) + return -1; + m->id = gfxd_DPLoadTLUT; + argi(m, 0, "count", count, gfxd_Num); + argu(m, 1, "tmem", tmem, gfxd_Tmem); + argu(m, 2, "dram", dram, gfxd_Tlut); + return 0; +} + +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int d_BranchZ(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_BranchZ; + int na = getfield(hi, 12, 12); + int nb = getfield(hi, 12, 0); + int32_t zval; + if (lo > 0x7FFFFFFF) + zval = INT32_MIN + (int32_t)(lo & 0x7FFFFFFF); + else + zval = lo; + argi(m, 0, "vtx", nb / 2, gfxd_Vtx); + argi(m, 1, "zval", zval, gfxd_Zraw); + int ret = 0; + if (nb % 2 != 0 || na / 5 != nb / 2 || na % 5 != 0) + { + badarg(m, 0); + ret = -1; + } + return ret; +} +#endif + +UCFUNC int d_DisplayList(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int flag = getfield(hi, 8, 16); + if (flag == 0) + return d_SPDisplayList(m, hi, lo); + else if (flag == 1) + return d_SPBranchList(m, hi, lo); + else + { + m->id = gfxd_DisplayList; + argu(m, 0, "dl", lo, gfxd_Dl); + argi(m, 1, "flag", flag, gfxd_Dlflag); + return 0; + } +} + +UCFUNC int d_DPHalf1(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPHalf1; + argu(m, 0, "hi", lo, gfxd_Word); + return 0; +} + +UCFUNC int d_DPHalf2(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPHalf2; + argu(m, 0, "lo", lo, gfxd_Word); + return 0; +} + +UCFUNC int c_DPWord(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_DPHalf1 || m[1].id != gfxd_DPHalf2) + return -1; + uint32_t wordhi = argvu(&m[0], 0); + uint32_t wordlo = argvu(&m[1], 0); + m->id = gfxd_DPWord; + argu(m, 0, "wordhi", wordhi, gfxd_Word); + argu(m, 1, "wordlo", wordlo, gfxd_Word); + return 0; +} + +UCFUNC int d_DPLoadTile(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPLoadTile; + argi(m, 0, "tile", getfield(lo, 3, 24), gfxd_Tile); + argu(m, 1, "uls", getfield(hi, 12, 12), gfxd_Coordq); + argu(m, 2, "ult", getfield(hi, 12, 0), gfxd_Coordq); + argu(m, 3, "lrs", getfield(lo, 12, 12), gfxd_Coordq); + argu(m, 4, "lrt", getfield(lo, 12, 0), gfxd_Coordq); + return 0; +} + +#if defined(F3DEX_GBI_2) +UCFUNC int d_SPGeometryMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + uint32_t clearbits = getfield(~hi, 24, 0); + uint32_t setbits = lo; + if (clearbits == 0 && setbits != 0) + return d_SPSetGeometryMode(m, hi, lo); + else if (clearbits != 0 && setbits == 0) + return d_SPClearGeometryMode(m, hi, lo); + else if (clearbits == 0x00FFFFFF) + return d_SPLoadGeometryMode(m, hi, lo); + else + { + m->id = gfxd_SPGeometryMode; + argu(m, 0, "c", clearbits, gfxd_Gm); + argu(m, 1, "s", setbits, gfxd_Gm); + return 0; + } +} +#endif + +UCFUNC int d_SPSetOtherMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPSetOtherMode; + int opc = getfield(hi, 8, 24); +#if defined(F3D_GBI) || defined(F3DEX_GBI) + int length = getfield(hi, 8, 0); + int shift = getfield(hi, 8, 8); +#elif defined(F3DEX_GBI_2) + int length = getfield(hi, 8, 0) + 1; + int shift = 32 - (getfield(hi, 8, 8) + length); +#endif + argi(m, 0, "opc", opc, gfxd_Opcode); + argi(m, 1, "sft", shift, gfxd_Sftlo); + argi(m, 2, "len", length, gfxd_Num); + if (opc == G_SETOTHERMODE_H) + argu(m, 3, "mode", lo, gfxd_Othermodehi); + else if (opc == G_SETOTHERMODE_L) + argu(m, 3, "mode", lo, gfxd_Othermodelo); + else + argu(m, 3, "mode", lo, gfxd_Word); + return 0; +} + +UCFUNC int d_SPSetOtherModeLo(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ +#if defined(F3D_GBI) || defined(F3DEX_GBI) + int length = getfield(hi, 8, 0); + int shift = getfield(hi, 8, 8); +#elif defined(F3DEX_GBI_2) + int length = getfield(hi, 8, 0) + 1; + int shift = 32 - (getfield(hi, 8, 8) + length); +#endif + if (shift == G_MDSFT_ALPHACOMPARE && length == G_MDSIZ_ALPHACOMPARE) + return d_DPSetAlphaCompare(m, hi, lo); + else if (shift == G_MDSFT_ZSRCSEL && length == G_MDSIZ_ZSRCSEL) + return d_DPSetDepthSource(m, hi, lo); + else if (shift == G_MDSFT_RENDERMODE && length == G_MDSIZ_RENDERMODE) + return d_DPSetRenderMode(m, hi, lo); + else if (config.emit_ext_macro) + { + m->id = gfxd_SPSetOtherModeLo; + argi(m, 0, "sft", shift, gfxd_Sftlo); + argi(m, 1, "len", length, gfxd_Num); + argu(m, 2, "mode", lo, gfxd_Othermodelo); + return 0; + } + else + return d_SPSetOtherMode(m, hi, lo); +} + +UCFUNC int d_SPSetOtherModeHi(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ +#if defined(F3D_GBI) || defined(F3DEX_GBI) + int length = getfield(hi, 8, 0); + int shift = getfield(hi, 8, 8); +#elif defined(F3DEX_GBI_2) + int length = getfield(hi, 8, 0) + 1; + int shift = 32 - (getfield(hi, 8, 8) + length); +#endif + if (shift == G_MDSFT_ALPHADITHER && length == G_MDSIZ_ALPHADITHER) + return d_DPSetAlphaDither(m, hi, lo); + else if (shift == G_MDSFT_RGBDITHER && length == G_MDSIZ_RGBDITHER) + return d_DPSetColorDither(m, hi, lo); + else if (shift == G_MDSFT_COMBKEY && length == G_MDSIZ_COMBKEY) + return d_DPSetCombineKey(m, hi, lo); + else if (shift == G_MDSFT_TEXTCONV && length == G_MDSIZ_TEXTCONV) + return d_DPSetTextureConvert(m, hi, lo); + else if (shift == G_MDSFT_TEXTFILT && length == G_MDSIZ_TEXTFILT) + return d_DPSetTextureFilter(m, hi, lo); + else if (shift == G_MDSFT_TEXTLUT && length == G_MDSIZ_TEXTLUT) + return d_DPSetTextureLUT(m, hi, lo); + else if (shift == G_MDSFT_TEXTLOD && length == G_MDSIZ_TEXTLOD) + return d_DPSetTextureLOD(m, hi, lo); + else if (shift == G_MDSFT_TEXTDETAIL && length == G_MDSIZ_TEXTDETAIL) + return d_DPSetTextureDetail(m, hi, lo); + else if (shift == G_MDSFT_TEXTPERSP && length == G_MDSIZ_TEXTPERSP) + return d_DPSetTexturePersp(m, hi, lo); + else if (shift == G_MDSFT_CYCLETYPE && length == G_MDSIZ_CYCLETYPE) + return d_DPSetCycleType(m, hi, lo); + else if (shift == G_MDSFT_PIPELINE && length == G_MDSIZ_PIPELINE) + return d_DPPipelineMode(m, hi, lo); + else if (config.emit_ext_macro) + { + m->id = gfxd_SPSetOtherModeHi; + argi(m, 0, "sft", shift, gfxd_Sfthi); + argi(m, 1, "len", length, gfxd_Num); + argu(m, 2, "mode", lo, gfxd_Othermodehi); + return 0; + } + else + return d_SPSetOtherMode(m, hi, lo); +} + +UCFUNC int d_DPSetOtherMode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_DPSetOtherMode; + argu(m, 0, "hi", getfield(hi, 24, 0), gfxd_Othermodehi); + argu(m, 1, "lo", lo, gfxd_Othermodelo); + return 0; +} + +UCFUNC int d_MoveWd(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ +#if defined(F3D_GBI) || defined(F3DEX_GBI) + int index = getfield(hi, 8, 0); + int offset = getfield(hi, 16, 8); +#elif defined(F3DEX_GBI_2) + int index = getfield(hi, 8, 16); + int offset = getfield(hi, 16, 0); +#endif + if (index == G_MW_FOG && offset == G_MWO_FOG) + return d_SPFogPosition(m, hi, lo); +#if !(defined(F3D_BETA) && (defined(F3D_GBI) || defined(F3DEX_GBI))) + else if (index == G_MW_PERSPNORM && offset == 0) + return d_SPPerspNormalize(m, hi, lo); +#endif + else if (index == G_MW_SEGMENT) + return d_SPSegment(m, hi, lo); + else if (index == G_MW_NUMLIGHT && offset == G_MWO_NUMLIGHT) + return d_SPNumLights(m, hi, lo); +#if defined(F3D_GBI) || (defined(F3D_BETA) && defined(F3DEX_GBI)) + else if (index == G_MW_POINTS) + return d_SPModifyVertex(m, hi, lo); +#endif +#if defined(F3D_GBI) || defined(F3DEX_GBI) + else if (index == G_MW_MATRIX) + return d_SPInsertMatrix(m, hi, lo); +#endif + else + { + m->id = gfxd_MoveWd; + argi(m, 0, "index", index, gfxd_Mw); + if (index == G_MW_MATRIX) + argu(m, 1, "offset", offset, gfxd_Mwo_matrix); + else if (index == G_MW_CLIP) + argu(m, 1, "offset", offset, gfxd_Mwo_clip); + else if (index == G_MW_LIGHTCOL) + argu(m, 1, "offset", offset, gfxd_Mwo_lightcol); + else + argu(m, 1, "offset", offset, gfxd_Mwo); + argu(m, 2, "value", lo, gfxd_Word); + } + return 0; +} + +#if defined(F3D_GBI) || defined(F3DEX_GBI) +UCFUNC int d_MoveMem(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int size = getfield(hi, 16, 0); + int index = getfield(hi, 8, 16); + if (size == sizeof(Light) + && index >= G_MV_L0 + && index <= G_MV_L7 + && index % 2 == 0) + { + return d_SPLight(m, hi, lo); + } + else if (size == sizeof(Light) && index == G_MV_LOOKATX) + return d_SPLookAtX(m, hi, lo); + else if (size == sizeof(Light) && index == G_MV_LOOKATY) + return d_SPLookAtY(m, hi, lo); + else if (size == sizeof(Vp) && index == G_MV_VIEWPORT) + return d_SPViewport(m, hi, lo); + else + { + m->id = gfxd_MoveMem; + argu(m, 0, "size", size, gfxd_Size); + argi(m, 1, "index", index, gfxd_Mv); + argu(m, 2, "dram", lo, gfxd_Dram); + return 0; + } +} +#elif defined(F3DEX_GBI_2) +UCFUNC int d_MoveMem(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int size = (getfield(hi, 5, 19) + 1) * 8; + int index = getfield(hi, 8, 0); + int offset = getfield(hi, 8, 8) * 8; + if (size == sizeof(Light) + && index == G_MV_LIGHT + && offset >= G_MVO_L0 + && offset <= G_MVO_L7 + && offset % 0x18 == 0) + { + return d_SPLight(m, hi, lo); + } + else if (size == sizeof(Light) + && index == G_MV_LIGHT + && offset == G_MVO_LOOKATX) + { + return d_SPLookAtX(m, hi, lo); + } + else if (size == sizeof(Light) + && index == G_MV_LIGHT + && offset == G_MVO_LOOKATY) + { + return d_SPLookAtY(m, hi, lo); + } + else if (size == sizeof(Vp) + && index == G_MV_VIEWPORT + && offset == 0) + { + return d_SPViewport(m, hi, lo); + } + else + { + m->id = gfxd_MoveMem; + argu(m, 0, "size", size, gfxd_Size); + argi(m, 1, "index", index, gfxd_Mv); + argu(m, 2, "offset", offset, gfxd_Size); + argu(m, 3, "dram", lo, gfxd_Dram); + return 0; + } +} +#endif + +#if defined(F3DEX_GBI_2) +UCFUNC int d_SPDmaRead(gfxd_macro_t *m, uint32_t hi, uint32_t lo); +UCFUNC int d_SPDmaWrite(gfxd_macro_t *m, uint32_t hi, uint32_t lo); +UCFUNC int d_SPDma_io(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + int flag = getfield(hi, 1, 23); + if (flag == 0) + return d_SPDmaRead(m, hi, lo); + else if (flag == 1) + return d_SPDmaWrite(m, hi, lo); + else + { + m->id = gfxd_SPDma_io; + argi(m, 0, "flag", flag, gfxd_Dmaflag); + argu(m, 1, "dmem", getfield(hi, 10, 13) * 8, gfxd_Dmem); + argu(m, 2, "dram", lo, gfxd_Dram); + argu(m, 3, "size", getfield(hi, 12, 10) + 1, gfxd_Size); + return 0; + } +} + +UCFUNC int d_SPDmaRead(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPDmaRead; + argu(m, 0, "dmem", getfield(hi, 10, 13) * 8, gfxd_Dmem); + argu(m, 1, "dram", lo, gfxd_Dram); + argu(m, 2, "size", getfield(hi, 12, 10) + 1, gfxd_Size); + return 0; +} + +UCFUNC int d_SPDmaWrite(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPDmaWrite; + argu(m, 0, "dmem", getfield(hi, 10, 13) * 8, gfxd_Dmem); + argu(m, 1, "dram", lo, gfxd_Dram); + argu(m, 2, "size", getfield(hi, 12, 10) + 1, gfxd_Size); + return 0; +} +#endif + +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) +UCFUNC int d_LoadUcode(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_LoadUcode; + argu(m, 0, "uc_start", lo, gfxd_Uctext); + argu(m, 1, "uc_dsize", getfield(hi, 16, 0) + 1, gfxd_Size); + return 0; +} + +UCFUNC int c_SPLoadUcodeEx(gfxd_macro_t *m, int n_macro) +{ + if (n_macro < 2) + return -1; + if (m[0].id != gfxd_DPHalf1) + return -1; + uint32_t uc_dstart = argvu(&m[0], 0); + if (m[1].id != gfxd_LoadUcode) + return -1; + uint32_t uc_start = argvu(&m[1], 0); + uint32_t uc_dsize = argvu(&m[1], 1); + m->id = gfxd_SPLoadUcodeEx; + argu(m, 0, "uc_start", uc_start, gfxd_Uctext); + argu(m, 1, "uc_dstart", uc_dstart, gfxd_Ucdata); + argu(m, 2, "uc_dsize", uc_dsize, gfxd_Size); + return 0; +} +#endif + +UCFUNC int d_TexRect(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_TexRect; + argu(m, 0, "ulx", getfield(lo, 12, 12), gfxd_Coordq); + argu(m, 1, "uly", getfield(lo, 12, 0), gfxd_Coordq); + argu(m, 2, "lrx", getfield(hi, 12, 12), gfxd_Coordq); + argu(m, 3, "lry", getfield(hi, 12, 0), gfxd_Coordq); + argi(m, 4, "tile", getfield(lo, 3, 24), gfxd_Tile); + return 0; +} + +UCFUNC int d_TexRectFlip(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_TexRectFlip; + argu(m, 0, "ulx", getfield(lo, 12, 12), gfxd_Coordq); + argu(m, 1, "uly", getfield(lo, 12, 0), gfxd_Coordq); + argu(m, 2, "lrx", getfield(hi, 12, 12), gfxd_Coordq); + argu(m, 3, "lry", getfield(hi, 12, 0), gfxd_Coordq); + argi(m, 4, "tile", getfield(lo, 3, 24), gfxd_Tile); + return 0; +} + +UCFUNC int d_SPNoOp(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_SPNoOp; + return 0; +} + +#if defined(F3DEX_GBI_2) +UCFUNC int d_Special3(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_Special3; + argu(m, 0, "hi", getfield(hi, 24, 0), gfxd_Word); + argu(m, 1, "lo", lo, gfxd_Word); + return 0; +} + +UCFUNC int d_Special2(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_Special2; + argu(m, 0, "hi", getfield(hi, 24, 0), gfxd_Word); + argu(m, 1, "lo", lo, gfxd_Word); + return 0; +} + +UCFUNC int d_Special1(gfxd_macro_t *m, uint32_t hi, uint32_t lo) +{ + m->id = gfxd_Special1; + argu(m, 0, "hi", getfield(hi, 24, 0), gfxd_Word); + argu(m, 1, "lo", lo, gfxd_Word); + return 0; +} +#endif diff --git a/ZAPDTR/lib/libgfxd/uc_macrotbl.c b/ZAPDTR/lib/libgfxd/uc_macrotbl.c new file mode 100644 index 000000000..a8939cede --- /dev/null +++ b/ZAPDTR/lib/libgfxd/uc_macrotbl.c @@ -0,0 +1,1397 @@ +static const gfxd_macro_type_t macro_tbl[] = +{ + [gfxd_Invalid] = + { + .prefix = NULL, + .suffix = NULL, + .opcode = -1, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_Invalid, + }, + [gfxd_DPFillRectangle] = + { + .prefix = NULL, + .suffix = "DPFillRectangle", + .opcode = G_FILLRECT, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_DPFillRectangle, + }, + [gfxd_DPFullSync] = + { + .prefix = NULL, + .suffix = "DPFullSync", + .opcode = G_RDPFULLSYNC, + .n_gfx = 1, + .n_arg = 0, + .disas_fn = d_DPFullSync, + }, + [gfxd_DPLoadSync] = + { + .prefix = NULL, + .suffix = "DPLoadSync", + .opcode = G_RDPLOADSYNC, + .n_gfx = 1, + .n_arg = 0, + .disas_fn = d_DPLoadSync, + }, + [gfxd_DPTileSync] = + { + .prefix = NULL, + .suffix = "DPTileSync", + .opcode = G_RDPTILESYNC, + .n_gfx = 1, + .n_arg = 0, + .disas_fn = d_DPTileSync, + }, + [gfxd_DPPipeSync] = + { + .prefix = NULL, + .suffix = "DPPipeSync", + .opcode = G_RDPPIPESYNC, + .n_gfx = 1, + .n_arg = 0, + .disas_fn = d_DPPipeSync, + }, + [gfxd_DPLoadTLUT_pal16] = + { + .prefix = NULL, + .suffix = "DPLoadTLUT_pal16", + .opcode = G_SETTIMG, + .n_gfx = 6, + .n_arg = 2, + .combine_fn = c_DPLoadTLUT_pal16, + }, + [gfxd_DPLoadTLUT_pal256] = + { + .prefix = NULL, + .suffix = "DPLoadTLUT_pal256", + .opcode = G_SETTIMG, + .n_gfx = 6, + .n_arg = 1, + .combine_fn = c_DPLoadTLUT_pal256, + }, + [gfxd_DPLoadMultiBlockYuvS] = + { + .prefix = NULL, + .suffix = "DPLoadMultiBlockYuvS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 14, + .combine_fn = c_DPLoadMultiBlockYuvS, + .ext = 1, + }, + [gfxd_DPLoadMultiBlockYuv] = + { + .prefix = NULL, + .suffix = "DPLoadMultiBlockYuv", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 14, + .combine_fn = c_DPLoadMultiBlockYuv, + .ext = 1, + }, + [gfxd_DPLoadMultiBlock_4bS] = + { + .prefix = NULL, + .suffix = "DPLoadMultiBlock_4bS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 13, + .combine_fn = c_DPLoadMultiBlock_4bS, + }, + [gfxd_DPLoadMultiBlock_4b] = + { + .prefix = NULL, + .suffix = "DPLoadMultiBlock_4b", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 13, + .combine_fn = c_DPLoadMultiBlock_4b, + }, + [gfxd_DPLoadMultiBlockS] = + { + .prefix = NULL, + .suffix = "DPLoadMultiBlockS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 14, + .combine_fn = c_DPLoadMultiBlockS, + }, + [gfxd_DPLoadMultiBlock] = + { + .prefix = NULL, + .suffix = "DPLoadMultiBlock", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 14, + .combine_fn = c_DPLoadMultiBlock, + }, + [gfxd__DPLoadTextureBlockYuvS] = + { + .prefix = "_", + .suffix = "DPLoadTextureBlockYuvS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 13, + .combine_fn = c__DPLoadTextureBlockYuvS, + .ext = 1, + }, + [gfxd__DPLoadTextureBlockYuv] = + { + .prefix = "_", + .suffix = "DPLoadTextureBlockYuv", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 13, + .combine_fn = c__DPLoadTextureBlockYuv, + .ext = 1, + }, + [gfxd__DPLoadTextureBlock_4bS] = + { + .prefix = "_", + .suffix = "DPLoadTextureBlock_4bS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 12, + .combine_fn = c__DPLoadTextureBlock_4bS, + .ext = 1, + }, + [gfxd__DPLoadTextureBlock_4b] = + { + .prefix = "_", + .suffix = "DPLoadTextureBlock_4b", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 12, + .combine_fn = c__DPLoadTextureBlock_4b, + }, + [gfxd__DPLoadTextureBlockS] = + { + .prefix = "_", + .suffix = "DPLoadTextureBlockS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 13, + .combine_fn = c__DPLoadTextureBlockS, + .ext = 1, + }, + [gfxd__DPLoadTextureBlock] = + { + .prefix = "_", + .suffix = "DPLoadTextureBlock", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 13, + .combine_fn = c__DPLoadTextureBlock, + }, + [gfxd_DPLoadTextureBlockYuvS] = + { + .prefix = NULL, + .suffix = "DPLoadTextureBlockYuvS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 12, + .combine_fn = c_DPLoadTextureBlockYuvS, + .ext = 1, + }, + [gfxd_DPLoadTextureBlockYuv] = + { + .prefix = NULL, + .suffix = "DPLoadTextureBlockYuv", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 12, + .combine_fn = c_DPLoadTextureBlockYuv, + .ext = 1, + }, + [gfxd_DPLoadTextureBlock_4bS] = + { + .prefix = NULL, + .suffix = "DPLoadTextureBlock_4bS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 11, + .combine_fn = c_DPLoadTextureBlock_4bS, + }, + [gfxd_DPLoadTextureBlock_4b] = + { + .prefix = NULL, + .suffix = "DPLoadTextureBlock_4b", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 11, + .combine_fn = c_DPLoadTextureBlock_4b, + }, + [gfxd_DPLoadTextureBlockS] = + { + .prefix = NULL, + .suffix = "DPLoadTextureBlockS", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 12, + .combine_fn = c_DPLoadTextureBlockS, + }, + [gfxd_DPLoadTextureBlock] = + { + .prefix = NULL, + .suffix = "DPLoadTextureBlock", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 12, + .combine_fn = c_DPLoadTextureBlock, + }, + [gfxd_DPLoadMultiTileYuv] = + { + .prefix = NULL, + .suffix = "DPLoadMultiTileYuv", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 18, + .combine_fn = c_DPLoadMultiTileYuv, + .ext = 1, + }, + [gfxd_DPLoadMultiTile_4b] = + { + .prefix = NULL, + .suffix = "DPLoadMultiTile_4b", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 17, + .combine_fn = c_DPLoadMultiTile_4b, + }, + [gfxd_DPLoadMultiTile] = + { + .prefix = NULL, + .suffix = "DPLoadMultiTile", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 18, + .combine_fn = c_DPLoadMultiTile, + }, + [gfxd__DPLoadTextureTileYuv] = + { + .prefix = "_", + .suffix = "DPLoadTextureTileYuv", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 17, + .combine_fn = c__DPLoadTextureTileYuv, + .ext = 1, + }, + [gfxd__DPLoadTextureTile_4b] = + { + .prefix = "_", + .suffix = "DPLoadTextureTile_4b", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 16, + .combine_fn = c__DPLoadTextureTile_4b, + .ext = 1, + }, + [gfxd__DPLoadTextureTile] = + { + .prefix = "_", + .suffix = "DPLoadTextureTile", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 17, + .combine_fn = c__DPLoadTextureTile, + .ext = 1, + }, + [gfxd_DPLoadTextureTileYuv] = + { + .prefix = NULL, + .suffix = "DPLoadTextureTileYuv", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 16, + .combine_fn = c_DPLoadTextureTileYuv, + .ext = 1, + }, + [gfxd_DPLoadTextureTile_4b] = + { + .prefix = NULL, + .suffix = "DPLoadTextureTile_4b", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 15, + .combine_fn = c_DPLoadTextureTile_4b, + }, + [gfxd_DPLoadTextureTile] = + { + .prefix = NULL, + .suffix = "DPLoadTextureTile", + .opcode = G_SETTIMG, + .n_gfx = 7, + .n_arg = 16, + .combine_fn = c_DPLoadTextureTile, + }, + [gfxd_DPLoadBlock] = + { + .prefix = NULL, + .suffix = "DPLoadBlock", + .opcode = G_LOADBLOCK, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_DPLoadBlock, + }, + [gfxd_DPNoOp] = + { + .prefix = NULL, + .suffix = "DPNoOp", + .opcode = G_NOOP, + .n_gfx = 1, + .n_arg = 0, + .alias = gfxd_DPNoOpTag, + }, + [gfxd_DPNoOpTag] = + { + .prefix = NULL, + .suffix = "DPNoOpTag", + .opcode = G_NOOP, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_DPNoOpTag, + }, + [gfxd_DPPipelineMode] = + { + .prefix = NULL, + .suffix = "DPPipelineMode", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetBlendColor] = + { + .prefix = NULL, + .suffix = "DPSetBlendColor", + .opcode = G_SETBLENDCOLOR, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_DPSetBlendColor, + }, + [gfxd_DPSetEnvColor] = + { + .prefix = NULL, + .suffix = "DPSetEnvColor", + .opcode = G_SETENVCOLOR, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_DPSetEnvColor, + }, + [gfxd_DPSetFillColor] = + { + .prefix = NULL, + .suffix = "DPSetFillColor", + .opcode = G_SETFILLCOLOR, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_DPSetFillColor, + }, + [gfxd_DPSetFogColor] = + { + .prefix = NULL, + .suffix = "DPSetFogColor", + .opcode = G_SETFOGCOLOR, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_DPSetFogColor, + }, + [gfxd_DPSetPrimColor] = + { + .prefix = NULL, + .suffix = "DPSetPrimColor", + .opcode = G_SETPRIMCOLOR, + .n_gfx = 1, + .n_arg = 6, + .disas_fn = d_DPSetPrimColor, + }, + [gfxd_DPSetColorImage] = + { + .prefix = NULL, + .suffix = "DPSetColorImage", + .opcode = G_SETCIMG, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_DPSetColorImage, + }, + [gfxd_DPSetDepthImage] = + { + .prefix = NULL, + .suffix = "DPSetDepthImage", + .opcode = G_SETZIMG, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_DPSetDepthImage, + }, + [gfxd_DPSetTextureImage] = + { + .prefix = NULL, + .suffix = "DPSetTextureImage", + .opcode = G_SETTIMG, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_DPSetTextureImage, + }, + [gfxd_DPSetAlphaCompare] = + { + .prefix = NULL, + .suffix = "DPSetAlphaCompare", + .opcode = G_SETOTHERMODE_L, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeLo, + }, + [gfxd_DPSetAlphaDither] = + { + .prefix = NULL, + .suffix = "DPSetAlphaDither", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetColorDither] = + { + .prefix = NULL, + .suffix = "DPSetColorDither", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetCombineMode] = + { + .prefix = NULL, + .suffix = "DPSetCombineMode", + .opcode = G_SETCOMBINE, + .n_gfx = 1, + .n_arg = 2, + .alias = gfxd_DPSetCombineLERP, + }, + [gfxd_DPSetCombineLERP] = + { + .prefix = NULL, + .suffix = "DPSetCombineLERP", + .opcode = G_SETCOMBINE, + .n_gfx = 1, + .n_arg = 16, + .disas_fn = d_DPSetCombineLERP, + }, + [gfxd_DPSetConvert] = + { + .prefix = NULL, + .suffix = "DPSetConvert", + .opcode = G_SETCONVERT, + .n_gfx = 1, + .n_arg = 6, + .disas_fn = d_DPSetConvert, + }, + [gfxd_DPSetTextureConvert] = + { + .prefix = NULL, + .suffix = "DPSetTextureConvert", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetCycleType] = + { + .prefix = NULL, + .suffix = "DPSetCycleType", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetDepthSource] = + { + .prefix = NULL, + .suffix = "DPSetDepthSource", + .opcode = G_SETOTHERMODE_L, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeLo, + }, + [gfxd_DPSetCombineKey] = + { + .prefix = NULL, + .suffix = "DPSetCombineKey", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetKeyGB] = + { + .prefix = NULL, + .suffix = "DPSetKeyGB", + .opcode = G_SETKEYGB, + .n_gfx = 1, + .n_arg = 6, + .disas_fn = d_DPSetKeyGB, + }, + [gfxd_DPSetKeyR] = + { + .prefix = NULL, + .suffix = "DPSetKeyR", + .opcode = G_SETKEYR, + .n_gfx = 1, + .n_arg = 3, + .disas_fn = d_DPSetKeyR, + }, + [gfxd_DPSetPrimDepth] = + { + .prefix = NULL, + .suffix = "DPSetPrimDepth", + .opcode = G_SETPRIMDEPTH, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_DPSetPrimDepth, + }, + [gfxd_DPSetRenderMode] = + { + .prefix = NULL, + .suffix = "DPSetRenderMode", + .opcode = G_SETOTHERMODE_L, + .n_gfx = 1, + .n_arg = 2, + .alias = gfxd_SPSetOtherModeLo, + }, + [gfxd_DPSetScissor] = + { + .prefix = NULL, + .suffix = "DPSetScissor", + .opcode = G_SETSCISSOR, + .n_gfx = 1, + .n_arg = 5, + .alias = gfxd_DPSetScissorFrac, + }, + [gfxd_DPSetScissorFrac] = + { + .prefix = NULL, + .suffix = "DPSetScissorFrac", + .opcode = G_SETSCISSOR, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_DPSetScissorFrac, + }, + [gfxd_DPSetTextureDetail] = + { + .prefix = NULL, + .suffix = "DPSetTextureDetail", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetTextureFilter] = + { + .prefix = NULL, + .suffix = "DPSetTextureFilter", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetTextureLOD] = + { + .prefix = NULL, + .suffix = "DPSetTextureLOD", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetTextureLUT] = + { + .prefix = NULL, + .suffix = "DPSetTextureLUT", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetTexturePersp] = + { + .prefix = NULL, + .suffix = "DPSetTexturePersp", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPSetOtherModeHi, + }, + [gfxd_DPSetTile] = + { + .prefix = NULL, + .suffix = "DPSetTile", + .opcode = G_SETTILE, + .n_gfx = 1, + .n_arg = 12, + .disas_fn = d_DPSetTile, + }, + [gfxd_DPSetTileSize] = + { + .prefix = NULL, + .suffix = "DPSetTileSize", + .opcode = G_SETTILESIZE, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_DPSetTileSize, + }, + [gfxd_SP1Triangle] = + { + .prefix = NULL, + .suffix = "SP1Triangle", + .opcode = G_TRI1, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_SP1Triangle, + }, +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + [gfxd_SP2Triangles] = + { + .prefix = NULL, + .suffix = "SP2Triangles", + .opcode = G_TRI2, + .n_gfx = 1, + .n_arg = 8, + .disas_fn = d_SP2Triangles, + }, +#endif +#if defined(F3DEX_GBI) + [gfxd_SP1Quadrangle] = + { + .prefix = NULL, + .suffix = "SP1Quadrangle", + .opcode = G_TRI2, + .n_gfx = 1, + .n_arg = 5, + .alias = gfxd_SP2Triangles, + }, +#elif defined(F3DEX_GBI_2) + [gfxd_SP1Quadrangle] = + { + .prefix = NULL, + .suffix = "SP1Quadrangle", + .opcode = G_QUAD, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_SP1Quadrangle, + }, +#endif +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + [gfxd_SPBranchLessZraw] = + { + .prefix = NULL, + .suffix = "SPBranchLessZraw", + .opcode = G_RDPHALF_1, + .n_gfx = 2, + .n_arg = 3, + .combine_fn = c_SPBranchLessZraw, + }, +#endif + [gfxd_SPBranchList] = + { + .prefix = NULL, + .suffix = "SPBranchList", + .opcode = G_DL, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_DisplayList, + }, + [gfxd_SPClipRatio] = + { + .prefix = NULL, + .suffix = "SPClipRatio", + .opcode = G_MOVEWORD, + .n_gfx = 4, + .n_arg = 1, + .combine_fn = c_SPClipRatio, + }, + [gfxd_SPCullDisplayList] = + { + .prefix = NULL, + .suffix = "SPCullDisplayList", + .opcode = G_CULLDL, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_SPCullDisplayList, + }, + [gfxd_SPDisplayList] = + { + .prefix = NULL, + .suffix = "SPDisplayList", + .opcode = G_DL, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_DisplayList, + }, + [gfxd_SPEndDisplayList] = + { + .prefix = NULL, + .suffix = "SPEndDisplayList", + .opcode = G_ENDDL, + .n_gfx = 1, + .n_arg = 0, + .disas_fn = d_SPEndDisplayList, + }, + [gfxd_SPFogFactor] = + { + .prefix = NULL, + .suffix = "SPFogFactor", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 2, + .alias = gfxd_SPFogPosition, + }, + [gfxd_SPFogPosition] = + { + .prefix = NULL, + .suffix = "SPFogPosition", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 2, + .alias = gfxd_MoveWd, + }, +#if defined(F3D_GBI) || defined(F3DEX_GBI) + [gfxd_SPForceMatrix] = + { + .prefix = NULL, + .suffix = "SPForceMatrix", + .opcode = G_MOVEMEM, + .n_gfx = 4, + .n_arg = 1, + .combine_fn = c_SPForceMatrix, + }, + [gfxd_SPSetGeometryMode] = + { + .prefix = NULL, + .suffix = "SPSetGeometryMode", + .opcode = G_SETGEOMETRYMODE, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_SPSetGeometryMode, + }, + [gfxd_SPClearGeometryMode] = + { + .prefix = NULL, + .suffix = "SPClearGeometryMode", + .opcode = G_CLEARGEOMETRYMODE, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_SPClearGeometryMode, + }, + [gfxd_SPLoadGeometryMode] = + { + .prefix = NULL, + .suffix = "SPLoadGeometryMode", + .opcode = G_CLEARGEOMETRYMODE, + .n_gfx = 2, + .n_arg = 1, + .combine_fn = c_SPLoadGeometryMode, + }, +#elif defined(F3DEX_GBI_2) + [gfxd_SPForceMatrix] = + { + .prefix = NULL, + .suffix = "SPForceMatrix", + .opcode = G_MOVEMEM, + .n_gfx = 2, + .n_arg = 1, + .combine_fn = c_SPForceMatrix, + }, + [gfxd_SPSetGeometryMode] = + { + .prefix = NULL, + .suffix = "SPSetGeometryMode", + .opcode = G_GEOMETRYMODE, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPGeometryMode, + }, + [gfxd_SPClearGeometryMode] = + { + .prefix = NULL, + .suffix = "SPClearGeometryMode", + .opcode = G_GEOMETRYMODE, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPGeometryMode, + }, + [gfxd_SPLoadGeometryMode] = + { + .prefix = NULL, + .suffix = "SPLoadGeometryMode", + .opcode = G_GEOMETRYMODE, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPGeometryMode, + }, +#endif +#if defined(F3D_GBI) || defined(F3DEX_GBI) + [gfxd_SPInsertMatrix] = + { + .prefix = NULL, + .suffix = "SPInsertMatrix", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 2, + .alias = gfxd_MoveWd, + }, +#endif + [gfxd_SPLine3D] = + { + .prefix = NULL, + .suffix = "SPLine3D", + .opcode = G_LINE3D, + .n_gfx = 1, + .n_arg = 3, + .alias = gfxd_SPLineW3D, + }, + [gfxd_SPLineW3D] = + { + .prefix = NULL, + .suffix = "SPLineW3D", + .opcode = G_LINE3D, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_SPLineW3D, + }, +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + [gfxd_SPLoadUcode] = + { + .prefix = NULL, + .suffix = "SPLoadUcode", + .opcode = G_RDPHALF_1, + .n_gfx = 2, + .n_arg = 2, + .combine_fn = c_SPLoadUcode, + }, +#endif + [gfxd_SPLookAtX] = + { + .prefix = NULL, + .suffix = "SPLookAtX", + .opcode = G_MOVEMEM, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_MoveMem, + }, + [gfxd_SPLookAtY] = + { + .prefix = NULL, + .suffix = "SPLookAtY", + .opcode = G_MOVEMEM, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_MoveMem, + }, + [gfxd_SPLookAt] = + { + .prefix = NULL, + .suffix = "SPLookAt", + .opcode = G_MOVEMEM, + .n_gfx = 2, + .n_arg = 1, + .combine_fn = c_SPLookAt, + }, + [gfxd_SPMatrix] = + { + .prefix = NULL, + .suffix = "SPMatrix", + .opcode = G_MTX, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_SPMatrix, + }, +#if defined(F3D_GBI) || (defined(F3D_BETA) && defined(F3DEX_GBI)) + [gfxd_SPModifyVertex] = + { + .prefix = NULL, + .suffix = "SPModifyVertex", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 3, + .alias = gfxd_MoveWd, + }, +#elif defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + [gfxd_SPModifyVertex] = + { + .prefix = NULL, + .suffix = "SPModifyVertex", + .opcode = G_MODIFYVTX, + .n_gfx = 1, + .n_arg = 3, + .disas_fn = d_SPModifyVertex, + }, +#endif +#if defined(F3D_BETA) && (defined(F3D_GBI) || defined(F3DEX_GBI)) + [gfxd_SPPerspNormalize] = + { + .prefix = NULL, + .suffix = "SPPerspNormalize", + .opcode = G_PERSPNORM, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_SPPerspNormalize, + }, +#else + [gfxd_SPPerspNormalize] = + { + .prefix = NULL, + .suffix = "SPPerspNormalize", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_MoveWd, + }, +#endif +#if defined(F3D_GBI) || defined(F3DEX_GBI) + [gfxd_SPPopMatrix] = + { + .prefix = NULL, + .suffix = "SPPopMatrix", + .opcode = G_POPMTX, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_SPPopMatrix, + }, +#elif defined(F3DEX_GBI_2) + [gfxd_SPPopMatrix] = + { + .prefix = NULL, + .suffix = "SPPopMatrix", + .opcode = G_POPMTX, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_SPPopMatrixN, + }, + [gfxd_SPPopMatrixN] = + { + .prefix = NULL, + .suffix = "SPPopMatrixN", + .opcode = G_POPMTX, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_SPPopMatrixN, + }, +#endif + [gfxd_SPSegment] = + { + .prefix = NULL, + .suffix = "SPSegment", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 2, + .alias = gfxd_MoveWd, + }, + [gfxd_SPSetLights1] = + { + .prefix = NULL, + .suffix = "SPSetLights1", + .opcode = G_MOVEWORD, + .n_gfx = 3, + .n_arg = 1, + .combine_fn = c_SPSetLights1, + }, + [gfxd_SPSetLights2] = + { + .prefix = NULL, + .suffix = "SPSetLights2", + .opcode = G_MOVEWORD, + .n_gfx = 4, + .n_arg = 1, + .combine_fn = c_SPSetLights2, + }, + [gfxd_SPSetLights3] = + { + .prefix = NULL, + .suffix = "SPSetLights3", + .opcode = G_MOVEWORD, + .n_gfx = 5, + .n_arg = 1, + .combine_fn = c_SPSetLights3, + }, + [gfxd_SPSetLights4] = + { + .prefix = NULL, + .suffix = "SPSetLights4", + .opcode = G_MOVEWORD, + .n_gfx = 6, + .n_arg = 1, + .combine_fn = c_SPSetLights4, + }, + [gfxd_SPSetLights5] = + { + .prefix = NULL, + .suffix = "SPSetLights5", + .opcode = G_MOVEWORD, + .n_gfx = 7, + .n_arg = 1, + .combine_fn = c_SPSetLights5, + }, + [gfxd_SPSetLights6] = + { + .prefix = NULL, + .suffix = "SPSetLights6", + .opcode = G_MOVEWORD, + .n_gfx = 8, + .n_arg = 1, + .combine_fn = c_SPSetLights6, + }, + [gfxd_SPSetLights7] = + { + .prefix = NULL, + .suffix = "SPSetLights7", + .opcode = G_MOVEWORD, + .n_gfx = 9, + .n_arg = 1, + .combine_fn = c_SPSetLights7, + }, + [gfxd_SPNumLights] = + { + .prefix = NULL, + .suffix = "SPNumLights", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_MoveWd, + }, + [gfxd_SPLight] = + { + .prefix = NULL, + .suffix = "SPLight", + .opcode = G_MOVEMEM, + .n_gfx = 1, + .n_arg = 2, + .alias = gfxd_MoveMem, + }, + [gfxd_SPLightColor] = + { + .prefix = NULL, + .suffix = "SPLightColor", + .opcode = G_MOVEWORD, + .n_gfx = 2, + .n_arg = 2, + .combine_fn = c_SPLightColor, + }, + [gfxd_SPTexture] = + { + .prefix = NULL, + .suffix = "SPTexture", + .opcode = G_TEXTURE, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_SPTexture, + }, + [gfxd_SPTextureRectangle] = + { + .prefix = NULL, + .suffix = "SPTextureRectangle", + .opcode = G_TEXRECT, + .n_gfx = 3, + .n_arg = 9, + .combine_fn = c_SPTextureRectangle, + }, + [gfxd_SPTextureRectangleFlip] = + { + .prefix = NULL, + .suffix = "SPTextureRectangleFlip", + .opcode = G_TEXRECTFLIP, + .n_gfx = 3, + .n_arg = 9, + .combine_fn = c_SPTextureRectangleFlip, + }, + [gfxd_SPVertex] = + { + .prefix = NULL, + .suffix = "SPVertex", + .opcode = G_VTX, + .n_gfx = 1, + .n_arg = 3, + .disas_fn = d_SPVertex, + }, + [gfxd_SPViewport] = + { + .prefix = NULL, + .suffix = "SPViewport", + .opcode = G_MOVEMEM, + .n_gfx = 1, + .n_arg = 1, + .alias = gfxd_MoveMem, + }, + [gfxd_DPLoadTLUTCmd] = + { + .prefix = NULL, + .suffix = "DPLoadTLUTCmd", + .opcode = G_LOADTLUT, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_DPLoadTLUTCmd, + }, + [gfxd_DPLoadTLUT] = + { + .prefix = NULL, + .suffix = "DPLoadTLUT", + .opcode = G_SETTIMG, + .n_gfx = 6, + .n_arg = 3, + .combine_fn = c_DPLoadTLUT, + }, +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + [gfxd_BranchZ] = + { + .prefix = NULL, + .suffix = "BranchZ", + .opcode = G_BRANCH_Z, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_BranchZ, + .ext = 1, + }, +#endif + [gfxd_DisplayList] = + { + .prefix = NULL, + .suffix = "DisplayList", + .opcode = G_DL, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_DisplayList, + .ext = 1, + }, + [gfxd_DPHalf1] = + { + .prefix = NULL, + .suffix = "DPHalf1", + .opcode = G_RDPHALF_1, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_DPHalf1, + .ext = 1, + }, + [gfxd_DPHalf2] = + { + .prefix = NULL, + .suffix = "DPHalf2", + .opcode = G_RDPHALF_2, + .n_gfx = 1, + .n_arg = 1, + .disas_fn = d_DPHalf2, + .ext = 1, + }, + [gfxd_DPWord] = + { + .prefix = NULL, + .suffix = "DPWord", + .opcode = G_RDPHALF_1, + .n_gfx = 2, + .n_arg = 2, + .combine_fn = c_DPWord, + }, + [gfxd_DPLoadTile] = + { + .prefix = NULL, + .suffix = "DPLoadTile", + .opcode = G_LOADTILE, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_DPLoadTile, + }, +#if defined(F3DEX_GBI_2) + [gfxd_SPGeometryMode] = + { + .prefix = NULL, + .suffix = "SPGeometryMode", + .opcode = G_GEOMETRYMODE, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_SPGeometryMode, + }, +#endif + [gfxd_SPSetOtherMode] = + { + .prefix = NULL, + .suffix = "SPSetOtherMode", + .opcode = -1, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_SPSetOtherMode, + }, + [gfxd_SPSetOtherModeLo] = + { + .prefix = NULL, + .suffix = "SPSetOtherModeLo", + .opcode = G_SETOTHERMODE_L, + .n_gfx = 1, + .n_arg = 3, + .disas_fn = d_SPSetOtherModeLo, + .ext = 1, + }, + [gfxd_SPSetOtherModeHi] = + { + .prefix = NULL, + .suffix = "SPSetOtherModeHi", + .opcode = G_SETOTHERMODE_H, + .n_gfx = 1, + .n_arg = 3, + .disas_fn = d_SPSetOtherModeHi, + .ext = 1, + }, + [gfxd_DPSetOtherMode] = + { + .prefix = NULL, + .suffix = "DPSetOtherMode", + .opcode = G_RDPSETOTHERMODE, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_DPSetOtherMode, + }, + [gfxd_MoveWd] = + { + .prefix = NULL, + .suffix = "MoveWd", + .opcode = G_MOVEWORD, + .n_gfx = 1, + .n_arg = 3, + .disas_fn = d_MoveWd, + }, +#if defined(F3D_GBI) || defined(F3DEX_GBI) + [gfxd_MoveMem] = + { + .prefix = NULL, + .suffix = "MoveMem", + .opcode = G_MOVEMEM, + .n_gfx = 1, + .n_arg = 3, + .disas_fn = d_MoveMem, + .ext = 1, + }, +#elif defined(F3DEX_GBI_2) + [gfxd_MoveMem] = + { + .prefix = NULL, + .suffix = "MoveMem", + .opcode = G_MOVEMEM, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_MoveMem, + .ext = 1, + }, +#endif +#if defined(F3DEX_GBI_2) + [gfxd_SPDma_io] = + { + .prefix = NULL, + .suffix = "SPDma_io", + .opcode = G_DMA_IO, + .n_gfx = 1, + .n_arg = 4, + .disas_fn = d_SPDma_io, + }, + [gfxd_SPDmaRead] = + { + .prefix = NULL, + .suffix = "SPDmaRead", + .opcode = G_DMA_IO, + .n_gfx = 1, + .n_arg = 3, + .alias = gfxd_SPDma_io, + }, + [gfxd_SPDmaWrite] = + { + .prefix = NULL, + .suffix = "SPDmaWrite", + .opcode = G_DMA_IO, + .n_gfx = 1, + .n_arg = 3, + .alias = gfxd_SPDma_io, + }, +#endif +#if defined(F3DEX_GBI) || defined(F3DEX_GBI_2) + [gfxd_LoadUcode] = + { + .prefix = NULL, + .suffix = "LoadUcode", + .opcode = G_LOAD_UCODE, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_LoadUcode, + }, + [gfxd_SPLoadUcodeEx] = + { + .prefix = NULL, + .suffix = "SPLoadUcodeEx", + .opcode = G_RDPHALF_1, + .n_gfx = 2, + .n_arg = 3, + .combine_fn = c_SPLoadUcodeEx, + }, +#endif + [gfxd_TexRect] = + { + .prefix = NULL, + .suffix = "TexRect", + .opcode = G_TEXRECT, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_TexRect, + .ext = 1, + }, + [gfxd_TexRectFlip] = + { + .prefix = NULL, + .suffix = "TexRectFlip", + .opcode = G_TEXRECTFLIP, + .n_gfx = 1, + .n_arg = 5, + .disas_fn = d_TexRectFlip, + .ext = 1, + }, + [gfxd_SPNoOp] = + { + .prefix = NULL, + .suffix = "SPNoOp", + .opcode = G_SPNOOP, + .n_gfx = 1, + .n_arg = 0, + .disas_fn = d_SPNoOp, + }, +#if defined(F3DEX_GBI_2) + [gfxd_Special3] = + { + .prefix = NULL, + .suffix = "Special3", + .opcode = G_SPECIAL_3, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_Special3, + .ext = 1, + }, + [gfxd_Special2] = + { + .prefix = NULL, + .suffix = "Special2", + .opcode = G_SPECIAL_2, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_Special2, + .ext = 1, + }, + [gfxd_Special1] = + { + .prefix = NULL, + .suffix = "Special1", + .opcode = G_SPECIAL_1, + .n_gfx = 1, + .n_arg = 2, + .disas_fn = d_Special1, + .ext = 1, + }, +#endif +}; diff --git a/ZAPDTR/lib/tinyxml2/tinyxml2.cpp b/ZAPDTR/lib/tinyxml2/tinyxml2.cpp new file mode 100644 index 000000000..23a3a6ce4 --- /dev/null +++ b/ZAPDTR/lib/tinyxml2/tinyxml2.cpp @@ -0,0 +1,2837 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml2.h" + +#include // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +#else +# include +# include +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + + +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::TransferTo( StrPair* other ) +{ + if ( this == other ) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT( other != 0 ); + TIXMLASSERT( other->_flags == 0 ); + TIXMLASSERT( other->_start == 0 ); + TIXMLASSERT( other->_end == 0 ); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + delete [] _start; + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + TIXMLASSERT( str ); + Reset(); + size_t len = strlen( str ); + TIXMLASSERT( _start == 0 ); + _start = new char[ len+1 ]; + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( endTag && *endTag ); + TIXMLASSERT(curLineNumPtr); + + char* start = p; + char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } else if (*p == '\n') { + ++(*curLineNumPtr); + } + ++p; + TIXMLASSERT( p ); + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + if ( !p || !(*p) ) { + return 0; + } + if ( !XMLUtil::IsNameStartChar( *p ) ) { + return 0; + } + + char* const start = p; + ++p; + while ( *p && XMLUtil::IsNameChar( *p ) ) { + ++p; + } + + Set( start, p, 0 ); + return p; +} + + +void StrPair::CollapseWhitespace() +{ + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start, 0 ); + + if ( *_start ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p, 0 ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } + } + else { + bool entityFound = false; + for( int i = 0; i < NUM_ENTITIES; ++i ) { + const Entity& entity = entities[i]; + if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 + && *( p + entity.length + 1 ) == ';' ) { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if ( !entityFound ) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT( _start ); + return _start; +} + + + + +// --------- XMLUtil ----------- // + +const char* XMLUtil::writeBoolTrue = "true"; +const char* XMLUtil::writeBoolFalse = "false"; + +void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) +{ + static const char* defTrue = "true"; + static const char* defFalse = "false"; + + writeBoolTrue = (writeTrue) ? writeTrue : defTrue; + writeBoolFalse = (writeFalse) ? writeFalse : defFalse; +} + + +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( bom ); + *bom = false; + const unsigned char* pu = reinterpret_cast(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + TIXMLASSERT( p ); + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs are annotated with carefully designed comments + // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc + switch (*length) { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT( false ); + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + const char* q = p+3; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != 'x' ) { + unsigned int digit = 0; + + if ( *q >= '0' && *q <= '9' ) { + digit = *q - '0'; + } + else if ( *q >= 'a' && *q <= 'f' ) { + digit = *q - 'a' + 10; + } + else if ( *q >= 'A' && *q <= 'F' ) { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT( digit < 16 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p+2; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit < 10 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT( mult <= UINT_MAX / 10 ); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); +} + +/* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 +*/ +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); +} + + +void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize) +{ + // horrible syntax trick to make the compiler happy about %lld + TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v); +} + + +bool XMLUtil::ToInt( const char* str, int* value ) +{ + if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) +{ + if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + if ( StringEqual( str, "true" ) ) { + *value = true; + return true; + } + else if ( StringEqual( str, "false" ) ) { + *value = false; + return true; + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToInt64(const char* str, int64_t* value) +{ + long long v = 0; // horrible syntax trick to make the compiler happy about %lld + if (TIXML_SSCANF(str, "%lld", &v) == 1) { + *value = (int64_t)v; + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( p ); + char* const start = p; + int const startLine = _parseCurLineNum; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += xmlHeaderLen; + } + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += commentHeaderLen; + } + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { + XMLText* text = CreateUnlinkedNode( _textPool ); + returnNode = text; + returnNode->_parseLineNum = _parseCurLineNum; + p += cdataHeaderLen; + text->SetCData( true ); + } + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += dtdHeaderLen; + } + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _elementPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += elementHeaderLen; + } + else { + returnNode = CreateUnlinkedNode( _textPool ); + returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character + p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; + } + + TIXMLASSERT( returnNode ); + TIXMLASSERT( p ); + *node = returnNode; + return p; +} + + +bool XMLDocument::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLNode ----------- // + +XMLNode::XMLNode( XMLDocument* doc ) : + _document( doc ), + _parent( 0 ), + _value(), + _parseLineNum( 0 ), + _firstChild( 0 ), _lastChild( 0 ), + _prev( 0 ), _next( 0 ), + _userData( 0 ), + _memPool( 0 ) +{ +} + + +XMLNode::~XMLNode() +{ + DeleteChildren(); + if ( _parent ) { + _parent->Unlink( this ); + } +} + +const char* XMLNode::Value() const +{ + // Edge case: XMLDocuments don't have a Value. Return null. + if ( this->ToDocument() ) + return 0; + return _value.GetStr(); +} + +void XMLNode::SetValue( const char* str, bool staticMem ) +{ + if ( staticMem ) { + _value.SetInternedStr( str ); + } + else { + _value.SetStr( str ); + } +} + +XMLNode* XMLNode::DeepClone(XMLDocument* target) const +{ + XMLNode* clone = this->ShallowClone(target); + if (!clone) return 0; + + for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { + XMLNode* childClone = child->DeepClone(target); + TIXMLASSERT(childClone); + clone->InsertEndChild(childClone); + } + return clone; +} + +void XMLNode::DeleteChildren() +{ + while( _firstChild ) { + TIXMLASSERT( _lastChild ); + DeleteChild( _firstChild ); + } + _firstChild = _lastChild = 0; +} + + +void XMLNode::Unlink( XMLNode* child ) +{ + TIXMLASSERT( child ); + TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); + if ( child == _firstChild ) { + _firstChild = _firstChild->_next; + } + if ( child == _lastChild ) { + _lastChild = _lastChild->_prev; + } + + if ( child->_prev ) { + child->_prev->_next = child->_next; + } + if ( child->_next ) { + child->_next->_prev = child->_prev; + } + child->_next = 0; + child->_prev = 0; + child->_parent = 0; +} + + +void XMLNode::DeleteChild( XMLNode* node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( node->_document == _document ); + TIXMLASSERT( node->_parent == this ); + Unlink( node ); + TIXMLASSERT(node->_prev == 0); + TIXMLASSERT(node->_next == 0); + TIXMLASSERT(node->_parent == 0); + DeleteNode( node ); +} + + +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _lastChild ) { + TIXMLASSERT( _firstChild ); + TIXMLASSERT( _lastChild->_next == 0 ); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT( _firstChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_prev == 0 ); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT( _lastChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + + TIXMLASSERT( afterThis ); + + if ( afterThis->_parent != this ) { + TIXMLASSERT( false ); + return 0; + } + if ( afterThis == addThis ) { + // Current state: BeforeThis -> AddThis -> OneAfterAddThis + // Now AddThis must disappear from it's location and then + // reappear between BeforeThis and OneAfterAddThis. + // So just leave it where it is. + return addThis; + } + + if ( afterThis->_next == 0 ) { + // The last node or the only node. + return InsertEndChild( addThis ); + } + InsertChildPreamble( addThis ); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; +} + + + + +const XMLElement* XMLNode::FirstChildElement( const char* name ) const +{ + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::LastChildElement( const char* name ) const +{ + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _next; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _prev; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // + // + // + // With a special case: + // + // + // + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + XMLDocument::DepthTracker tracker(_document); + if (_document->Error()) + return 0; + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + TIXMLASSERT( p ); + if ( node == 0 ) { + break; + } + + int initialLineNum = node->_parseLineNum; + + StrPair endTag; + p = node->ParseDeep( p, &endTag, curLineNumPtr ); + if ( !p ) { + DeleteNode( node ); + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); + } + break; + } + + XMLDeclaration* decl = node->ToDeclaration(); + if ( decl ) { + // Declarations are only allowed at document level + // + // Multiple declarations are allowed but all declarations + // must occur before anything else. + // + // Optimized due to a security test case. If the first node is + // a declaration, and the last node is a declaration, then only + // declarations have so far been addded. + bool wellLocated = false; + + if (ToDocument()) { + if (FirstChild()) { + wellLocated = + FirstChild() && + FirstChild()->ToDeclaration() && + LastChild() && + LastChild()->ToDeclaration(); + } + else { + wellLocated = true; + } + } + if ( !wellLocated ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); + DeleteNode( node ); + break; + } + } + + XMLElement* ele = node->ToElement(); + if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEndTag ) { + ele->_value.TransferTo( parentEndTag ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } + } + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { + mismatch = true; + } + } + if ( mismatch ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); + DeleteNode( node ); + break; + } + } + InsertEndChild( node ); + } + return 0; +} + +/*static*/ void XMLNode::DeleteNode( XMLNode* node ) +{ + if ( node == 0 ) { + return; + } + TIXMLASSERT(node->_document); + if (!node->ToDocument()) { + node->_document->MarkInUse(node); + } + + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free( node ); +} + +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if (insertThis->_parent) { + insertThis->_parent->Unlink( insertThis ); + } + else { + insertThis->_document->MarkInUse(insertThis); + insertThis->_memPool->SetTracked(); + } +} + +const XMLElement* XMLNode::ToElementWithName( const char* name ) const +{ + const XMLElement* element = this->ToElement(); + if ( element == 0 ) { + return 0; + } + if ( name == 0 ) { + return element; + } + if ( XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + return 0; +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText( p, "<", flags, curLineNumPtr ); + if ( p && *p ) { + return p-1; + } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLText* text = compare->ToText(); + return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Comment parses as text. + p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLComment* comment = compare->ToComment(); + return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Declaration parses as text. + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Unknown parses as text. + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLUnknown* unknown = compare->ToUnknown(); + return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // + +const char* XMLAttribute::Name() const +{ + return _name.GetStr(); +} + +const char* XMLAttribute::Value() const +{ + return _value.GetStr(); +} + +char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryInt64Value(int64_t* value) const +{ + if (XMLUtil::ToInt64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} + + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( OPEN ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute( _rootAttribute ); + _rootAttribute = next; + } +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + +int XMLElement::IntAttribute(const char* name, int defaultValue) const +{ + int i = defaultValue; + QueryIntAttribute(name, &i); + return i; +} + +unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedAttribute(name, &i); + return i; +} + +int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Attribute(name, &i); + return i; +} + +bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolAttribute(name, &b); + return b; +} + +double XMLElement::DoubleAttribute(const char* name, double defaultValue) const +{ + double d = defaultValue; + QueryDoubleAttribute(name, &d); + return d; +} + +float XMLElement::FloatAttribute(const char* name, float defaultValue) const +{ + float f = defaultValue; + QueryFloatAttribute(name, &f); + return f; +} + +const char* XMLElement::GetText() const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + return FirstChild()->Value(); + } + return 0; +} + + +void XMLElement::SetText( const char* inText ) +{ + if ( FirstChild() && FirstChild()->ToText() ) + FirstChild()->SetValue( inText ); + else { + XMLText* theText = GetDocument()->NewText( inText ); + InsertFirstChild( theText ); + } +} + + +void XMLElement::SetText( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + + +void XMLElement::SetText( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryInt64Text(int64_t* ival) const +{ + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToInt64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + +int XMLElement::IntText(int defaultValue) const +{ + int i = defaultValue; + QueryIntText(&i); + return i; +} + +unsigned XMLElement::UnsignedText(unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedText(&i); + return i; +} + +int64_t XMLElement::Int64Text(int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Text(&i); + return i; +} + +bool XMLElement::BoolText(bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolText(&b); + return b; +} + +double XMLElement::DoubleText(double defaultValue) const +{ + double d = defaultValue; + QueryDoubleText(&d); + return d; +} + +float XMLElement::FloatText(float defaultValue) const +{ + float f = defaultValue; + QueryFloatText(&f); + return f; +} + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + if ( last ) { + TIXMLASSERT( last->_next == 0 ); + last->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + attrib->SetName( name ); + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) +{ + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar( *p ) ) { + XMLAttribute* attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + attrib->_parseLineNum = _document->_parseCurLineNum; + + int attrLineNum = attrib->_parseLineNum; + + p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); + if ( !p || Attribute( attrib->Name() ) ) { + DeleteAttribute( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + TIXMLASSERT( prevAttribute->_next == 0 ); + prevAttribute->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); + return 0; + } + } + return p; +} + +void XMLElement::DeleteAttribute( XMLAttribute* attribute ) +{ + if ( attribute == 0 ) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free( attribute ); +} + +XMLAttribute* XMLElement::CreateAttribute() +{ + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + TIXMLASSERT( attrib ); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + return attrib; +} + +// +// +// foobar +// +char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + + // The closing element is the form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p, curLineNumPtr ); + if ( !p || !*p || _closingType != OPEN ) { + return p; + } + + p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // + +// Warning: List must match 'enum XMLError' +const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE", + "XML_ELEMENT_DEPTH_EXCEEDED" +}; + + +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID(XML_SUCCESS), + _whitespaceMode( whitespaceMode ), + _errorStr(), + _errorLineNum( 0 ), + _charBuffer( 0 ), + _parseCurLineNum( 0 ), + _parsingDepth(0), + _unlinked(), + _elementPool(), + _attributePool(), + _textPool(), + _commentPool() +{ + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; +} + + +XMLDocument::~XMLDocument() +{ + Clear(); +} + + +void XMLDocument::MarkInUse(XMLNode* node) +{ + TIXMLASSERT(node); + TIXMLASSERT(node->_parent == 0); + + for (int i = 0; i < _unlinked.Size(); ++i) { + if (node == _unlinked[i]) { + _unlinked.SwapRemove(i); + break; + } + } +} + +void XMLDocument::Clear() +{ + DeleteChildren(); + while( _unlinked.Size()) { + DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. + } + +#ifdef TINYXML2_DEBUG + const bool hadError = Error(); +#endif + ClearError(); + + delete [] _charBuffer; + _charBuffer = 0; + _parsingDepth = 0; + +#if 0 + _textPool.Trace( "text" ); + _elementPool.Trace( "element" ); + _commentPool.Trace( "comment" ); + _attributePool.Trace( "attribute" ); +#endif + +#ifdef TINYXML2_DEBUG + if ( !hadError ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +void XMLDocument::DeepCopy(XMLDocument* target) const +{ + TIXMLASSERT(target); + if (target == this) { + return; // technically success - a no-op. + } + + target->Clear(); + for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { + target->InsertEndChild(node->DeepClone(target)); + } +} + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + XMLElement* ele = CreateUnlinkedNode( _elementPool ); + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + XMLComment* comment = CreateUnlinkedNode( _commentPool ); + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + XMLText* text = CreateUnlinkedNode( _textPool ); + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + XMLDeclaration* dec = CreateUnlinkedNode( _commentPool ); + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + XMLUnknown* unk = CreateUnlinkedNode( _commentPool ); + unk->SetValue( str ); + return unk; +} + +static FILE* callfopen( const char* filepath, const char* mode ) +{ + TIXMLASSERT( filepath ); + TIXMLASSERT( mode ); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filepath, mode ); + if ( err ) { + return 0; + } +#else + FILE* fp = fopen( filepath, mode ); +#endif + return fp; +} + +void XMLDocument::DeleteNode( XMLNode* node ) { + TIXMLASSERT( node ); + TIXMLASSERT(node->_document == this ); + if (node->_parent) { + node->_parent->DeleteChild( node ); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + + Clear(); + FILE* fp = callfopen( filename, "rb" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + +// This is likely overengineered template art to have a check that unsigned long value incremented +// by one still fits into size_t. If size_t type is larger than unsigned long type +// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit +// -Wtype-limits warning. This piece makes the compiler select code with a check when a check +// is useful and code with no check when a check is redundant depending on how size_t and unsigned long +// types sizes relate to each other. +template += sizeof(size_t))> +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long value ) + { + return value < (size_t)-1; + } +}; + +template <> +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long ) + { + return true; + } +}; + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + Clear(); + + fseek( fp, 0, SEEK_SET ); + if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + fseek( fp, 0, SEEK_END ); + const long filelength = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + if ( filelength == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + TIXMLASSERT( filelength >= 0 ); + + if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + const size_t size = filelength; + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[size+1]; + size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + + FILE* fp = callfopen( filename, "w" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + ClearError(); + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + Clear(); + + if ( len == 0 || !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == (size_t)(-1) ) { + len = strlen( p ); + } + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[ len+1 ]; + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + Parse(); + if ( Error() ) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) const +{ + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); + } +} + + +void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) +{ + TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + _errorID = error; + _errorLineNum = lineNum; + _errorStr.Reset(); + + size_t BUFFER_SIZE = 1000; + char* buffer = new char[BUFFER_SIZE]; + + TIXMLASSERT(sizeof(error) <= sizeof(int)); + TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum); + + if (format) { + size_t len = strlen(buffer); + TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); + len = strlen(buffer); + + va_list va; + va_start(va, format); + TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); + va_end(va); + } + _errorStr.SetStr(buffer); + delete[] buffer; +} + + +/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) +{ + TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); + const char* errorName = _errorNames[errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; +} + +const char* XMLDocument::ErrorStr() const +{ + return _errorStr.Empty() ? "" : _errorStr.GetStr(); +} + + +void XMLDocument::PrintError() const +{ + printf("%s\n", ErrorStr()); +} + +const char* XMLDocument::ErrorName() const +{ + return ErrorIDToName(_errorID); +} + +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + _parseCurLineNum = 1; + _parseLineNum = 1; + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0, &_parseCurLineNum ); +} + +void XMLDocument::PushDepth() +{ + _parsingDepth++; + if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { + SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); + } +} + +void XMLDocument::PopDepth() +{ + TIXMLASSERT(_parsingDepth > 0); + --_parsingDepth; +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : + _elementJustOpened( false ), + _stack(), + _firstElement( true ), + _fp( file ), + _depth( depth ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ), + _buffer() +{ + for( int i=0; i'] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + const int len = TIXML_VSCPRINTF( format, va ); + // Close out and re-start the va-args + va_end( va ); + TIXMLASSERT( len >= 0 ); + va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); + char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. + TIXML_VSNPRINTF( p, len+1, format, va ); + } + va_end( va ); +} + + +void XMLPrinter::Write( const char* data, size_t size ) +{ + if ( _fp ) { + fwrite ( data , sizeof(char), size, _fp); + } + else { + char* p = _buffer.PushArr( static_cast(size) ) - 1; // back up over the null terminator. + memcpy( p, data, size ); + p[size] = 0; + } +} + + +void XMLPrinter::Putc( char ch ) +{ + if ( _fp ) { + fputc ( ch, _fp); + } + else { + char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. + p[0] = ch; + p[1] = 0; + } +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[(unsigned char)(*q)] ) { + while ( p < q ) { + const size_t delta = q - p; + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + Write( p, toPrint ); + p += toPrint; + } + bool entityPatternPrinted = false; + for( int i=0; i( bom ) ); + } + if ( writeDec ) { + PushDeclaration( "xml version=\"1.0\"" ); + } +} + + +void XMLPrinter::OpenElement( const char* name, bool compactMode ) +{ + SealElementIfJustOpened(); + _stack.Push( name ); + + if ( _textDepth < 0 && !_firstElement && !compactMode ) { + Putc( '\n' ); + } + if ( !compactMode ) { + PrintSpace( _depth ); + } + + Write ( "<" ); + Write ( name ); + + _elementJustOpened = true; + _firstElement = false; + ++_depth; +} + + +void XMLPrinter::PushAttribute( const char* name, const char* value ) +{ + TIXMLASSERT( _elementJustOpened ); + Putc ( ' ' ); + Write( name ); + Write( "=\"" ); + PrintString( value, false ); + Putc ( '\"' ); +} + + +void XMLPrinter::PushAttribute( const char* name, int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute(const char* name, int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); +} + + +void XMLPrinter::PushAttribute( const char* name, bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::CloseElement( bool compactMode ) +{ + --_depth; + const char* name = _stack.Pop(); + + if ( _elementJustOpened ) { + Write( "/>" ); + } + else { + if ( _textDepth < 0 && !compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + Write ( "" ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !compactMode) { + Putc( '\n' ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElementIfJustOpened() +{ + if ( !_elementJustOpened ) { + return; + } + _elementJustOpened = false; + Putc( '>' ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + SealElementIfJustOpened(); + if ( cdata ) { + Write( "" ); + } + else { + PrintString( text, true ); + } +} + +void XMLPrinter::PushText( int64_t value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + _firstElement = false; + + Write( "" ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + _firstElement = false; + + Write( "" ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + _firstElement = false; + + Write( "' ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; + OpenElement( element.Name(), compactMode ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& element ) +{ + CloseElement( CompactMode(element) ); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 diff --git a/ZAPDTR/lib/tinyxml2/tinyxml2.h b/ZAPDTR/lib/tinyxml2/tinyxml2.h new file mode 100644 index 000000000..7cd312736 --- /dev/null +++ b/ZAPDTR/lib/tinyxml2/tinyxml2.h @@ -0,0 +1,2309 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +# include +# include +# include +# if defined(__PS3__) +# include +# endif +#else +# include +# include +# include +# include +# include +#endif +#include + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined (__DEBUG__) +# ifndef TINYXML2_DEBUG +# define TINYXML2_DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#elif __GNUC__ >= 4 +# define TINYXML2_LIB __attribute__((visibility("default"))) +#else +# define TINYXML2_LIB +#endif + + +#if defined(TINYXML2_DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 7; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 1; + +#define TINYXML2_MAJOR_VERSION 7 +#define TINYXML2_MINOR_VERSION 0 +#define TINYXML2_PATCH_VERSION 1 + +// A fixed element depth limit is problematic. There needs to be a +// limit to avoid a stack overflow. However, that limit varies per +// system, and the capacity of the stack. On the other hand, it's a trivial +// attack that can result from ill, malicious, or even correctly formed XML, +// so there needs to be a limit in place. +static const int TINYXML2_MAX_ELEMENT_DEPTH = 100; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] + + Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 +*/ +class TINYXML2_LIB StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + TIXMLASSERT( start ); + TIXMLASSERT( end ); + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + void Reset(); + +private: + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( const StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template +class DynArray +{ +public: + DynArray() : + _mem( _pool ), + _allocated( INITIAL_SIZE ), + _size( 0 ) + { + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size] = t; + ++_size; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + --_size; + return _mem[_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + void SwapRemove(int i) { + TIXMLASSERT(i >= 0 && i < _size); + TIXMLASSERT(_size > 0); + _mem[i] = _mem[_size - 1]; + --_size; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + TIXMLASSERT( newAllocated >= _size ); + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int ITEM_SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + MemPoolT< ITEM_SIZE >::Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* lastBlock = _blockPtrs.Pop(); + delete lastBlock; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return ITEM_SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + Item* blockItems = block->items; + for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { + blockItems[i].next = &(blockItems[i + 1]); + } + blockItems[ITEMS_PER_BLOCK - 1].next = 0; + _root = blockItems; + } + Item* const result = _root; + TIXMLASSERT( result != 0 ); + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + ++_nAllocs; + ++_nUntracked; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Item* item = static_cast( mem ); +#ifdef TINYXML2_DEBUG + memset( item, 0xfe, sizeof( *item ) ); +#endif + item->next = _root; + _root = item; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, + ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + --_nUntracked; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK + // in private part if ITEMS_PER_BLOCK is private + enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Item { + Item* next; + char itemData[ITEM_SIZE]; + }; + struct Block { + Item items[ITEMS_PER_BLOCK]; + }; + DynArray< Block*, 10 > _blockPtrs; + Item* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + XML_ELEMENT_DEPTH_EXCEEDED, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class TINYXML2_LIB XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { + TIXMLASSERT( p ); + + while( IsWhiteSpace(*p) ) { + if (curLineNumPtr && *p == '\n') { + ++(*curLineNumPtr); + } + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) { + return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + TIXMLASSERT( p ); + TIXMLASSERT( q ); + TIXMLASSERT( nChar >= 0 ); + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + static void ToStr(int64_t v, char* buffer, int bufferSize); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); + static bool ToInt64(const char* str, int64_t* value); + + // Changes what is serialized for a boolean value. + // Default to "true" and "false". Shouldn't be changed + // unless you have a special testing or compatibility need. + // Be careful: static, global, & not thread safe. + // Be sure to set static const memory as parameters. + static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); + +private: + static const char* writeBoolTrue; + static const char* writeBoolFalse; +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Gets the line number the node is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Make a copy of this node and all its children. + + If the 'target' is null, then the nodes will + be allocated in the current document. If 'target' + is specified, the memory will be allocated is the + specified XMLDocument. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want to use + XMLDocument::DeepCopy() + */ + XMLNode* DeepClone( XMLDocument* target ) const; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + + /** + Set user data into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void SetUserData(void* userData) { _userData = userData; } + + /** + Get user data set into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void* GetUserData() const { return _userData; } + +protected: + explicit XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + int _parseLineNum; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + + void* _userData; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + const XMLElement* ToElementWithName( const char* name ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// Gets the line number the attribute is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_SUCCESS on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute(int64_t value); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); + + mutable StrPair _name; + mutable StrPair _value; + int _parseLineNum; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. The default + value will be returned if the attribute isn't present, + or if there is an error. (For a method with error + checking, see QueryIntAttribute()). + */ + int IntAttribute(const char* name, int defaultValue = 0) const; + /// See IntAttribute() + unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; + /// See IntAttribute() + int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; + /// See IntAttribute() + bool BoolAttribute(const char* name, bool defaultValue = false) const; + /// See IntAttribute() + double DoubleAttribute(const char* name, double defaultValue = 0) const; + /// See IntAttribute() + float FloatAttribute(const char* name, float defaultValue = 0) const; + + /** Given an attribute name, QueryIntAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryInt64Attribute(const char* name, int64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryInt64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryStringAttribute(const char* name, const char** value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + *value = a->Value(); + return XML_SUCCESS; + } + + + + /** Given an attribute name, QueryAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + XMLError QueryAttribute(const char* name, int64_t* value) const { + return QueryInt64Attribute(name, value); + } + + XMLError QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, int64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + This is text + fooElement->SetText( "Hullaballoo!" ); + Hullaballoo! + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + Hullaballoo!This is text + @endverbatim + + For this XML: + @verbatim + + @endverbatim + SetText() will generate + @verbatim + Hullaballoo! + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + int IntText(int defaultValue = 0) const; + + /// See QueryIntText() + unsigned UnsignedText(unsigned defaultValue = 0) const; + /// See QueryIntText() + int64_t Int64Text(int64_t defaultValue = 0) const; + /// See QueryIntText() + bool BoolText(bool defaultValue = false) const; + /// See QueryIntText() + double DoubleText(double defaultValue = 0) const; + /// See QueryIntText() + float FloatText(float defaultValue = 0) const; + + // internal: + enum ElementClosingType { + OPEN, // + CLOSED, // + CLOSING // + }; + ElementClosingType ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindOrCreateAttribute( const char* name ); + char* ParseAttributes( char* p, int* curLineNumPtr ); + static void DeleteAttribute( XMLAttribute* attribute ); + XMLAttribute* CreateAttribute(); + + enum { BUF_SIZE = 200 }; + ElementClosingType _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; + // Gives access to SetError and Push/PopDepth, but over-access for everything else. + // Wishing C++ had "internal" scope. + friend class XMLNode; + friend class XMLText; + friend class XMLComment; + friend class XMLDeclaration; + friend class XMLUnknown; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_SUCCESS (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + + /** + Load an XML file from disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespaceMode; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + void ClearError() { + SetError(XML_SUCCESS, 0, 0); + } + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_SUCCESS; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + static const char* ErrorIDToName(XMLError errorID); + + /** Returns a "long form" error description. A hopefully helpful + diagnostic with location, line number, and/or additional info. + */ + const char* ErrorStr() const; + + /// A (trivial) utility function that prints the ErrorStr() to stdout. + void PrintError() const; + + /// Return the line where the error occurred, or zero if unknown. + int ErrorLineNum() const + { + return _errorLineNum; + } + + /// Clear the document, resetting it to the initial state. + void Clear(); + + /** + Copies this document to a target document. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see XMLNode::DeepClone(). + + NOTE: that the 'target' must be non-null. + */ + void DeepCopy(XMLDocument* target) const; + + // internal + char* Identify( char* p, XMLNode** node ); + + // internal + void MarkInUse(XMLNode*); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespaceMode; + mutable StrPair _errorStr; + int _errorLineNum; + char* _charBuffer; + int _parseCurLineNum; + int _parsingDepth; + // Memory tracking does add some overhead. + // However, the code assumes that you don't + // have a bunch of unlinked nodes around. + // Therefore it takes less memory to track + // in the document vs. a linked list in the XMLNode, + // and the performance is the same. + DynArray _unlinked; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); + + void SetError( XMLError error, int lineNum, const char* format, ... ); + + // Something of an obvious security hole, once it was discovered. + // Either an ill-formed XML or an excessively deep one can overflow + // the stack. Track stack depth, and error out if needed. + class DepthTracker { + public: + explicit DepthTracker(XMLDocument * document) { + this->_document = document; + document->PushDepth(); + } + ~DepthTracker() { + _document->PopDepth(); + } + private: + XMLDocument * _document; + }; + void PushDepth(); + void PopDepth(); + + template + NodeType* CreateUnlinkedNode( MemPoolT& pool ); +}; + +template +inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) +{ + TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); + TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); + NodeType* returnNode = new (pool.Alloc()) NodeType( this ); + TIXMLASSERT( returnNode ); + returnNode->_memPool = &pool; + + _unlinked.Push(returnNode); + return returnNode; +} + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + explicit XMLHandle( XMLNode* node ) : _node( node ) { + } + /// Create a handle from a node. + explicit XMLHandle( XMLNode& node ) : _node( &node ) { + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( _node ? _node->ToElement() : 0 ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( _node ? _node->ToText() : 0 ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( _node ? _node->ToUnknown() : 0 ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { + } + explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { + } + XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( _node ? _node->ToElement() : 0 ); + } + const XMLText* ToText() const { + return ( _node ? _node->ToText() : 0 ); + } + const XMLUnknown* ToUnknown() const { + return ( _node ? _node->ToUnknown() : 0 ); + } + const XMLDeclaration* ToDeclaration() const { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute(const char* name, int64_t value); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from an unsigned. + void PushText(int64_t value); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer() { + _buffer.Clear(); + _buffer.Push(0); + _firstElement = true; + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + void Print( const char* format, ... ); + void Write( const char* data, size_t size ); + inline void Write( const char* data ) { Write( data, strlen( data ) ); } + void Putc( char ch ); + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; + + // Prohibit cloning, intentionally not implemented + XMLPrinter( const XMLPrinter& ); + XMLPrinter& operator=( const XMLPrinter& ); +}; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED