summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLywx <kiritodev01@gmail.com>2023-11-15 15:11:15 -0600
committerGitHub <noreply@github.com>2023-11-15 15:11:15 -0600
commiteaddecd0b402c12a780831e3139d7a35e78322e6 (patch)
tree0c961e1ba2339f52892b54f44b8ff0018b77c382 /src
parenta66b259d7c10c3367a04819c6b55d47fb9a99f5e (diff)
Torch v0.1 (#12)
* Splitted version yamls and implemented wip geo and dlist extraction * Fixed linux compilation * Added PoC WSL 2 detection * Add undefined behaviour * Added gfxdis as submodule * update * Removed gfxdis as a submodule * Code works * Replace ByteSwap with BSWAP * Cleanup vertice factory * readability * readability 2 * Cleanup gfxfactory * last one * Rename name to symbol * More implementation * Implemented first PoC of C file generation * Added output formatting on factories * changes * Moved generated dlists onto their respective folder * Migrated more factories onto the new extractor system * Fully ported all factories and added header generation * Some updates * Added Lights factory * fix * Fixed vtx extraction * Lights work now * delete old startup_logo yaml * Generate all sections in single file * Added support to generate header and code for textures * Added O3 for release builds * Added WIP dlist extraction and moved to use f3dold microcode * Added segment support, autogeneration and fixed C generation * Added symbol names on display list extraction * Removed warnings * Moved back to transform and replace * Removed unnecesary macros * Added extraction order and reversed vtx order * Implemented true backwards sort * [WIP] Implemented runtime gbi, more headers and a few config features * Fix CLI11 on WSL and variety of fixes * Fixes * Update DisplayListFactory.h * Update TextureFactory.cpp * wip lights * fix * Correct callback * Added waypoints * Update ceremony_data.yml * Changes * Update TextureFactory.cpp * Update commandline args * Update comment * Remove printf * Update couple commands * Renamed cubeos to torch * Removed unused stuff and added an example config file --------- Co-authored-by: KiritoDv <kiritodev01@gmail.com> Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/Companion.cpp472
-rw-r--r--src/Companion.h67
-rw-r--r--src/factories/AudioHeaderFactory.cpp4
-rw-r--r--src/factories/AudioHeaderFactory.h10
-rw-r--r--src/factories/BankFactory.cpp103
-rw-r--r--src/factories/BankFactory.h26
-rw-r--r--src/factories/BaseFactory.cpp17
-rw-r--r--src/factories/BaseFactory.h55
-rw-r--r--src/factories/BlobFactory.cpp47
-rw-r--r--src/factories/BlobFactory.h21
-rw-r--r--src/factories/DisplayListFactory.cpp377
-rw-r--r--src/factories/DisplayListFactory.h39
-rw-r--r--src/factories/DisplayListOverrides.cpp103
-rw-r--r--src/factories/DisplayListOverrides.h13
-rw-r--r--src/factories/LightsFactory.cpp94
-rw-r--r--src/factories/LightsFactory.h66
-rw-r--r--src/factories/RawFactory.cpp18
-rw-r--r--src/factories/RawFactory.h39
-rw-r--r--src/factories/ResourceType.h5
-rw-r--r--src/factories/SampleFactory.cpp66
-rw-r--r--src/factories/SampleFactory.h24
-rw-r--r--src/factories/SequenceFactory.cpp32
-rw-r--r--src/factories/SequenceFactory.h28
-rw-r--r--src/factories/TextureFactory.cpp133
-rw-r--r--src/factories/TextureFactory.h36
-rw-r--r--src/factories/VtxFactory.cpp114
-rw-r--r--src/factories/VtxFactory.h41
-rw-r--r--src/factories/debug/MIO0Factory.cpp23
-rw-r--r--src/factories/mk64/WaypointFactory.cpp83
-rw-r--r--src/factories/mk64/WaypointFactory.h44
-rw-r--r--src/factories/sm64/AnimationFactory.cpp74
-rw-r--r--src/factories/sm64/AnimationFactory.h32
-rw-r--r--src/factories/sm64/DialogFactory.cpp54
-rw-r--r--src/factories/sm64/DialogFactory.h28
-rw-r--r--src/factories/sm64/DictionaryFactory.cpp39
-rw-r--r--src/factories/sm64/DictionaryFactory.h25
-rw-r--r--src/factories/sm64/GeoCommands.h436
-rw-r--r--src/factories/sm64/GeoFactory.cpp.old594
-rw-r--r--src/factories/sm64/GeoFactory.h.old (renamed from src/factories/debug/MIO0Factory.h)4
-rw-r--r--src/factories/sm64/SAnimFactory.cpp86
-rw-r--r--src/factories/sm64/SAnimFactory.h9
-rw-r--r--src/factories/sm64/SDialogFactory.cpp62
-rw-r--r--src/factories/sm64/SDialogFactory.h9
-rw-r--r--src/factories/sm64/SDictionaryFactory.cpp35
-rw-r--r--src/factories/sm64/SDictionaryFactory.h9
-rw-r--r--src/factories/sm64/STextFactory.cpp28
-rw-r--r--src/factories/sm64/STextFactory.h9
-rw-r--r--src/factories/sm64/TextFactory.cpp29
-rw-r--r--src/factories/sm64/TextFactory.h18
-rw-r--r--src/main.cpp70
-rw-r--r--src/n64/Cartridge.h1
-rw-r--r--src/n64/CommandMacros.h17
-rw-r--r--src/n64/gbi-otr.h140
-rw-r--r--src/n64/gbi.h4801
-rw-r--r--src/n64/types.h59
-rw-r--r--src/storm/SWrapper.cpp20
-rw-r--r--src/types/RawBuffer.h12
-rw-r--r--src/types/SegmentedAddr.h7
-rw-r--r--src/utils/MIODecoder.cpp11
-rw-r--r--src/utils/MIODecoder.h4
60 files changed, 8259 insertions, 663 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp
index 1b98d2d..761f2eb 100644
--- a/src/Companion.cpp
+++ b/src/Companion.cpp
@@ -2,208 +2,450 @@
#include "storm/SWrapper.h"
#include "utils/MIODecoder.h"
-#include "factories/RawFactory.h"
-#include "factories/BlobFactory.h"
-#include "factories/debug/MIO0Factory.h"
+#include "factories/sm64/AnimationFactory.h"
+#include "factories/sm64/DialogFactory.h"
+#include "factories/sm64/DictionaryFactory.h"
+#include "factories/sm64/TextFactory.h"
+#include "factories/BankFactory.h"
#include "factories/AudioHeaderFactory.h"
-#include "factories/SequenceFactory.h"
#include "factories/SampleFactory.h"
-#include "factories/BankFactory.h"
+#include "factories/SequenceFactory.h"
+#include "factories/VtxFactory.h"
#include "factories/TextureFactory.h"
-#include "factories/sm64/SAnimFactory.h"
-#include "factories/sm64/STextFactory.h"
-#include "factories/sm64/SDialogFactory.h"
-#include "factories/sm64/SDictionaryFactory.h"
+#include "factories/DisplayListFactory.h"
+#include "factories/BlobFactory.h"
+#include "factories/LightsFactory.h"
+#include "factories/mk64/WaypointFactory.h"
#include "spdlog/spdlog.h"
-#include <chrono>
#include <fstream>
#include <iostream>
#include <filesystem>
-namespace fs = std::filesystem;
using namespace std::chrono;
+namespace fs = std::filesystem;
+
+static const std::string regular = "[%Y-%m-%d %H:%M:%S.%e] [%l] %v";
+static const std::string line = "[%Y-%m-%d %H:%M:%S.%e] [%l] > %v";
-void Companion::Init() {
+void Companion::Init(const ExportType type) {
spdlog::set_level(spdlog::level::debug);
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
- this->RegisterFactory("AUDIO:HEADER", new AudioHeaderFactory());
- this->RegisterFactory("SEQUENCE", new SequenceFactory());
- this->RegisterFactory("SAMPLE", new SampleFactory());
- this->RegisterFactory("BANK", new BankFactory());
+ this->gExporterType = type;
+ this->RegisterFactory("BLOB", std::make_shared<BlobFactory>());
+ this->RegisterFactory("TEXTURE", std::make_shared<TextureFactory>());
+ this->RegisterFactory("VTX", std::make_shared<VtxFactory>());
+ this->RegisterFactory("LIGHTS", std::make_shared<LightsFactory>());
+ this->RegisterFactory("GFX", std::make_shared<DListFactory>());
+ this->RegisterFactory("AUDIO:HEADER", std::make_shared<AudioHeaderFactory>());
+ this->RegisterFactory("SEQUENCE", std::make_shared<SequenceFactory>());
+ this->RegisterFactory("SAMPLE", std::make_shared<SampleFactory>());
+ this->RegisterFactory("BANK", std::make_shared<BankFactory>());
+
+ // SM64 specific
+ this->RegisterFactory("SM64:DIALOG", std::make_shared<SM64::DialogFactory>());
+ this->RegisterFactory("SM64:TEXT", std::make_shared<SM64::TextFactory>());
+ this->RegisterFactory("SM64:DICTIONARY", std::make_shared<SM64::DictionaryFactory>());
+ this->RegisterFactory("SM64:ANIM", std::make_shared<SM64::AnimationFactory>());
+ // this->RegisterFactory("GEO_LAYOUT", new SGeoFactory());
+
+ // MK64 specific
+ this->RegisterFactory("MK64:TRACKWAYPOINTS", std::make_shared<MK64::WaypointFactory>());
- this->RegisterFactory("TEXTURE", new TextureFactory());
- this->RegisterFactory("BLOB", new BlobFactory());
+ this->Process();
+}
- // SM64 Specific
- this->RegisterFactory("SM64:DIALOG", new SDialogFactory());
- this->RegisterFactory("SM64:ANIM", new SAnimFactory());
- this->RegisterFactory("SM64:TEXT", new STextFactory());
- this->RegisterFactory("SM64:DICTIONARY", new SDictionaryFactory());
+void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary) {
+ std::ostringstream stream;
- // Debug
- this->RegisterFactory("MIO0", new MIO0Factory());
+ auto type = node["type"].as<std::string>();
+ auto offset = node["offset"].as<uint32_t>();
+ std::transform(type.begin(), type.end(), type.begin(), ::toupper);
- this->Process();
+ SPDLOG_INFO("[{}] Processing {} at 0x{:X}", type, name, offset);
+ auto factory = this->GetFactory(type);
+ if(!factory.has_value()){
+ SPDLOG_ERROR("No factory found for {}", name);
+ return;
+ }
+
+ auto result = factory->get()->parse(this->gRomData, node);
+ if(!result.has_value()){
+ SPDLOG_ERROR("Failed to process {}", name);
+ return;
+ }
+
+ auto exporter = factory->get()->GetExporter(this->gExporterType);
+ if(!exporter.has_value()){
+ SPDLOG_ERROR("No exporter found for {}", name);
+ return;
+ }
+
+ for (auto [fst, snd] : this->gAssetDependencies[this->gCurrentFile]) {
+ if(snd.second) continue;
+ std::string doutput = (this->gCurrentDirectory / fst).string();
+ std::replace(doutput.begin(), doutput.end(), '\\', '/');
+ this->gAssetDependencies[this->gCurrentFile][fst].second = true;
+ this->ExtractNode(snd.first, doutput, binary);
+ }
+
+ switch (this->gExporterType) {
+ case ExportType::Binary: {
+ if(binary == nullptr) break;
+ stream.str("");
+ stream.clear();
+ exporter->get()->Export(stream, result.value(), name, node, &name);
+ auto data = stream.str();
+ binary->CreateFile(name, std::vector(data.begin(), data.end()));
+ break;
+ }
+ default: {
+ exporter->get()->Export(stream, result.value(), name, node, &name);
+ break;
+ }
+ }
+
+ SPDLOG_INFO("Processed {}", name);
+ this->gWriteMap[this->gCurrentFile][type].emplace_back(node["offset"].as<uint32_t>(), stream.str());
}
void Companion::Process() {
- const std::string regular = "[%Y-%m-%d %H:%M:%S.%e] [%l] %v";
- const std::string line = "[%Y-%m-%d %H:%M:%S.%e] [%l] > %v";
+ if(!fs::exists("config.yml")) {
+ SPDLOG_ERROR("No config file found");
+ return;
+ }
auto start = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
std::ifstream input( this->gRomPath, std::ios::binary );
- this->gRomData = std::vector<uint8_t>( std::istreambuf_iterator<char>( input ), {} );
+ this->gRomData = std::vector<uint8_t>( std::istreambuf_iterator( input ), {} );
input.close();
- this->cartridge = new N64::Cartridge(this->gRomData);
- cartridge->Initialize();
+ this->gCartridge = new N64::Cartridge(this->gRomData);
+ gCartridge->Initialize();
YAML::Node config = YAML::LoadFile("config.yml");
- if(!config[cartridge->GetHash()]){
- SPDLOG_ERROR("No config found for {}", cartridge->GetHash());
+ if(!config[gCartridge->GetHash()]){
+ SPDLOG_ERROR("No config found for {}", gCartridge->GetHash());
return;
}
- auto cfg = config[cartridge->GetHash()];
- auto path = cfg["path"].as<std::string>();
- auto otr = cfg["output"].as<std::string>();
+ auto rom = config[gCartridge->GetHash()];
+ auto cfg = rom["config"];
+
+ if(!cfg) {
+ SPDLOG_ERROR("No config found for {}", gCartridge->GetHash());
+ return;
+ }
+
+ if(rom["segments"]) {
+ this->gSegments = rom["segments"].as<std::vector<uint32_t>>();
+ }
+ auto path = rom["path"].as<std::string>();
+ auto opath = cfg["output"];
+ auto gbi = cfg["gbi"];
+
+ switch (gExporterType) {
+ case ExportType::Binary: {
+ this->gOutputPath = opath && opath["binary"] ? opath["binary"].as<std::string>() : "generic.otr";
+ break;
+ }
+ case ExportType::Header: {
+ this->gOutputPath = opath && opath["headers"] ? opath["headers"].as<std::string>() : "headers";
+ break;
+ }
+ case ExportType::Code: {
+ this->gOutputPath = opath && opath["code"] ? opath["code"].as<std::string>() : "code";
+ break;
+ }
+ }
+
+ if(gbi) {
+ auto key = gbi.as<std::string>();
+
+ if(key == "F3D") {
+ this->gGBIVersion = GBIVersion::f3d;
+ } else if(key == "F3DEX") {
+ this->gGBIVersion = GBIVersion::f3dex;
+ } else if(key == "F3DB") {
+ this->gGBIVersion = GBIVersion::f3db;
+ } else if(key == "F3DEX2") {
+ this->gGBIVersion = GBIVersion::f3dex2;
+ } else if(key == "F3DEXB") {
+ this->gGBIVersion = GBIVersion::f3dexb;
+ } else if (key == "F3DEX_MK64") {
+ this->gGBIVersion = GBIVersion::f3dex;
+ this->gGBIMinorVersion = GBIMinorVersion::Mk64;
+ } else {
+ SPDLOG_ERROR("Invalid GBI version");
+ return;
+ }
+ }
+
+ if(auto sort = cfg["sort"]) {
+ if(sort.IsSequence()) {
+ this->gWriteOrder = sort.as<std::vector<std::string>>();
+ } else {
+ this->gWriteOrder = sort.as<std::string>();
+ }
+ } else {
+ this->gWriteOrder = std::vector<std::string> {
+ "LIGHTS", "TEXTURE", "VTX", "GFX"
+ };
+ }
+
+ if(std::holds_alternative<std::vector<std::string>>(this->gWriteOrder)) {
+ for (auto& [key, _] : this->gFactories) {
+ auto entries = std::get<std::vector<std::string>>(this->gWriteOrder);
+
+ if(std::find(entries.begin(), entries.end(), key) != entries.end()) {
+ continue;
+ }
+
+ entries.push_back(key);
+ }
+ }
SPDLOG_INFO("------------------------------------------------");
spdlog::set_pattern(line);
- SPDLOG_INFO("Starting CubeOS...");
- SPDLOG_INFO("Game: {}", cartridge->GetGameTitle());
- SPDLOG_INFO("CRC: {}", cartridge->GetCRC());
- SPDLOG_INFO("Version: {}", cartridge->GetVersion());
- SPDLOG_INFO("Country: [{}]", cartridge->GetCountryCode());
- SPDLOG_INFO("Hash: {}", cartridge->GetHash());
+ SPDLOG_INFO("Starting Torch...");
+ SPDLOG_INFO("Game: {}", gCartridge->GetGameTitle());
+ SPDLOG_INFO("CRC: {}", gCartridge->GetCRC());
+ SPDLOG_INFO("Version: {}", gCartridge->GetVersion());
+ SPDLOG_INFO("Country: [{}]", gCartridge->GetCountryCode());
+ SPDLOG_INFO("Hash: {}", gCartridge->GetHash());
SPDLOG_INFO("Assets: {}", path);
- auto wrapper = SWrapper(otr);
+ auto wrapper = this->gExporterType == ExportType::Binary ? new SWrapper(this->gOutputPath) : nullptr;
auto vWriter = LUS::BinaryWriter();
vWriter.SetEndianness(LUS::Endianness::Big);
- vWriter.Write((uint8_t) LUS::Endianness::Big);
- vWriter.Write(cartridge->GetCRC());
+ vWriter.Write(static_cast<uint8_t>(LUS::Endianness::Big));
+ vWriter.Write(gCartridge->GetCRC());
- for (const auto & entry : fs::directory_iterator(path)){
+ for (const auto & entry : fs::recursive_directory_iterator(path)){
+ if(entry.is_directory()) continue;
YAML::Node root = YAML::LoadFile(entry.path().string());
+ this->gCurrentDirectory = relative(entry.path(), path).replace_extension("");
+ this->gCurrentFile = entry.path().string();
+
for(auto asset = root.begin(); asset != root.end(); ++asset){
- auto type = asset->second["type"].as<std::string>();
+ auto node = asset->second;
+ if(!asset->second["offset"]) continue;
+
+ auto output = (this->gCurrentDirectory / asset->first.as<std::string>()).string();
+ std::replace(output.begin(), output.end(), '\\', '/');
+
+ this->gAddrMap[this->gCurrentFile][node["offset"].as<uint32_t>()] = std::make_tuple(output, node);
+ }
- LUS::BinaryWriter write = LUS::BinaryWriter();
- RawFactory* factory = this->GetFactory(type);
- factory->SetCartridge(cartridge);
+ // Stupid hack because the iteration broke the assets
+ root = YAML::LoadFile(entry.path().string());
+
+ for(auto asset = root.begin(); asset != root.end(); ++asset){
spdlog::set_pattern(regular);
SPDLOG_INFO("------------------------------------------------");
spdlog::set_pattern(line);
- SPDLOG_INFO("Processing {} [{}]", asset->first.as<std::string>(), type);
- SPDLOG_INFO("Root: {}", entry.path().string());
- if(!factory->process(&write, asset->second, this->gRomData)){
- SPDLOG_ERROR("Failed to process {}", asset->first.as<std::string>());
- continue;
- }
+ auto entryName = asset->first.as<std::string>();
+ std::string output = (this->gCurrentDirectory / entryName).string();
+ std::replace(output.begin(), output.end(), '\\', '/');
- auto buffer = write.ToVector();
- auto output = (entry.path().stem() / asset->first.as<std::string>()).string();
+ this->ExtractNode(asset->second, output, wrapper);
+ }
- std::replace(output.begin(), output.end(), '\\', '/');
+ if(gExporterType != ExportType::Binary){
+ std::string output = (this->gOutputPath / this->gCurrentDirectory).string();
- wrapper.CreateFile(output, buffer);
+ switch (gExporterType) {
+ case ExportType::Header: {
+ output += "/definition.h";
+ break;
+ }
+ case ExportType::Code: {
+ output += "/root.inc.c";
+ break;
+ }
+ default: break;
+ }
+
+ std::ostringstream stream;
+
+ if(std::holds_alternative<std::string>(this->gWriteOrder)) {
+ auto sort = std::get<std::string>(this->gWriteOrder);
+ std::vector<std::pair<uint32_t, std::string>> outbuf;
+ for (const auto& [type, buffer] : this->gWriteMap[this->gCurrentFile]) {
+ outbuf.insert(outbuf.end(), buffer.begin(), buffer.end());
+ }
+ this->gWriteMap.clear();
+
+ if(sort == "OFFSET") {
+ std::sort(outbuf.begin(), outbuf.end(), [](const auto& a, const auto& b) {
+ return std::get<uint32_t>(a) < std::get<uint32_t>(b);
+ });
+ } else if(sort == "ROFFSET") {
+ std::sort(outbuf.begin(), outbuf.end(), [](const auto& a, const auto& b) {
+ return std::get<uint32_t>(a) > std::get<uint32_t>(b);
+ });
+ } else if(sort != "LINEAR") {
+ throw std::runtime_error("Invalid write order");
+ }
- if(type != "TEXTURE") {
- SPDLOG_DEBUG("Writing debug file");
- std::string dpath = "debug/" + output;
- if(!fs::exists(fs::path(dpath).parent_path())){
- fs::create_directories(fs::path(dpath).parent_path());
+ for (auto& [symbol, buffer] : outbuf) {
+ stream << buffer;
}
- std::ofstream stream(dpath, std::ios::binary);
- stream.write((char*)buffer.data(), buffer.size());
- stream.close();
+ outbuf.clear();
+ } else {
+ for (const auto& type : std::get<std::vector<std::string>>(this->gWriteOrder)) {
+ std::vector<std::pair<uint32_t, std::string>> outbuf = this->gWriteMap[this->gCurrentFile][type];
+
+ std::sort(outbuf.begin(), outbuf.end(), [](const auto& a, const auto& b) {
+ return std::get<uint32_t>(a) > std::get<uint32_t>(b);
+ });
+
+ for (auto& [symbol, buffer] : outbuf) {
+ stream << buffer;
+ }
+ }
+ }
+
+ std::string buffer = stream.str();
+
+ if(buffer.empty()) {
+ continue;
+ }
+
+ std::replace(output.begin(), output.end(), '\\', '/');
+ if(!exists(fs::path(output).parent_path())){
+ create_directories(fs::path(output).parent_path());
}
- SPDLOG_INFO("Processed {}", output);
+ std::ofstream file(output, std::ios::binary);
+
+ if(gExporterType == ExportType::Header) {
+ std::string symbol = entry.path().stem();
+ std::transform(symbol.begin(), symbol.end(), symbol.begin(), toupper);
+ file << "#ifndef " << symbol << "_H" << std::endl;
+ file << "#define " << symbol << "_H" << std::endl << std::endl;
+ file << buffer;
+ file << std::endl << "#endif" << std::endl;
+ } else {
+ file << buffer;
+ }
- write.Close();
+ file.close();
}
}
spdlog::set_pattern(regular);
SPDLOG_INFO("------------------------------------------------");
spdlog::set_pattern(line);
- SPDLOG_INFO("Writing version file");
- wrapper.CreateFile("version", vWriter.ToVector());
- vWriter.Close();
+ if(wrapper != nullptr) {
+ SPDLOG_INFO("Writing version file");
+ wrapper->CreateFile("version", vWriter.ToVector());
+ vWriter.Close();
+ wrapper->Close();
+ }
auto end = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
SPDLOG_INFO("Done! Took {}ms", end.count() - start.count());
- SPDLOG_INFO("Exported to {}", otr);
spdlog::set_pattern(regular);
SPDLOG_INFO("------------------------------------------------");
MIO0Decoder::ClearCache();
- wrapper.Close();
- this->cartridge = nullptr;
- Companion::Instance = nullptr;
+ this->gCartridge = nullptr;
+ Instance = nullptr;
}
-void Companion::RegisterFactory(const std::string &extension, RawFactory *factory) {
- this->gFactories[extension] = factory;
- SPDLOG_DEBUG("Registered factory for {}", extension);
-}
+void Companion::Pack(const std::string& folder, const std::string& output) {
+
+ spdlog::set_level(spdlog::level::debug);
+ spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
+
+ SPDLOG_INFO("------------------------------------------------");
+
+ SPDLOG_INFO("Starting Torch...");
+ SPDLOG_INFO("Scanning {}", folder);
+
+ auto start = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
+ std::unordered_map<std::string, std::vector<char>> files;
+
+ for (const auto & entry : fs::recursive_directory_iterator(folder)){
+ if(entry.is_directory()) continue;
+ std::ifstream input( entry.path(), std::ios::binary );
+ auto data = std::vector( std::istreambuf_iterator( input ), {} );
+ input.close();
+ files[entry.path().string()] = data;
+ }
+
+ auto wrapper = SWrapper(output);
-RawFactory *Companion::GetFactory(const std::string &extension) {
- if(!this->gFactories.contains(extension)){
- throw std::runtime_error("No factory found for " + extension);
+ for(auto& [path, data] : files){
+ std::string normalized = path;
+ std::replace(normalized.begin(), normalized.end(), '\\', '/');
+ // Remove parent folder
+ normalized = normalized.substr(folder.length() + 1);
+ wrapper.CreateFile(normalized, data);
+ SPDLOG_INFO("> Added {}", normalized);
}
- return this->gFactories[extension];
+ auto end = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
+ SPDLOG_INFO("Done! Took {}ms", end.count() - start.count());
+ SPDLOG_INFO("Exported to {}", output);
+ spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
+ SPDLOG_INFO("------------------------------------------------");
+
+ wrapper.Close();
}
-void Companion::Pack(const std::string& folder, const std::string& output) {
+void Companion::RegisterAsset(const std::string& name, YAML::Node& node) {
+ if(!node["offset"]) return;
+ this->gAssetDependencies[this->gCurrentFile][name] = std::make_pair(node, false);
- spdlog::set_level(spdlog::level::debug);
- spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
+ auto output = (this->gCurrentDirectory / name).string();
+ std::replace(output.begin(), output.end(), '\\', '/');
+ this->gAddrMap[this->gCurrentFile][node["offset"].as<uint32_t>()] = std::make_tuple(output, node);
+}
- SPDLOG_INFO("------------------------------------------------");
+void Companion::RegisterFactory(const std::string& type, const std::shared_ptr<BaseFactory>& factory) {
+ this->gFactories[type] = factory;
+ SPDLOG_DEBUG("Registered factory for {}", type);
+}
- SPDLOG_INFO("Starting CubeOS...");
- SPDLOG_INFO("Scanning {}", folder);
+std::optional<std::shared_ptr<BaseFactory>> Companion::GetFactory(const std::string &type) {
+ if(!this->gFactories.contains(type)){
+ return std::nullopt;
+ }
- auto start = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
- std::unordered_map<std::string, std::vector<char>> files;
+ return this->gFactories[type];
+}
- for (const auto & entry : fs::recursive_directory_iterator(folder)){
- if(entry.is_directory()) continue;
- std::ifstream input( entry.path(), std::ios::binary );
- auto data = std::vector<char>( std::istreambuf_iterator<char>( input ), {} );
- input.close();
- files[entry.path().string()] = data;
- }
+std::optional<std::uint32_t> Companion::GetSegmentedAddr(const uint8_t segment) {
+ if(segment >= this->gSegments.size()) {
+ return std::nullopt;
+ }
- auto wrapper = SWrapper(output);
+ return this->gSegments[segment];
+}
- for(auto& [path, data] : files){
- std::string normalized = path;
- std::replace(normalized.begin(), normalized.end(), '\\', '/');
- // Remove parent folder
- normalized = normalized.substr(folder.length() + 1);
- wrapper.CreateFile(normalized, data);
- SPDLOG_INFO("> Added {}", normalized);
- }
+std::optional<std::tuple<std::string, YAML::Node>> Companion::GetNodeByAddr(const uint32_t addr){
+ if(!this->gAddrMap.contains(this->gCurrentFile)){
+ return std::nullopt;
+ }
- auto end = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
- SPDLOG_INFO("Done! Took {}ms", end.count() - start.count());
- SPDLOG_INFO("Exported to {}", output);
- spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
- SPDLOG_INFO("------------------------------------------------");
+ if(!this->gAddrMap[this->gCurrentFile].contains(addr)){
+ return std::nullopt;
+ }
+
+ return this->gAddrMap[this->gCurrentFile][addr];
+}
- wrapper.Close();
+std::string Companion::NormalizeAsset(const std::string& name) const {
+ auto path = fs::path(this->gCurrentFile).stem().string() + "_" + name;
+ return path;
} \ No newline at end of file
diff --git a/src/Companion.h b/src/Companion.h
index 8d131fb..1223f91 100644
--- a/src/Companion.h
+++ b/src/Companion.h
@@ -1,28 +1,71 @@
#pragma once
#include <string>
-#include <utility>
+#include <optional>
+#include <filesystem>
#include <vector>
+#include <fstream>
#include <unordered_map>
-#include <filesystem>
-#include "factories/RawFactory.h"
+#include <variant>
+#include "factories/BaseFactory.h"
#include "n64/Cartridge.h"
+class SWrapper;
+namespace fs = std::filesystem;
+
+enum class GBIVersion {
+ f3d,
+ f3dex,
+ f3db,
+ f3dex2,
+ f3dexb,
+};
+
+enum class GBIMinorVersion {
+ None,
+ Mk64,
+};
+
class Companion {
public:
static Companion* Instance;
- explicit Companion(std::filesystem::path rom) : gRomPath(std::move(rom)) {}
- void Init();
+ explicit Companion(std::filesystem::path rom, bool otr, bool debug) : gRomPath(std::move(rom)), gOTRMode(otr), gIsDebug(debug) {}
+ void Init(ExportType type);
void Process();
- N64::Cartridge* GetCartridge() { return this->cartridge; }
+ bool IsOTRMode() { return this->gOTRMode; }
+ bool IsDebug() { return this->gIsDebug; }
+ N64::Cartridge* GetCartridge() { return this->gCartridge; }
+ std::vector<uint8_t> GetRomData() { return this->gRomData; }
+ std::string GetOutputPath() { return this->gOutputPath; }
+ GBIVersion GetGBIVersion() { return this->gGBIVersion; }
+ GBIMinorVersion GetGBIMinorVersion() { return this->gGBIMinorVersion; }
+ std::optional<std::uint32_t> GetSegmentedAddr(uint8_t segment);
+ std::optional<std::tuple<std::string, YAML::Node>> GetNodeByAddr(uint32_t addr);
+ std::optional<std::shared_ptr<BaseFactory>> GetFactory(const std::string& type);
static void Pack(const std::string& folder, const std::string& output);
+ std::string NormalizeAsset(const std::string& name) const;
+ void RegisterAsset(const std::string& name, YAML::Node& node);
private:
- std::filesystem::path gRomPath;
+ bool gOTRMode = false;
+ bool gIsDebug = false;
+ GBIVersion gGBIVersion = GBIVersion::f3d;
+ GBIMinorVersion gGBIMinorVersion = GBIMinorVersion::None;
+ std::string gOutputPath;
+ std::string gCurrentFile;
+ ExportType gExporterType;
+ fs::path gCurrentDirectory;
+ N64::Cartridge* gCartridge;
std::vector<uint8_t> gRomData;
- std::unordered_map<std::string, RawFactory*> gFactories;
- N64::Cartridge* cartridge;
+ std::filesystem::path gRomPath;
+ std::vector<uint32_t> gSegments;
+
+ std::variant<std::vector<std::string>, std::string> gWriteOrder;
+ std::unordered_map<std::string, std::shared_ptr<BaseFactory>> gFactories;
+ std::map<std::string, std::map<std::string, std::pair<YAML::Node, bool>>> gAssetDependencies;
+ std::map<std::string, std::map<std::string, std::vector<std::pair<uint32_t, std::string>>>> gWriteMap;
+ std::unordered_map<std::string, std::unordered_map<uint32_t, std::tuple<std::string, YAML::Node>>> gAddrMap;
- void RegisterFactory(const std::string& type, RawFactory* factory);
- RawFactory* GetFactory(const std::string& type);
-}; \ No newline at end of file
+ void RegisterFactory(const std::string& type, const std::shared_ptr<BaseFactory>& factory);
+ void ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary);
+};
diff --git a/src/factories/AudioHeaderFactory.cpp b/src/factories/AudioHeaderFactory.cpp
index b493458..b33d057 100644
--- a/src/factories/AudioHeaderFactory.cpp
+++ b/src/factories/AudioHeaderFactory.cpp
@@ -3,8 +3,8 @@
#include <vector>
#include "audio/AudioManager.h"
-bool AudioHeaderFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+std::optional<std::shared_ptr<IParsedData>> AudioHeaderFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
AudioManager::Instance = new AudioManager();
AudioManager::Instance->initialize(buffer, data);
- return false;
+ return std::nullopt;
} \ No newline at end of file
diff --git a/src/factories/AudioHeaderFactory.h b/src/factories/AudioHeaderFactory.h
index bd7336e..5372eb5 100644
--- a/src/factories/AudioHeaderFactory.h
+++ b/src/factories/AudioHeaderFactory.h
@@ -1,9 +1,11 @@
#pragma once
-#include "RawFactory.h"
+#include "BaseFactory.h"
-class AudioHeaderFactory : public RawFactory {
+class AudioHeaderFactory : public BaseFactory {
public:
- AudioHeaderFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {};
+ }
}; \ No newline at end of file
diff --git a/src/factories/BankFactory.cpp b/src/factories/BankFactory.cpp
index 30d554f..6b4dc93 100644
--- a/src/factories/BankFactory.cpp
+++ b/src/factories/BankFactory.cpp
@@ -1,39 +1,32 @@
#include "BankFactory.h"
-
-#include <vector>
-#include "audio/AudioManager.h"
+#include "utils/MIODecoder.h"
+#include "Companion.h"
#include "audio/samples_table.h"
-#include "binarytools/BinaryReader.h"
-bool BankFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- auto banks = AudioManager::Instance->get_banks();
- auto bankId = data["id"].as<uint32_t>();
- auto bank = banks[bankId];
+void BankBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto bank = std::static_pointer_cast<BankData>(raw);
- auto gSampleTable = this->GetCartridge()->GetCountry() == N64::CountryCode::Japan ? gJPSampleTable : gUSSampleTable;
+ WriteHeader(writer, LUS::ResourceType::Bank, 0);
+ writer.Write(bank->mBankId);
+ writer.Write((uint32_t) bank->mBank.insts.size());
+ for (auto& instrument : bank->mBank.insts) {
+ writer.Write((uint8_t) instrument.valid);
+ if(!instrument.valid) continue;
- WRITE_HEADER(LUS::ResourceType::Bank, 0);
-
- WRITE_U32(bankId);
- WRITE_U32(bank.insts.size());
- for(auto &instrument : bank.insts){
- WRITE_U8(instrument.valid);
- if(!instrument.valid){
- continue;
- }
- WRITE_U8(instrument.releaseRate);
- WRITE_U8(instrument.normalRangeLo);
- WRITE_U8(instrument.normalRangeHi);
+ writer.Write((uint8_t) instrument.releaseRate);
+ writer.Write((uint8_t) instrument.normalRangeLo);
+ writer.Write((uint8_t) instrument.normalRangeHi);
- auto envelope = bank.envelopes[instrument.envelope];
+ auto envelope = bank->mBank.envelopes[instrument.envelope];
if(!envelope.entries.empty()){
- WRITE_U32(envelope.entries.size());
- for(auto &entry : envelope.entries){
- writer->Write(entry.delay);
- writer->Write(entry.arg);
+ writer.Write((uint32_t) envelope.entries.size());
+ for (auto& entry : envelope.entries) {
+ writer.Write((uint16_t) entry.delay);
+ writer.Write((uint16_t) entry.arg);
}
} else {
- WRITE_U32(0);
+ writer.Write((uint32_t) 0);
}
uint32_t soundFlags = 0;
@@ -50,47 +43,55 @@ bool BankFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vect
soundFlags |= (1 << 2);
}
- WRITE_U32(soundFlags);
+ writer.Write((uint32_t) soundFlags);
if(hasLo){
auto value = instrument.soundLo.value();
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
- writer->Write(std::string(gSampleTable[idx]));
- writer->Write(value.tuning);
+ uint32_t idx = AudioManager::Instance->get_index(bank->mBank.samples[value.offset]);
+ writer.Write(std::string(bank->mSampleTable[idx]));
+ writer.Write(value.tuning);
}
if(hasMed){
auto value = instrument.soundMed.value();
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
- writer->Write(std::string(gSampleTable[idx]));
- writer->Write(value.tuning);
+ uint32_t idx = AudioManager::Instance->get_index(bank->mBank.samples[value.offset]);
+ writer.Write(std::string(bank->mSampleTable[idx]));
+ writer.Write(value.tuning);
}
if(hasHi){
auto value = instrument.soundHi.value();
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
- writer->Write(std::string(gSampleTable[idx]));
- writer->Write(value.tuning);
+ uint32_t idx = AudioManager::Instance->get_index(bank->mBank.samples[value.offset]);
+ writer.Write(std::string(bank->mSampleTable[idx]));
+ writer.Write(value.tuning);
}
}
- WRITE_U32(bank.drums.size());
- for(auto &drum : bank.drums){
- WRITE_U8(drum.releaseRate);
- WRITE_U8(drum.pan);
- auto envelope = bank.envelopes[drum.envelope];
+ writer.Write((uint32_t) bank->mBank.drums.size());
+ for(auto &drum : bank->mBank.drums){
+ writer.Write((uint8_t) drum.releaseRate);
+ writer.Write((uint8_t) drum.pan);
+ auto envelope = bank->mBank.envelopes[drum.envelope];
if(!envelope.entries.empty()){
- WRITE_U32(envelope.entries.size());
+ writer.Write((uint32_t) envelope.entries.size());
for(auto &entry : envelope.entries){
- writer->Write(entry.delay);
- writer->Write(entry.arg);
+ writer.Write(entry.delay);
+ writer.Write(entry.arg);
}
} else {
- WRITE_U32(0);
+ writer.Write((uint32_t) 0);
}
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[drum.sound.offset]);
- std::string out = std::string(gSampleTable[idx]);
- writer->Write(out);
- writer->Write(drum.sound.tuning);
+ uint32_t idx = AudioManager::Instance->get_index(bank->mBank.samples[drum.sound.offset]);
+ std::string out = std::string(bank->mSampleTable[idx]);
+ writer.Write(out);
+ writer.Write(drum.sound.tuning);
}
- return true;
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> BankFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
+ auto banks = AudioManager::Instance->get_banks();
+ auto bankId = data["id"].as<uint32_t>();
+
+ auto gSampleTable = Companion::Instance->GetCartridge()->GetCountry() == N64::CountryCode::Japan ? gJPSampleTable : gUSSampleTable;
+ return std::make_shared<BankData>(banks[bankId], bankId, gSampleTable);
} \ No newline at end of file
diff --git a/src/factories/BankFactory.h b/src/factories/BankFactory.h
index c19f137..bdabe10 100644
--- a/src/factories/BankFactory.h
+++ b/src/factories/BankFactory.h
@@ -1,9 +1,27 @@
#pragma once
-#include "RawFactory.h"
+#include "BaseFactory.h"
+#include "audio/AudioManager.h"
-class BankFactory : public RawFactory {
+class BankData : public IParsedData {
public:
- BankFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+ Bank mBank;
+ uint32_t mBankId;
+ const char** mSampleTable;
+
+ BankData(Bank bank, uint32_t bankId, const char** sampleTable) : mBank(bank), mBankId(bankId), mSampleTable(sampleTable) {}
+};
+
+class BankBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class BankFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Binary, BankBinaryExporter)
+ };
+ }
}; \ No newline at end of file
diff --git a/src/factories/BaseFactory.cpp b/src/factories/BaseFactory.cpp
new file mode 100644
index 0000000..c0da8cd
--- /dev/null
+++ b/src/factories/BaseFactory.cpp
@@ -0,0 +1,17 @@
+#include "BaseFactory.h"
+
+void BaseExporter::WriteHeader(LUS::BinaryWriter &writer, LUS::ResourceType resType, int32_t version) {
+ writer.Write((uint8_t)(LUS::Endianness::Native)); // 0x00
+ writer.Write((uint8_t)0); // 0x01
+ writer.Write((uint8_t)0); // 0x02
+ writer.Write((uint8_t)0); // 0x03
+ writer.Write((uint32_t) resType); // 0x04
+ writer.Write((uint32_t) version); // 0x08
+ writer.Write((uint64_t) 0xDEADBEEFDEADBEEF); // id, 0x0C
+ writer.Write((uint32_t) 0); // 0x10
+ writer.Write((uint64_t) 0); // ROM CRC, 0x14
+ writer.Write((uint32_t) 0); // ROM Enum, 0x1C
+
+ while (writer.GetBaseAddress() < 0x40)
+ writer.Write((uint32_t)0); // To be used at a later date!
+} \ No newline at end of file
diff --git a/src/factories/BaseFactory.h b/src/factories/BaseFactory.h
new file mode 100644
index 0000000..365816b
--- /dev/null
+++ b/src/factories/BaseFactory.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "ResourceType.h"
+#include "n64/Cartridge.h"
+#include <cstdint>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include <string>
+#include <yaml-cpp/yaml.h>
+#include <strhash64/StrHash64.h>
+#include <binarytools/BinaryWriter.h>
+#include <binarytools/BinaryReader.h>
+
+#define REGISTER(type, c) { ExportType::type, std::make_shared<c>() },
+
+#define SEGMENT_OFFSET(a) ((uint32_t)(a)&0x00FFFFFF)
+#define SEGMENT_NUMBER(x) ((x >> 24) & 0xFF)
+
+#define tab "\t"
+#define fourSpaceTab " "
+
+enum class ExportType {
+ Header,
+ Code,
+ Binary,
+};
+
+class IParsedData {};
+
+template<typename T>
+class GenericData : public IParsedData {
+public:
+ T mData;
+};
+
+class BaseExporter {
+public:
+ virtual void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) = 0;
+ static void WriteHeader(LUS::BinaryWriter& write, LUS::ResourceType resType, int32_t version);
+};
+
+class BaseFactory {
+public:
+ virtual std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) = 0;
+ std::optional<std::shared_ptr<BaseExporter>> GetExporter(ExportType type) {
+ auto exporters = this->GetExporters();
+ if (exporters.find(type) != exporters.end()) {
+ return exporters[type];
+ }
+ return std::nullopt;
+ }
+private:
+ virtual std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() = 0;
+}; \ No newline at end of file
diff --git a/src/factories/BlobFactory.cpp b/src/factories/BlobFactory.cpp
index cc66463..886a206 100644
--- a/src/factories/BlobFactory.cpp
+++ b/src/factories/BlobFactory.cpp
@@ -1,28 +1,43 @@
#include "BlobFactory.h"
-#include <cstring>
#include "utils/MIODecoder.h"
+#include <iomanip>
-namespace fs = std::filesystem;
+void BlobCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto data = std::static_pointer_cast<RawBuffer>(raw)->mBuffer;
-bool BlobFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ write << "u8 " << entryName << "[] = {\n" << tab;
+ for (int i = 0; i < data.size(); i++) {
+ if ((i % 15 == 0) && i != 0) {
+ write << "\n" << tab;
+ }
- WRITE_HEADER(LUS::ResourceType::Blob, 0);
+ write << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int) data[i] << ", ";
+ }
+ write << "\n};\n";
+}
+
+void BlobBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto data = std::static_pointer_cast<RawBuffer>(raw)->mBuffer;
+
+ WriteHeader(writer, LUS::ResourceType::Blob, 0);
+ writer.Write((uint32_t) data.size());
+ writer.Write((char*) data.data(), data.size());
+ writer.Finish(write);
+}
- auto size = data["size"].as<size_t>();
- auto offset = data["offset"].as<size_t>();
+std::optional<std::shared_ptr<IParsedData>> BlobFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
+ auto size = data["size"].as<uint32_t>();
+ auto offset = data["offset"].as<uint32_t>();
+ std::shared_ptr<RawBuffer> result;
- auto* blob = new uint8_t[size];
if(data["mio0"]){
auto decoded = MIO0Decoder::Decode(buffer, offset);
- auto cursor = data["mio0"].as<size_t>();
- memcpy(blob, decoded.data() + cursor, size);
+ auto cursor = data["mio0"].as<uint32_t>();
+ result = std::make_shared<RawBuffer>(decoded.data() + cursor, size);
} else {
- memcpy(blob, buffer.data() + offset, size);
+ result = std::make_shared<RawBuffer>(buffer.data() + offset, size);
}
- WRITE_U32(size); // Blob Data Size
- WRITE_ARRAY(blob, size); // Blob Data
-
- delete[] blob;
- return true;
-}
+ return result;
+} \ No newline at end of file
diff --git a/src/factories/BlobFactory.h b/src/factories/BlobFactory.h
index 302fb01..c199618 100644
--- a/src/factories/BlobFactory.h
+++ b/src/factories/BlobFactory.h
@@ -1,9 +1,22 @@
#pragma once
-#include "RawFactory.h"
+#include "BaseFactory.h"
+#include "../types/RawBuffer.h"
+class BlobBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
-class BlobFactory : public RawFactory {
+class BlobCodeExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class BlobFactory : public BaseFactory {
public:
- BlobFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Binary, BlobBinaryExporter)
+ REGISTER(Code, BlobCodeExporter)
+ };
+ }
}; \ No newline at end of file
diff --git a/src/factories/DisplayListFactory.cpp b/src/factories/DisplayListFactory.cpp
new file mode 100644
index 0000000..ec28ed0
--- /dev/null
+++ b/src/factories/DisplayListFactory.cpp
@@ -0,0 +1,377 @@
+#include "DisplayListFactory.h"
+#include "DisplayListOverrides.h"
+#include "utils/MIODecoder.h"
+#include "spdlog/spdlog.h"
+#include "Companion.h"
+#include <gfxd.h>
+#include <fstream>
+
+#define C0(pos, width) ((w0 >> (pos)) & ((1U << width) - 1))
+
+template< typename T >
+std::string to_hex(T number, const bool append0x = true) {
+ std::stringstream stream;
+ if(append0x) {
+ stream << "0x";
+ }
+ stream << std::setfill ('0') << std::setw(sizeof(T)*2)
+ << std::hex << number;
+
+ auto format = stream.str();
+ std::transform(format.begin(), format.end(), format.begin(), ::toupper);
+ return format;
+}
+
+void GFXDSetGBIVersion(){
+ switch (Companion::Instance->GetGBIVersion()) {
+ case GBIVersion::f3d:
+ gfxd_target(gfxd_f3d);
+ break;
+ case GBIVersion::f3dex:
+ gfxd_target(gfxd_f3dex);
+ break;
+ case GBIVersion::f3db:
+ gfxd_target(gfxd_f3db);
+ break;
+ case GBIVersion::f3dex2:
+ gfxd_target(gfxd_f3dex2);
+ break;
+ case GBIVersion::f3dexb:
+ gfxd_target(gfxd_f3dexb);
+ break;
+ }
+}
+
+void DListHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
+ const auto symbol = node["symbol"] ? node["symbol"].as<std::string>() : entryName;
+
+ if(Companion::Instance->IsOTRMode()){
+ write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
+ return;
+ }
+
+ write << "extern Gfx " << symbol << "[];\n";
+}
+
+void DListCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ const auto cmds = std::static_pointer_cast<DListData>(raw)->mGfxs;
+ const auto symbol = node["symbol"].as<std::string>();
+ const auto offset = node["offset"].as<uint32_t>();
+ char out[0xFFFF] = {0};
+
+ gfxd_input_buffer(cmds.data(), sizeof(uint32_t) * cmds.size());
+ gfxd_output_buffer(out, sizeof(out));
+
+ gfxd_endian(gfxd_endian_host, sizeof(uint32_t));
+ gfxd_macro_fn([] {
+ auto gfx = static_cast<const Gfx*>(gfxd_macro_data());
+ auto opcode = (gfx->words.w0 >> 24) & 0xFF;
+
+ gfxd_puts(fourSpaceTab);
+
+ #define QUAD 0xB5
+ #define TRI2 0xB1
+
+ switch(opcode) {
+
+ // For mk64 only
+ case QUAD:
+ if (Companion::Instance->GetGBIMinorVersion() == GBIMinorVersion::Mk64) {
+ GFXDOverride::Quadrangle(gfx);
+ } else {
+ gfxd_macro_dflt();
+ }
+ break;
+ // Prevents mix and matching of quadrangle commands. Forces 2TRI only.
+ case TRI2:
+ GFXDOverride::Triangle2(gfx);
+ break;
+ default:
+ gfxd_macro_dflt();
+ break;
+ }
+
+ gfxd_puts(",\n");
+ return 0;
+ });
+
+ gfxd_vtx_callback(GFXDOverride::Vtx);
+ gfxd_timg_callback(GFXDOverride::Texture);
+ gfxd_dl_callback(GFXDOverride::DisplayList);
+ gfxd_lightsn_callback(GFXDOverride::Light);
+ GFXDSetGBIVersion();
+
+ if (Companion::Instance->IsDebug()) {
+ write << "// 0x" << std::hex << std::uppercase << offset << "\n";
+ }
+
+ gfxd_puts(("Gfx " + symbol + "[] = {\n").c_str());
+ gfxd_execute();
+ gfxd_puts("};\n\n");
+
+ write << std::string(out);
+}
+
+void DebugDisplayList(uint32_t w0, uint32_t w1){
+ uint32_t dlist[] = {w0, w1};
+ gfxd_input_buffer(dlist, sizeof(dlist));
+ gfxd_output_fd(fileno(stdout));
+ gfxd_endian(gfxd_endian_host, sizeof(uint32_t));
+ gfxd_macro_fn([](){
+ gfxd_puts("> ");
+ gfxd_macro_dflt();
+ gfxd_puts("\n");
+ return 0;
+ });
+ gfxd_vtx_callback(GFXDOverride::Vtx);
+ gfxd_timg_callback(GFXDOverride::Texture);
+ gfxd_dl_callback(GFXDOverride::DisplayList);
+ //gfxd_light_callback(GFXDOverride::Light);
+ GFXDSetGBIVersion();
+ gfxd_execute();
+ int bp = 0;
+}
+
+void DListBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto cmds = std::static_pointer_cast<DListData>(raw)->mGfxs;
+ auto writer = LUS::BinaryWriter();
+
+ WriteHeader(writer, LUS::ResourceType::DisplayList, 0);
+
+ while (writer.GetBaseAddress() % 8 != 0)
+ writer.Write(static_cast<uint8_t>(0xFF));
+
+ auto bhash = CRC64((*replacement).c_str());
+ writer.Write(static_cast<uint32_t>((G_MARKER << 24)));
+ writer.Write(0xBEEFBEEF);
+ writer.Write(static_cast<uint32_t>(bhash >> 32));
+ writer.Write(static_cast<uint32_t>(bhash & 0xFFFFFFFF));
+
+#ifndef _WIN32
+#define case case (uint8_t)
+#endif
+
+ for(size_t i = 0; i < cmds.size(); i+=2){
+ auto w0 = cmds[i];
+ auto w1 = cmds[i + 1];
+ uint8_t opcode = w0 >> 24;
+
+ switch (opcode) {
+ case G_VTX: {
+ auto nvtx = (C0(0, 16)) / sizeof(Vtx);
+ auto didx = C0(16, 4);
+ uint32_t ptr = SEGMENT_OFFSET(w1);
+
+ if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found vtx: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(decl.value()));
+
+ // TODO: Find a better way to do this because its going to break on other games
+ Gfx value = gsSPVertexOTR(didx, nvtx, 0);
+
+ SPDLOG_INFO("gsSPVertex({}, {}, 0x{:X})", nvtx, didx, ptr);
+
+ w0 = value.words.w0;
+ w1 = value.words.w1;
+
+ writer.Write(w0);
+ writer.Write(w1);
+
+ w0 = hash >> 32;
+ w1 = hash & 0xFFFFFFFF;
+ } else {
+ SPDLOG_WARN("Warning: Could not find vtx at 0x{:X}", ptr);
+ }
+ break;
+ }
+ case G_DL: {
+ auto ptr = SEGMENT_OFFSET(w1);
+ auto dec = Companion::Instance->GetNodeByAddr(ptr);
+
+ Gfx value = gsSPDisplayListOTRHash(ptr);
+ w0 = value.words.w0;
+ w1 = value.words.w1;
+
+ writer.Write(w0);
+ writer.Write(w1);
+
+ if(dec.has_value()){
+ uint64_t hash = CRC64(std::get<0>(dec.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value()));
+ w0 = hash >> 32;
+ w1 = hash & 0xFFFFFFFF;
+ } else {
+ SPDLOG_WARN("Warning: Could not find display list at 0x{:X}", ptr);
+ }
+ break;
+ }
+ case G_SETTIMG: {
+ auto ptr = SEGMENT_OFFSET(w1);
+ auto dec = Companion::Instance->GetNodeByAddr(ptr);
+
+ Gfx value = gsDPSetTextureImage(C0(21, 3), C0(19, 2), C0(0, 10), ptr);
+ w0 = value.words.w0 & 0x00FFFFFF;
+ w0 += (G_SETTIMG_OTR_HASH << 24);
+ w1 = value.words.w1;
+
+ writer.Write(w0);
+ writer.Write(w1);
+
+ if(dec.has_value()){
+ uint64_t hash = CRC64(std::get<0>(dec.value()).c_str());
+ SPDLOG_INFO("Found texture: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value()));
+ w0 = hash >> 32;
+ w1 = hash & 0xFFFFFFFF;
+ } else {
+ SPDLOG_WARN("Warning: Could not find texture at 0x{:X}", ptr);
+ }
+ break;
+ }
+ default: break;
+ }
+
+ writer.Write(w0);
+ writer.Write(w1);
+ }
+
+#undef case
+
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ const auto gbi = Companion::Instance->GetGBIVersion();
+
+ const auto mio0 = node["mio0"].as<uint32_t>();
+ const auto offset = node["offset"].as<int32_t>();
+ auto decoded = MIO0Decoder::Decode(buffer, mio0);
+
+ LUS::BinaryReader reader(decoded.data(), decoded.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+ reader.Seek(offset, LUS::SeekOffsetType::Start);
+
+ std::vector<uint32_t> gfxs;
+ auto processing = true;
+
+ while (processing){
+ auto w0 = reader.ReadUInt32();
+ auto w1 = reader.ReadUInt32();
+
+ uint8_t opcode = w0 >> 24;
+ gfxs.push_back(w0);
+ gfxs.push_back(w1);
+
+ switch (opcode) {
+ case static_cast<uint8_t>(G_ENDDL):
+ processing = false;
+ break;
+ case static_cast<uint8_t>(G_DL): {
+ auto ptr = SEGMENT_OFFSET(w1);
+ auto dec = Companion::Instance->GetNodeByAddr(ptr);
+
+ if(!dec.has_value()){
+ SPDLOG_INFO("Addr to Display list command at 0x{:X} not in yaml, autogenerating it", w1);
+ auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1));
+ if(!addr.has_value()) {
+ SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1));
+ break;
+ }
+
+ auto rom = Companion::Instance->GetRomData();
+ auto factory = Companion::Instance->GetFactory("GFX")->get();
+ std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_dl_" + to_hex(w1, false));
+ YAML::Node dl;
+ dl["type"] = "GFX";
+ dl["mio0"] = addr.value();
+ dl["offset"] = ptr;
+ dl["symbol"] = output;
+ auto result = factory->parse(rom, dl);
+
+ if(!result.has_value()){
+ break;
+ }
+
+ Companion::Instance->RegisterAsset(output, dl);
+ } else {
+ SPDLOG_WARN("Warning: Could not find display list at 0x{:X}", ptr);
+ }
+ break;
+ }
+ // Lights1
+ case static_cast<uint8_t>(G_MOVEMEM): {
+ uint32_t ptr = SEGMENT_OFFSET(w1);
+
+ // Ignore if not a Lights1 command
+ if ( ( (w0 >> 16) & 0xFF ) != G_MV_L1) {
+ break;
+ }
+
+ if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); !decl.has_value()){
+ SPDLOG_INFO("Addr to Lights1 command at 0x{:X} not in yaml, autogenerating it", w1);
+ auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1));
+ if(!addr.has_value()) {
+ SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1));
+ break;
+ }
+ auto rom = Companion::Instance->GetRomData();
+ auto factory = Companion::Instance->GetFactory("LIGHTS")->get();
+ std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_lights1_" + to_hex(w1, false));
+ YAML::Node light;
+ light["type"] = "lights";
+ light["mio0"] = addr.value();
+ light["offset"] = ptr;
+ light["symbol"] = output;
+ auto result = factory->parse(rom, light);
+ if(result.has_value()){
+ Companion::Instance->RegisterAsset(output, light);
+ }
+ }
+ break;
+ }
+ case static_cast<uint8_t>(G_VTX): {
+ uint32_t nvtx;
+
+ switch (gbi) {
+ case GBIVersion::f3dex2:
+ nvtx = C0(12, 8);
+ break;
+ case GBIVersion::f3dex:
+ case GBIVersion::f3dexb:
+ nvtx = C0(10, 6);
+ break;
+ default:
+ nvtx = (C0(0, 16)) / sizeof(Vtx);
+ break;
+ }
+
+ uint32_t ptr = SEGMENT_OFFSET(w1);
+
+ if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); !decl.has_value()){
+ SPDLOG_INFO("Addr to Vtx array at 0x{:X} not in yaml, autogenerating it", w1);
+ auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1));
+ if(!addr.has_value()) {
+ SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1));
+ break;
+ }
+
+ auto rom = Companion::Instance->GetRomData();
+ auto factory = Companion::Instance->GetFactory("VTX")->get();
+ std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_vtx_" + to_hex(w1, false));
+ YAML::Node vtx;
+ vtx["type"] = "VTX";
+ vtx["mio0"] = addr.value();
+ vtx["offset"] = ptr;
+ vtx["count"] = nvtx;
+ vtx["symbol"] = output;
+ auto result = factory->parse(rom, vtx);
+ if(result.has_value()){
+ Companion::Instance->RegisterAsset(output, vtx);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return std::make_shared<DListData>(gfxs);
+} \ No newline at end of file
diff --git a/src/factories/DisplayListFactory.h b/src/factories/DisplayListFactory.h
new file mode 100644
index 0000000..1a27867
--- /dev/null
+++ b/src/factories/DisplayListFactory.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "BaseFactory.h"
+#include "n64/CommandMacros.h"
+
+#define F3DEX
+#define _LANGUAGE_C
+#include "n64/gbi.h"
+
+class DListData : public IParsedData {
+public:
+ std::vector<uint32_t> mGfxs;
+
+ explicit DListData(std::vector<uint32_t> gfxs) : mGfxs(gfxs) {}
+};
+
+class DListHeaderExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class DListBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class DListCodeExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class DListFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Header, DListHeaderExporter)
+ REGISTER(Binary, DListBinaryExporter)
+ REGISTER(Code, DListCodeExporter)
+ };
+ }
+};
diff --git a/src/factories/DisplayListOverrides.cpp b/src/factories/DisplayListOverrides.cpp
new file mode 100644
index 0000000..7da6ecf
--- /dev/null
+++ b/src/factories/DisplayListOverrides.cpp
@@ -0,0 +1,103 @@
+#include "DisplayListOverrides.h"
+
+#include "DisplayListFactory.h"
+#include "spdlog/spdlog.h"
+#include "Companion.h"
+
+#include <gfxd.h>
+#include <string>
+
+namespace GFXDOverride {
+
+void Triangle2(const Gfx* gfx) {
+ auto w0 = gfx->words.w0;
+ auto w1 = gfx->words.w1;
+
+ auto v1 = std::to_string( ((w0 >> 16) & 0xFF) / 2 );
+ auto v2 = std::to_string( ((w0 >> 8) & 0xFF) / 2 );
+ auto v3 = std::to_string( (w0 & 0xFF) / 2 );
+
+ auto v4 = std::to_string( ((w1 >> 16) & 0xFF) / 2 );
+ auto v5 = std::to_string( ((w1 >> 8) & 0xFF) / 2 );
+ auto v6 = std::to_string( (w1 & 0xFF) / 2 );
+ auto flag = "0";
+
+ const auto str = v1 + ", " + v2 + ", " + v3 + ", " + flag + ", " + v4 + ", " + v5 + ", " + v6 + ", " + flag;
+
+ gfxd_puts("gsSP2Triangles(");
+ gfxd_puts(str.c_str());
+ gfxd_puts(")");
+}
+
+void Quadrangle(const Gfx* gfx) {
+ auto w1 = gfx->words.w1;
+
+ auto v1 = std::to_string( ((w1 >> 16) & 0xFF) / 2 );
+ auto v2 = std::to_string( ((w1 >> 8) & 0xFF) / 2 );
+ auto v3 = std::to_string( (w1 & 0xFF) / 2 );
+ auto v4 = std::to_string( ((w1 >> 24) & 0xFF) / 2 );
+ auto flag = "0";
+
+ const auto str = v1 + ", " + v2 + ", " + v3 + ", " + v4 + ", " + flag;
+
+ gfxd_puts("gsSP1Quadrangle(");
+ gfxd_puts(str.c_str());
+ gfxd_puts(")");
+}
+
+int Vtx(uint32_t vtx, int32_t num) {
+ uint32_t ptr = SEGMENT_OFFSET(vtx);
+ if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); decl.has_value()){
+ auto node = std::get<1>(decl.value());
+ auto symbol = node["symbol"].as<std::string>();
+ SPDLOG_INFO("Wrote vtx: 0x{:X} Symbol: {}", ptr, symbol);
+ gfxd_puts(symbol.c_str());
+ return 1;
+ }
+
+ SPDLOG_WARN("Warning: Could not find vtx at 0x{:X}", ptr);
+ return 0;
+}
+
+int Texture(uint32_t timg, int32_t fmt, int32_t siz, int32_t width, int32_t height, int32_t pal) {
+ uint32_t ptr = SEGMENT_OFFSET(timg);
+ if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); decl.has_value()){
+ auto node = std::get<1>(decl.value());
+ auto symbol = node["symbol"].as<std::string>();
+ SPDLOG_INFO("Wrote texture: 0x{:X} Symbol: {}", ptr, symbol);
+ gfxd_puts(symbol.c_str());
+ return 1;
+ }
+
+ SPDLOG_WARN("Warning: Could not find texture at 0x{:X}", ptr);
+ return 0;
+}
+
+int Light(uint32_t lightsn, int32_t count) {
+ uint32_t ptr = SEGMENT_OFFSET(lightsn);
+ if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); decl.has_value()){
+ auto node = std::get<1>(decl.value());
+ auto symbol = node["symbol"].as<std::string>();
+ SPDLOG_INFO("Wrote light: 0x{:X} Symbol: {}", ptr, symbol);
+ gfxd_puts(symbol.c_str());
+ return 1;
+ }
+
+ SPDLOG_WARN("Warning: Could not find light at 0x{:X}", ptr);
+ return 0;
+}
+
+int DisplayList(uint32_t dl) {
+ uint32_t ptr = SEGMENT_OFFSET(dl);
+ if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); decl.has_value()){
+ auto node = std::get<1>(decl.value());
+ auto symbol = node["symbol"].as<std::string>();
+ SPDLOG_INFO("Wrote display list: 0x{:X} Symbol: {}", ptr, symbol);
+ gfxd_puts(symbol.c_str());
+ return 1;
+ }
+
+ SPDLOG_WARN("Warning: Could not find display list to override at 0x{:X}", ptr);
+ return 0;
+}
+}
diff --git a/src/factories/DisplayListOverrides.h b/src/factories/DisplayListOverrides.h
new file mode 100644
index 0000000..4eba137
--- /dev/null
+++ b/src/factories/DisplayListOverrides.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <cstdint>
+#include "DisplayListFactory.h"
+
+namespace GFXDOverride {
+void Quadrangle(const Gfx* gfx);
+void Triangle2(const Gfx* gfx);
+int Vtx(uint32_t vtx, int32_t num);
+int Texture(uint32_t timg, int32_t fmt, int32_t siz, int32_t width, int32_t height, int32_t pal);
+int Light(uint32_t lightsn, int32_t count);
+int DisplayList(uint32_t dl);
+}; \ No newline at end of file
diff --git a/src/factories/LightsFactory.cpp b/src/factories/LightsFactory.cpp
new file mode 100644
index 0000000..a0cf692
--- /dev/null
+++ b/src/factories/LightsFactory.cpp
@@ -0,0 +1,94 @@
+#include "LightsFactory.h"
+
+#include "utils/MIODecoder.h"
+#include "spdlog/spdlog.h"
+#include "Companion.h"
+
+void LightsHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
+ const auto symbol = node["symbol"] ? node["symbol"].as<std::string>() : entryName;
+
+ if(Companion::Instance->IsOTRMode()){
+ write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
+ return;
+ }
+
+ write << "extern Lights " << symbol << ";\n";
+}
+
+void LightsCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto light = std::static_pointer_cast<LightsData>(raw)->mLights;
+ auto symbol = node["symbol"].as<std::string>();
+
+ write << "Lights1 " << symbol << " = gdSPDefLights1 (\n";
+
+ // Ambient
+ auto r = (int16_t) light.a.l.col[0];
+ auto g = (int16_t) light.a.l.col[1];
+ auto b = (int16_t) light.a.l.col[2];
+
+ // Diffuse
+ auto r2 = (int16_t) light.l[0].l.col[0];
+ auto g2 = (int16_t) light.l[0].l.col[1];
+ auto b2 = (int16_t) light.l[0].l.col[2];
+
+ // Direction
+ auto x = (int16_t) light.l[0].l.dir[0];
+ auto y = (int16_t) light.l[0].l.dir[1];
+ auto z = (int16_t) light.l[0].l.dir[2];
+
+ SPDLOG_INFO("Read light: {:X} {:X} {:X} {:X} {:X}", r, g, b, r2, g2);
+
+ write << fourSpaceTab;
+ write << r << ", " << g << ", " << b << ",\n";
+ write << fourSpaceTab;
+ write << r2 << ", " << g2 << ", " << b2 << ", " << x << ", " << y << ", " << z << "\n";
+
+ write << ");\n\n";
+}
+
+void LightsBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto light = std::static_pointer_cast<LightsData>(raw)->mLights;
+ auto writer = LUS::BinaryWriter();
+
+ WriteHeader(writer, LUS::ResourceType::Lights, 0);
+ writer.Write((uint32_t) sizeof(light));
+
+}
+
+std::optional<std::shared_ptr<IParsedData>> LightsFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto mio0 = node["mio0"].as<size_t>();
+ auto offset = node["offset"].as<uint32_t>();
+ auto symbol = node["symbol"].as<std::string>();
+
+ auto decoded = MIO0Decoder::Decode(buffer, mio0);
+ LUS::BinaryReader reader(decoded.data() + offset, sizeof(Lights1Raw));
+
+ reader.SetEndianness(LUS::Endianness::Big);
+ Lights1Raw lights;
+ // Directional light
+
+ // Ambient
+ auto r = reader.ReadInt8();
+ auto g = reader.ReadInt8();
+ auto b = reader.ReadInt8();
+ //auto nil = reader.ReadInt32();
+ reader.Seek(5, LUS::SeekOffsetType::Current);
+
+ // Diffuse copy
+ auto r2 = reader.ReadUByte();
+ auto g2 = reader.ReadUByte();
+ auto b2 = reader.ReadUByte();
+
+
+ reader.Seek(5, LUS::SeekOffsetType::Current);
+
+ // Direction
+ auto x = reader.ReadInt8();
+ auto y = reader.ReadInt8();
+ auto z = reader.ReadInt8();
+
+ // The struct has several copies/padding. The zeros skip those for gdSPDefLights1.
+ lights = {r, g, b, 0, 0, 0, 0, 0, r2, g2, b2, 0, 0, 0, 0, 0, x, y, z};
+
+ return std::make_shared<LightsData>(lights);
+} \ No newline at end of file
diff --git a/src/factories/LightsFactory.h b/src/factories/LightsFactory.h
new file mode 100644
index 0000000..9c3bcf1
--- /dev/null
+++ b/src/factories/LightsFactory.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "BaseFactory.h"
+
+struct Light_tRaw {
+ uint8_t col[3]; /* diffuse light value (rgba) */
+ int8_t pad1;
+ uint8_t colc[3]; /* copy of diffuse light value (rgba) */
+ int8_t pad2;
+ int8_t dir[3]; /* direction of light (normalized) */
+ int8_t pad3;
+};
+
+union LightRaw {
+ Light_tRaw l;
+ long long int force_structure_alignment[2];
+};
+
+struct Ambient_tRaw {
+ uint8_t col[3]; /* ambient light value (rgba) */
+ int8_t pad1;
+ uint8_t colc[3]; /* copy of ambient light value (rgba) */
+ int8_t pad2;
+};
+
+
+union AmbientRaw {
+ Ambient_tRaw l;
+ long long int force_structure_alignment[1];
+};
+
+struct Lights1Raw {
+ AmbientRaw a;
+ LightRaw l[1];
+};
+
+class LightsData : public IParsedData {
+public:
+ Lights1Raw mLights;
+
+ LightsData(Lights1Raw lights) : mLights(lights) {}
+};
+
+class LightsHeaderExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class LightsBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class LightsCodeExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class LightsFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Code, LightsCodeExporter)
+ REGISTER(Header, LightsHeaderExporter)
+ REGISTER(Binary, LightsBinaryExporter)
+ };
+ }
+}; \ No newline at end of file
diff --git a/src/factories/RawFactory.cpp b/src/factories/RawFactory.cpp
deleted file mode 100644
index f737a9f..0000000
--- a/src/factories/RawFactory.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "RawFactory.h"
-
-void RawFactory::WriteHeader(LUS::BinaryWriter* writer, LUS::ResourceType resType, int32_t version) {
- writer->Write((uint8_t)(LUS::Endianness::Native)); // 0x00
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
-
- writer->Write((uint32_t) resType); // 0x04
- writer->Write((uint32_t) version); // 0x08
- writer->Write((uint64_t) 0xDEADBEEFDEADBEEF); // id, 0x0C
- writer->Write((uint32_t) 0); // 0x10
- writer->Write((uint64_t) 0); // ROM CRC, 0x14
- writer->Write((uint32_t) 0); // ROM Enum, 0x1C
-
- while (writer->GetBaseAddress() < 0x40)
- writer->Write((uint32_t)0); // To be used at a later date!
-} \ No newline at end of file
diff --git a/src/factories/RawFactory.h b/src/factories/RawFactory.h
deleted file mode 100644
index 89f35df..0000000
--- a/src/factories/RawFactory.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-#include "ResourceType.h"
-#include "n64/Cartridge.h"
-#include <string>
-#include <vector>
-#include <filesystem>
-#include <binarytools/BinaryWriter.h>
-#include <yaml-cpp/yaml.h>
-
-
-#define SEGMENT_OFFSET(a) ((uint32_t)(a)&0x00FFFFFF)
-
-#define WRITE_HEADER(type, version) this->WriteHeader(writer, type, version)
-#define WRITE_BHEADER(type, version) this->WriteHeader(writer, type, version, true)
-#define WRITE_U8(value) writer->Write((uint8_t) value)
-#define WRITE_U16(value) writer->Write((uint16_t) value)
-#define WRITE_U32(value) writer->Write((uint32_t) value)
-#define WRITE_U64(value) writer->Write((uint64_t) value)
-#define WRITE_I8(value) writer->Write((int8_t) value)
-#define WRITE_I16(value) writer->Write((int16_t) value)
-#define WRITE_I32(value) writer->Write((int32_t) value)
-#define WRITE_DATA(vec) writer->Write((char*) vec.data(), data.size())
-#define WRITE_ARRAY(data, size) writer->Write((char*) data, size)
-
-class RawFactory {
-public:
- RawFactory() = default;
- virtual bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) = 0;
- void WriteHeader(LUS::BinaryWriter* write, LUS::ResourceType resType, int32_t version);
- inline void SetCartridge(N64::Cartridge* cart) {
- this->cartdrige = cart;
- }
- inline N64::Cartridge* GetCartridge() {
- return this->cartdrige;
- }
-private:
- N64::Cartridge* cartdrige;
-}; \ No newline at end of file
diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h
index fea9fc9..62a55ce 100644
--- a/src/factories/ResourceType.h
+++ b/src/factories/ResourceType.h
@@ -17,10 +17,15 @@ enum class ResourceType {
Bank = 0x42414E4B, // BANK
Sample = 0x41554643, // AIFC
Sequence = 0x53455143, // SEQC
+ Lights = 0x46669697, // LIGHTS
// SM64
Anim = 0x414E494D, // ANIM
SDialog = 0x53444C47, // SDLG
Dictionary = 0x44494354, // DICT
+ Geo = 0x47454F20, // GEO
+
+ // MK64
+ Waypoints = 0x46665666, // TrackWaypoints
};
} // namespace LUS
diff --git a/src/factories/SampleFactory.cpp b/src/factories/SampleFactory.cpp
index 7e2d1a1..9b7c48f 100644
--- a/src/factories/SampleFactory.cpp
+++ b/src/factories/SampleFactory.cpp
@@ -1,46 +1,36 @@
#include "SampleFactory.h"
-
-#include <vector>
-#include "audio/AudioManager.h"
-
-bool SampleFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- WRITE_HEADER(LUS::ResourceType::Sample, 0);
-
- auto id = data["id"].as<int32_t>();
- AudioBankSample entry = AudioManager::Instance->get_aifc(id);
-
- // Write AdpcmLoop
- WRITE_U32(entry.loop.start);
- WRITE_U32(entry.loop.end);
- WRITE_I32(entry.loop.count);
- WRITE_U32(entry.loop.pad);
-
- if(entry.loop.state.has_value()){
- std::vector<int16_t> state = entry.loop.state.value();
- WRITE_U32(state.size());
- for(auto &value : state){
- writer->Write(value);
- }
+#include "utils/MIODecoder.h"
+
+void SampleBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto sample = std::static_pointer_cast<SampleData>(raw)->mSample;
+
+ WriteHeader(writer, LUS::ResourceType::Sample, 0);
+ writer.Write((uint32_t) sample.loop.start);
+ writer.Write((uint32_t) sample.loop.end);
+ writer.Write((uint32_t) sample.loop.count);
+ writer.Write((uint32_t) sample.loop.pad);
+
+ if(sample.loop.state.has_value()){
+ auto state = sample.loop.state.value();
+ writer.Write((uint32_t) state.size());
+ writer.Write((char*) state.data(), state.size() * sizeof(int16_t));
} else {
- WRITE_U32(0);
+ writer.Write((uint32_t) 0);
}
- // Write AdpcmBook
- WRITE_I32(entry.book.order);
- WRITE_I32(entry.book.npredictors);
-
- WRITE_U32(entry.book.table.size());
- for(auto &value : entry.book.table){
- writer->Write(value);
- }
+ writer.Write((uint32_t) sample.book.order);
+ writer.Write((uint32_t) sample.book.npredictors);
- // Write sample
- WRITE_I32(entry.data.size());
- for(auto &value : entry.data){
- WRITE_U8(value);
- }
+ writer.Write((uint32_t) sample.book.table.size());
+ writer.Write((char*) sample.book.table.data(), sample.book.table.size() * sizeof(int16_t));
+ writer.Write(sample.name);
- writer->Write(entry.name);
+ writer.Finish(write);
+}
- return true;
+std::optional<std::shared_ptr<IParsedData>> SampleFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
+ auto id = data["id"].as<int32_t>();
+ AudioBankSample entry = AudioManager::Instance->get_aifc(id);
+ return std::make_shared<SampleData>(entry);
} \ No newline at end of file
diff --git a/src/factories/SampleFactory.h b/src/factories/SampleFactory.h
index c0ad4ef..2877a66 100644
--- a/src/factories/SampleFactory.h
+++ b/src/factories/SampleFactory.h
@@ -1,9 +1,25 @@
#pragma once
-#include "RawFactory.h"
+#include "BaseFactory.h"
+#include "audio/AudioManager.h"
-class SampleFactory : public RawFactory {
+class SampleData : public IParsedData {
public:
- SampleFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+ AudioBankSample mSample;
+
+ SampleData(AudioBankSample sample) : mSample(sample) {}
+};
+
+class SampleBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class SampleFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Binary, SampleBinaryExporter)
+ };
+ }
}; \ No newline at end of file
diff --git a/src/factories/SequenceFactory.cpp b/src/factories/SequenceFactory.cpp
index b9bccf9..46ed35e 100644
--- a/src/factories/SequenceFactory.cpp
+++ b/src/factories/SequenceFactory.cpp
@@ -1,25 +1,25 @@
#include "SequenceFactory.h"
+#include "utils/MIODecoder.h"
-#include "audio/AudioManager.h"
-#include <vector>
+void SequenceBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto sequence = std::static_pointer_cast<SequenceData>(raw);
-bool SequenceFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- WRITE_HEADER(LUS::ResourceType::Sequence, 0);
+ WriteHeader(writer, LUS::ResourceType::Sequence, 0);
+ writer.Write((uint32_t) sequence->mId);
+ writer.Write((uint32_t) sequence->mBanks.size());
+ for (auto& bank : sequence->mBanks) {
+ writer.Write(bank);
+ }
+ writer.Write((uint32_t) sequence->mSize);
+ writer.Write((char*) sequence->mBuffer.data(), sequence->mSize);
+ writer.Finish(write);
+}
+std::optional<std::shared_ptr<IParsedData>> SequenceFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
auto id = data["id"].as<uint32_t>();
auto size = data["size"].as<size_t>();
auto offset = data["offset"].as<size_t>();
-
auto banks = data["banks"].as<std::vector<std::string>>();
-
- WRITE_U32(id);
- WRITE_U32(banks.size());
- for(auto& bank : banks){
- writer->Write(bank);
- }
-
- WRITE_U32(size);
- WRITE_ARRAY(buffer.data() + offset, size);
-
- return true;
+ return std::make_shared<SequenceData>(id, size, buffer.data() + offset, banks);
} \ No newline at end of file
diff --git a/src/factories/SequenceFactory.h b/src/factories/SequenceFactory.h
index 93e9b3e..1f82d75 100644
--- a/src/factories/SequenceFactory.h
+++ b/src/factories/SequenceFactory.h
@@ -1,9 +1,29 @@
#pragma once
-#include "RawFactory.h"
+#include "BaseFactory.h"
-class SequenceFactory : public RawFactory {
+class SequenceData : public IParsedData {
public:
- SequenceFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+ uint32_t mId;
+ uint32_t mSize;
+ std::vector<uint8_t> mBuffer;
+ std::vector<std::string> mBanks;
+
+ SequenceData(uint32_t id, uint32_t size, uint8_t* data, std::vector<std::string>& banks) : mId(id), mSize(size), mBanks(banks) {
+ mBuffer = std::vector<uint8_t>(data, data + size);
+ }
+};
+
+class SequenceBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class SequenceFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Binary, SequenceBinaryExporter)
+ };
+ }
}; \ No newline at end of file
diff --git a/src/factories/TextureFactory.cpp b/src/factories/TextureFactory.cpp
index d929d7c..f49db17 100644
--- a/src/factories/TextureFactory.cpp
+++ b/src/factories/TextureFactory.cpp
@@ -1,13 +1,16 @@
#include "TextureFactory.h"
-
#include "utils/MIODecoder.h"
#include "spdlog/spdlog.h"
-
-namespace fs = std::filesystem;
+#include "Companion.h"
+#include <iomanip>
static const std::unordered_map <std::string, TextureType> gTextureTypes = {
{ "RGBA16", TextureType::RGBA16bpp },
{ "RGBA32", TextureType::RGBA32bpp },
+ { "CI4", TextureType::Palette4bpp },
+ { "CI8", TextureType::Palette8bpp },
+ { "I4", TextureType::Grayscale4bpp },
+ { "I8", TextureType::Grayscale8bpp },
{ "IA1", TextureType::GrayscaleAlpha1bpp },
{ "IA4", TextureType::GrayscaleAlpha4bpp },
{ "IA8", TextureType::GrayscaleAlpha8bpp },
@@ -18,7 +21,7 @@ uint8_t* alloc_ia8_text_from_i1(uint16_t *in, int16_t width, int16_t height) {
int32_t inPos;
uint16_t bitMask;
int16_t outPos = 0;
- uint8_t* out = new uint8_t[width * height];
+ auto out = new uint8_t[width * height];
for (inPos = 0; inPos < (width * height) / 16; inPos++) {
bitMask = 0x8000;
@@ -38,47 +41,113 @@ uint8_t* alloc_ia8_text_from_i1(uint16_t *in, int16_t width, int16_t height) {
return out;
}
-bool TextureFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+void TextureHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
+ auto symbol = node["symbol"] ? node["symbol"].as<std::string>() : entryName;
+ auto data = std::static_pointer_cast<TextureData>(raw)->mBuffer;
- auto format = data["format"].as<std::string>();
- auto width = data["width"].as<uint32_t>();
- auto height = data["height"].as<uint32_t>();
- auto size = data["size"].as<size_t>();
- auto offset = data["offset"].as<size_t>();
+ if(Companion::Instance->IsOTRMode()){
+ write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
+ return;
+ }
+
+ write << "extern u8 " << symbol << "[" << data.size() << "];\n";
+}
+
+void TextureCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
+ auto data = std::static_pointer_cast<TextureData>(raw)->mBuffer;
+ auto symbol = node["symbol"] ? node["symbol"].as<std::string>() : entryName;
+ auto format = node["format"].as<std::string>();
+
+ std::transform(format.begin(), format.end(), format.begin(), tolower);
+ (*replacement) += "." + format;
+
+ std::string dpath = Companion::Instance->GetOutputPath() + "/" + (*replacement);
+ if(!exists(fs::path(dpath).parent_path())){
+ create_directories(fs::path(dpath).parent_path());
+ }
+
+ std::ofstream file(dpath + ".inc.c", std::ios::binary);
+
+ for (int i = 0; i < data.size(); i++) {
+ if (i % 16 == 0 && i != 0) {
+ file << std::endl;
+ }
+
+ file << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << ", ";
+ }
+
+ file.close();
+
+ if (Companion::Instance->GetGBIMinorVersion() == GBIMinorVersion::Mk64) {
+ write << "u8 " << symbol << "[] = {\n";
+ } else {
+ write << "ALIGNED8 static const u8 " << symbol << "[] = {\n";
+ }
+ write << tab << "#include \"" << Companion::Instance->GetOutputPath() + "/" << (*replacement) << ".inc.c\"\n";
+ write << "};\n\n";
+}
+
+void TextureBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
+ auto writer = LUS::BinaryWriter();
+ auto texture = std::static_pointer_cast<TextureData>(raw);
+ auto data = texture->mBuffer;
+
+ WriteHeader(writer, LUS::ResourceType::Texture, 0);
+
+ writer.Write((uint32_t) texture->mType);
+ writer.Write(texture->mWidth);
+ writer.Write(texture->mHeight);
+
+ writer.Write((uint32_t) data.size());
+ writer.Write((char*) data.data(), data.size());
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto format = node["format"].as<std::string>();
+ auto width = node["width"].as<uint32_t>();
+ auto height = node["height"].as<uint32_t>();
+ auto size = node["size"].as<size_t>();
+ auto offset = node["offset"].as<size_t>();
+
+ if (format.empty()) {
+ SPDLOG_ERROR("Texture entry at {:X} in yaml missing format node\n\
+ Please add one of the following formats\n\
+ rgba16, rgba32, ia16, ia8, ia4, i8, i4, ci8, ci4, 1bpp", offset);
+ return std::nullopt;
+ }
if(!gTextureTypes.contains(format)) {
- return false;
+ return std::nullopt;
}
TextureType type = gTextureTypes.at(format);
- WRITE_HEADER(LUS::ResourceType::Texture, 0);
-
- WRITE_U32(type);
- WRITE_U32(width);
- WRITE_U32(height);
+ std::vector<uint8_t> result;
- if(data["mio0"]){
- auto mio0 = data["mio0"].as<size_t>();
- auto decoded = MIO0Decoder::Decode(buffer, offset);
- auto data = decoded.data() + mio0;
+ if(node["mio0"]){
+ auto mio0 = node["mio0"].as<size_t>();
+ auto decoded = MIO0Decoder::Decode(buffer, mio0);
+ auto data = decoded.data() + offset;
if(type == TextureType::GrayscaleAlpha1bpp){
- auto ia8 = alloc_ia8_text_from_i1((uint16_t*)data, 8, 16);
- WRITE_U32(8 * 16);
- WRITE_ARRAY(ia8, 8 * 16);
+ auto ia8 = alloc_ia8_text_from_i1((uint16_t*) data, 8, 16);
+ result = std::vector(ia8, ia8 + 8 * 16);
delete[] ia8;
- } else {
- WRITE_U32(size);
- WRITE_ARRAY(data, size);
}
- } else {
- WRITE_U32(size);
- WRITE_ARRAY(buffer.data() + offset, size);
- }
+
+ result = std::vector(data, data + size);
+ } else {
+ result = std::vector(buffer.data() + offset, buffer.data() + offset + size);
+ }
SPDLOG_INFO("Texture: {} {}x{} {}", format, width, height, size);
SPDLOG_INFO("Offset: {}", offset);
- SPDLOG_INFO("Has MIO0: {}", data["mio0"] ? "true" : "false");
+ SPDLOG_INFO("Has MIO0: {}", node["mio0"] ? "true" : "false");
+ SPDLOG_INFO("Size: {}", result.size());
+
+ if(result.size() == 0){
+ return std::nullopt;
+ }
- return true;
+ return std::make_shared<TextureData>(type, width, height, result);
}
diff --git a/src/factories/TextureFactory.h b/src/factories/TextureFactory.h
index e153e07..5f5fcc8 100644
--- a/src/factories/TextureFactory.h
+++ b/src/factories/TextureFactory.h
@@ -1,6 +1,6 @@
#pragma once
-#include "RawFactory.h"
+#include "BaseFactory.h"
enum class TextureType {
Error,
@@ -16,8 +16,36 @@ enum class TextureType {
GrayscaleAlpha16bpp,
};
-class TextureFactory : public RawFactory {
+class TextureData : public IParsedData {
public:
- TextureFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+ TextureType mType;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ std::vector<uint8_t> mBuffer;
+
+ TextureData(TextureType type, uint32_t width, uint32_t height, std::vector<uint8_t>& buffer) : mType(type), mWidth(width), mHeight(height), mBuffer(std::move(buffer)) {}
+};
+
+class TextureHeaderExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class TextureCodeExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class TextureBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class TextureFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Header, TextureHeaderExporter)
+ REGISTER(Binary, TextureBinaryExporter)
+ REGISTER(Code, TextureCodeExporter)
+ };
+ }
}; \ No newline at end of file
diff --git a/src/factories/VtxFactory.cpp b/src/factories/VtxFactory.cpp
new file mode 100644
index 0000000..8196571
--- /dev/null
+++ b/src/factories/VtxFactory.cpp
@@ -0,0 +1,114 @@
+#include "VtxFactory.h"
+
+#include "Companion.h"
+#include "utils/MIODecoder.h"
+
+#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x
+#define COL(c) "0x" << std::hex << std::setw(2) << std::setfill('0') << c
+
+void VtxHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
+ const auto symbol = node["symbol"] ? node["symbol"].as<std::string>() : entryName;
+
+ if(Companion::Instance->IsOTRMode()){
+ write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
+ return;
+ }
+
+ write << "extern Vtx " << symbol << "[];\n";
+}
+
+void VtxCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto vtx = std::static_pointer_cast<VtxData>(raw)->mVtxs;
+ const auto symbol = node["symbol"].as<std::string>();
+ const auto offset = node["offset"].as<uint32_t>();
+
+ if (Companion::Instance->IsDebug()) {
+ write << "// 0x" << std::hex << std::uppercase << offset << "\n";
+ }
+
+ write << "Vtx " << symbol << "[] = {\n";
+
+ for (int i = 0; i < vtx.size(); ++i) {
+ auto v = vtx[i];
+
+ auto x = v.ob[0];
+ auto y = v.ob[1];
+ auto z = v.ob[2];
+
+ auto flag = v.flag;
+
+ auto tc1 = v.tc[0];
+ auto tc2 = v.tc[1];
+
+ auto c1 = (uint16_t) v.cn[0];
+ auto c2 = (uint16_t) v.cn[1];
+ auto c3 = (uint16_t) v.cn[2];
+ auto c4 = (uint16_t) v.cn[3];
+
+ if(i <= vtx.size() - 1) {
+ write << fourSpaceTab;
+ }
+
+ // {{{ x, y, z }, f, { tc1, tc2 }, { c1, c2, c3, c4 }}}
+ write << "{{{" << NUM(x) << ", " << NUM(y) << ", " << NUM(z) << "}, " << flag << ", {" << NUM(tc1) << ", " << NUM(tc2) << "}, {" << COL(c1) << ", " << COL(c2) << ", " << COL(c3) << ", " << COL(c4) << "}}},\n";
+ }
+
+ if (Companion::Instance->IsDebug()) {
+ write << fourSpaceTab << "// 0x" << std::hex << std::uppercase << (offset + (16 * vtx.size())) << "\n";
+ }
+
+ write << "};\n\n";
+}
+
+void VtxBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto vtx = std::static_pointer_cast<VtxData>(raw);
+ auto writer = LUS::BinaryWriter();
+
+ WriteHeader(writer, LUS::ResourceType::Vertex, 0);
+ writer.Write((uint32_t) vtx->mVtxs.size());
+ for(auto v : vtx->mVtxs) {
+ writer.Write(v.ob[0]);
+ writer.Write(v.ob[1]);
+ writer.Write(v.ob[2]);
+ writer.Write(v.flag);
+ writer.Write(v.tc[0]);
+ writer.Write(v.tc[1]);
+ writer.Write(v.cn[0]);
+ writer.Write(v.cn[1]);
+ writer.Write(v.cn[2]);
+ writer.Write(v.cn[3]);
+ }
+
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> VtxFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto mio0 = node["mio0"].as<size_t>();
+ auto offset = node["offset"].as<uint32_t>();
+ auto count = node["count"].as<size_t>();
+
+ auto decoded = MIO0Decoder::Decode(buffer, mio0);
+ LUS::BinaryReader reader(decoded.data() + offset, count * sizeof(VtxRaw) );
+
+ reader.SetEndianness(LUS::Endianness::Big);
+ std::vector<VtxRaw> vertices;
+
+ for(size_t i = 0; i < count; i++) {
+ auto x = reader.ReadInt16();
+ auto y = reader.ReadInt16();
+ auto z = reader.ReadInt16();
+ auto flag = reader.ReadUInt16();
+ auto tc1 = reader.ReadInt16();
+ auto tc2 = reader.ReadInt16();
+ auto cn1 = reader.ReadUByte();
+ auto cn2 = reader.ReadUByte();
+ auto cn3 = reader.ReadUByte();
+ auto cn4 = reader.ReadUByte();
+
+ vertices.push_back(VtxRaw({
+ {x, y, z}, flag, {tc1, tc2}, {cn1, cn2, cn3, cn4}
+ }));
+ }
+
+ return std::make_shared<VtxData>(vertices);
+} \ No newline at end of file
diff --git a/src/factories/VtxFactory.h b/src/factories/VtxFactory.h
new file mode 100644
index 0000000..22ec7dd
--- /dev/null
+++ b/src/factories/VtxFactory.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "BaseFactory.h"
+
+struct VtxRaw {
+ int16_t ob[3]; /* x, y, z */
+ uint16_t flag;
+ int16_t tc[2]; /* texture coord */
+ uint8_t cn[4]; /* color & alpha */
+};
+
+class VtxData : public IParsedData {
+public:
+ std::vector<VtxRaw> mVtxs;
+
+ explicit VtxData(std::vector<VtxRaw> vtxs) : mVtxs(vtxs) {}
+};
+
+class VtxHeaderExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class VtxBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class VtxCodeExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class VtxFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Code, VtxCodeExporter)
+ REGISTER(Header, VtxHeaderExporter)
+ REGISTER(Binary, VtxBinaryExporter)
+ };
+ }
+}; \ No newline at end of file
diff --git a/src/factories/debug/MIO0Factory.cpp b/src/factories/debug/MIO0Factory.cpp
deleted file mode 100644
index e5858ed..0000000
--- a/src/factories/debug/MIO0Factory.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "MIO0Factory.h"
-#include <cstring>
-#include "utils/MIODecoder.h"
-
-namespace fs = std::filesystem;
-
-bool MIO0Factory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
-
-// WRITE_HEADER(LUS::ResourceType::Blob, 0);
-
- auto offset = data["offset"].as<size_t>();
-
- auto decoded = MIO0Decoder::Decode(buffer, offset);
- auto size = decoded.size();
- auto* blob = new uint8_t[size];
- memcpy(blob, decoded.data(), size);
-
-// WRITE_U32(size); // MIO0 Data Size
- WRITE_ARRAY(blob, size); // MIO0 Data
-
- delete[] blob;
- return true;
-}
diff --git a/src/factories/mk64/WaypointFactory.cpp b/src/factories/mk64/WaypointFactory.cpp
new file mode 100644
index 0000000..9ec96bc
--- /dev/null
+++ b/src/factories/mk64/WaypointFactory.cpp
@@ -0,0 +1,83 @@
+#include "WaypointFactory.h"
+
+#include "Companion.h"
+#include "utils/MIODecoder.h"
+
+#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x
+#define COL(c) "0x" << std::hex << std::setw(2) << std::setfill('0') << c
+
+void MK64::WaypointHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
+ const auto symbol = node["symbol"] ? node["symbol"].as<std::string>() : entryName;
+
+ if(Companion::Instance->IsOTRMode()){
+ write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
+ return;
+ }
+
+ write << "extern TrackWaypoint " << symbol << "[];\n";
+}
+
+void MK64::WaypointCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto waypoints = std::static_pointer_cast<WaypointData>(raw)->mWaypoints;
+ auto symbol = node["symbol"].as<std::string>();
+
+ write << "TrackWaypoint " << symbol << "[] = {\n";
+
+ for (int i = 0; i < waypoints.size(); ++i) {
+ auto x = waypoints[i].posX;
+ auto y = waypoints[i].posY;
+ auto z = waypoints[i].posZ;
+
+ // Track segment
+ auto seg = waypoints[i].trackSegment;
+
+ if(i <= waypoints.size() - 1) {
+ write << fourSpaceTab;
+ }
+
+ // {{{ x, y, z }, f, { tc1, tc2 }, { c1, c2, c3, c4 }}}
+ write << "{" << NUM(x) << ", " << NUM(y) << ", " << NUM(z) << ", " << NUM(seg) << " },\n";
+ }
+ write << "};\n\n";
+}
+
+void MK64::WaypointBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto waypoints = std::static_pointer_cast<WaypointData>(raw)->mWaypoints;
+ auto writer = LUS::BinaryWriter();
+
+ WriteHeader(writer, LUS::ResourceType::Waypoints, 0);
+ writer.Write((uint32_t) waypoints.size());
+ for(auto w : waypoints) {
+ writer.Write(w.posX);
+ writer.Write(w.posY);
+ writer.Write(w.posZ);
+ writer.Write(w.trackSegment);
+ }
+
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> MK64::WaypointFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto mio0 = node["mio0"].as<size_t>();
+ auto offset = node["offset"].as<uint32_t>();
+ auto count = node["count"].as<size_t>();
+
+ auto decoded = MIO0Decoder::Decode(buffer, mio0);
+ LUS::BinaryReader reader(decoded.data() + offset, count * sizeof(MK64::TrackWaypoint) );
+
+ reader.SetEndianness(LUS::Endianness::Big);
+ std::vector<MK64::TrackWaypoint> waypoints;
+
+ for(size_t i = 0; i < count; i++) {
+ auto x = reader.ReadInt16();
+ auto y = reader.ReadInt16();
+ auto z = reader.ReadInt16();
+ auto trackSegment = reader.ReadUInt16();
+
+ waypoints.push_back(MK64::TrackWaypoint({
+ x, y, z, trackSegment
+ }));
+ }
+
+ return std::make_shared<WaypointData>(waypoints);
+} \ No newline at end of file
diff --git a/src/factories/mk64/WaypointFactory.h b/src/factories/mk64/WaypointFactory.h
new file mode 100644
index 0000000..1268e6c
--- /dev/null
+++ b/src/factories/mk64/WaypointFactory.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "../BaseFactory.h"
+
+namespace MK64 {
+
+ struct TrackWaypoint {
+ int16_t posX;
+ int16_t posY;
+ int16_t posZ;
+ uint16_t trackSegment;
+ };
+
+ class WaypointData : public IParsedData {
+ public:
+ std::vector<TrackWaypoint> mWaypoints;
+
+ explicit WaypointData(std::vector<TrackWaypoint> waypoints) : mWaypoints(waypoints) {}
+ };
+
+ class WaypointHeaderExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class WaypointBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class WaypointCodeExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class WaypointFactory : public BaseFactory {
+ public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Code, WaypointCodeExporter)
+ REGISTER(Header, WaypointHeaderExporter)
+ REGISTER(Binary, WaypointBinaryExporter)
+ };
+ }
+ };
+} \ No newline at end of file
diff --git a/src/factories/sm64/AnimationFactory.cpp b/src/factories/sm64/AnimationFactory.cpp
new file mode 100644
index 0000000..6afb405
--- /dev/null
+++ b/src/factories/sm64/AnimationFactory.cpp
@@ -0,0 +1,74 @@
+#include "AnimationFactory.h"
+#include "utils/MIODecoder.h"
+#include "spdlog/spdlog.h"
+
+void SM64::AnimationBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto anim = std::static_pointer_cast<AnimationData>(raw);
+
+ WriteHeader(writer, LUS::ResourceType::Anim, 0);
+ writer.Write((int16_t) anim->mFlags);
+ writer.Write((int16_t) anim->mAnimYTransDivisor);
+ writer.Write((int16_t) anim->mStartFrame);
+ writer.Write((int16_t) anim->mLoopStart);
+ writer.Write((int16_t) anim->mLoopEnd);
+ writer.Write((int16_t) anim->mUnusedBoneCount);
+ writer.Write((uint64_t) anim->mLength);
+
+ writer.Write((uint32_t) anim->mIndices.size());
+ for (auto& index : anim->mIndices) {
+ writer.Write((int16_t) index);
+ }
+
+ writer.Write((uint32_t) anim->mEntries.size());
+ for (auto& entry : anim->mEntries) {
+ writer.Write((uint16_t) entry);
+ }
+
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> SM64::AnimationFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto headerNode = node["header"];
+ auto valuesNode = node["values"];
+ auto indexNode = node["indices"];
+
+ LUS::BinaryReader header((char*) buffer.data() + headerNode["offset"].as<uint32_t>(), headerNode["size"].as<uint32_t>());
+ header.SetEndianness(LUS::Endianness::Big);
+
+ auto flags = header.ReadInt16();
+ auto animYTransDivisor = header.ReadInt16();
+ auto startFrame = header.ReadInt16();
+ auto loopStart = header.ReadInt16();
+ auto loopEnd = header.ReadInt16();
+ auto unusedBoneCount = header.ReadInt16();
+ header.ReadUInt32();
+ header.ReadUInt32();
+ auto length = header.ReadUInt32();
+
+ LUS::BinaryReader indices((char*) buffer.data() + indexNode["offset"].as<uint32_t>(), indexNode["size"].as<uint32_t>());
+ indices.SetEndianness(LUS::Endianness::Big);
+ size_t indexLength = indexNode["size"].as<uint32_t>() / sizeof(uint16_t);
+ std::vector<uint16_t> indicesData;
+ for (size_t i = 0; i < indexLength; i++) {
+ indicesData.push_back(indices.ReadInt16());
+ }
+
+ LUS::BinaryReader values((char*) buffer.data() + valuesNode["offset"].as<uint32_t>(), valuesNode["size"].as<uint32_t>());
+ values.SetEndianness(LUS::Endianness::Big);
+ size_t entries = valuesNode["size"].as<uint32_t>() / sizeof(uint16_t);
+ std::vector<uint16_t> valuesData;
+ for (size_t i = 0; i < entries; i++) {
+ valuesData.push_back(values.ReadUInt16());
+ }
+
+ SPDLOG_INFO("Flags: {}", flags);
+ SPDLOG_INFO("Anim-Y Trans Divisor: {}", animYTransDivisor);
+ SPDLOG_INFO("Start Frame: {}", startFrame);
+ SPDLOG_INFO("Loop Start: {}", loopStart);
+ SPDLOG_INFO("Loop End: {}", loopEnd);
+ SPDLOG_INFO("Unused Bone Count: {}", unusedBoneCount);
+ SPDLOG_INFO("Length: {}", length);
+
+ return std::make_shared<AnimationData>(flags, animYTransDivisor, startFrame, loopStart, loopEnd, unusedBoneCount, length, valuesData, indicesData);
+} \ No newline at end of file
diff --git a/src/factories/sm64/AnimationFactory.h b/src/factories/sm64/AnimationFactory.h
new file mode 100644
index 0000000..2d0ea45
--- /dev/null
+++ b/src/factories/sm64/AnimationFactory.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "../BaseFactory.h"
+
+namespace SM64 {
+class AnimationData : public IParsedData {
+public:
+ int16_t mFlags;
+ int16_t mAnimYTransDivisor;
+ int16_t mStartFrame;
+ int16_t mLoopStart;
+ int16_t mLoopEnd;
+ int16_t mUnusedBoneCount;
+ int16_t mLength;
+ std::vector<uint16_t> mIndices;
+ std::vector<uint16_t> mEntries;
+
+ AnimationData(int16_t flags, int16_t animYTransDivisor, int16_t startFrame, int16_t loopStart, int16_t loopEnd, int16_t unusedBoneCount, int16_t length, std::vector<uint16_t>& indices, std::vector<uint16_t>& entries) : mFlags(flags), mAnimYTransDivisor(animYTransDivisor), mStartFrame(startFrame), mLoopStart(loopStart), mLoopEnd(loopEnd), mUnusedBoneCount(unusedBoneCount), mLength(length), mIndices(indices), mEntries(entries) {}
+};
+
+class AnimationBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class AnimationFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return { REGISTER(Binary, AnimationBinaryExporter) };
+ }
+};
+} \ No newline at end of file
diff --git a/src/factories/sm64/DialogFactory.cpp b/src/factories/sm64/DialogFactory.cpp
new file mode 100644
index 0000000..897b956
--- /dev/null
+++ b/src/factories/sm64/DialogFactory.cpp
@@ -0,0 +1,54 @@
+#include "DialogFactory.h"
+#include "utils/MIODecoder.h"
+#include "spdlog/spdlog.h"
+
+void SM64::DialogBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto dialog = std::static_pointer_cast<DialogData>(raw);
+
+ WriteHeader(writer, LUS::ResourceType::SDialog, 0);
+ writer.Write((uint32_t) dialog->mUnused);
+ writer.Write((int8_t) dialog->mLinesPerBox);
+ writer.Write((int16_t) dialog->mLeftOffset);
+ writer.Write((int16_t) dialog->mWidth);
+
+ writer.Write((uint32_t) dialog->mText.size());
+ writer.Write((char*) dialog->mText.data(), dialog->mText.size());
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> SM64::DialogFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto offset = node["offset"].as<int32_t>();
+ auto mio0 = node["mio0"].as<size_t>();
+
+ auto decoded = MIO0Decoder::Decode(buffer, mio0);
+ auto bytes = (uint8_t*) decoded.data();
+ LUS::BinaryReader reader(bytes, decoded.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+ reader.Seek(offset, LUS::SeekOffsetType::Start);
+
+ auto unused = reader.ReadUInt32();
+ auto linesPerBox = reader.ReadUByte();
+ // Padding
+ reader.Read(1);
+ auto leftOffset = reader.ReadInt16();
+ auto width = reader.ReadInt16();
+ // Padding
+ reader.Read(2);
+ auto str = SEGMENT_OFFSET(reader.ReadInt32());
+ std::vector<uint8_t> text;
+
+ while(bytes[str] != 0xFF){
+ auto c = bytes[str++];
+ text.push_back(c);
+ }
+ text.push_back(0xFF);
+
+ SPDLOG_INFO("Unused: {}", unused);
+ SPDLOG_INFO("Lines per box: {}", linesPerBox);
+ SPDLOG_INFO("Left offset: {}", leftOffset);
+ SPDLOG_INFO("Width: {}", width);
+ SPDLOG_INFO("Size: {}", text.size());
+
+ return std::make_shared<DialogData>(unused, linesPerBox, leftOffset, width, text);
+} \ No newline at end of file
diff --git a/src/factories/sm64/DialogFactory.h b/src/factories/sm64/DialogFactory.h
new file mode 100644
index 0000000..75160af
--- /dev/null
+++ b/src/factories/sm64/DialogFactory.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "../BaseFactory.h"
+
+namespace SM64 {
+class DialogData : public IParsedData {
+public:
+ uint32_t mUnused;
+ uint8_t mLinesPerBox;
+ uint16_t mLeftOffset;
+ uint16_t mWidth;
+ std::vector<uint8_t> mText;
+
+ DialogData(uint32_t unused, uint8_t linesPerBox, uint16_t leftOffset, uint16_t width, std::vector<uint8_t>& text) : mUnused(unused), mLinesPerBox(linesPerBox), mLeftOffset(leftOffset), mWidth(width), mText(text) {}
+};
+
+class DialogBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class DialogFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return { REGISTER(Binary, DialogBinaryExporter) };
+ }
+};
+} \ No newline at end of file
diff --git a/src/factories/sm64/DictionaryFactory.cpp b/src/factories/sm64/DictionaryFactory.cpp
new file mode 100644
index 0000000..39d6055
--- /dev/null
+++ b/src/factories/sm64/DictionaryFactory.cpp
@@ -0,0 +1,39 @@
+#include "DictionaryFactory.h"
+#include "utils/MIODecoder.h"
+
+void SM64::DictionaryBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto data = std::static_pointer_cast<DictionaryData>(raw);
+
+ WriteHeader(writer, LUS::ResourceType::Dictionary, 0);
+
+ writer.Write((uint32_t) data->mDictionary.size());
+ for(auto& [key, value] : data->mDictionary){
+ writer.Write(key);
+ writer.Write((uint32_t) value.size());
+ writer.Write((char*) value.data(), value.size());
+ }
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> SM64::DictionaryFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
+ std::unordered_map<std::string, std::vector<uint8_t>> dictionary;
+
+ for (auto it = data["keys"].begin(); it != data["keys"].end(); ++it) {
+ auto key = it->first.as<std::string>();
+ auto offset = it->second.as<size_t>();
+
+ std::vector<uint8_t> text;
+ auto bytes = (uint8_t*) buffer.data();
+
+ while(bytes[offset] != 0xFF){
+ auto c = bytes[offset++];
+ text.push_back(c);
+ }
+
+ text.push_back(0xFF);
+ dictionary[key] = text;
+ }
+
+ return std::make_shared<DictionaryData>(dictionary);
+} \ No newline at end of file
diff --git a/src/factories/sm64/DictionaryFactory.h b/src/factories/sm64/DictionaryFactory.h
new file mode 100644
index 0000000..acb7429
--- /dev/null
+++ b/src/factories/sm64/DictionaryFactory.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../BaseFactory.h"
+
+namespace SM64 {
+
+class DictionaryData : public IParsedData {
+public:
+ std::unordered_map<std::string, std::vector<uint8_t>> mDictionary;
+
+ DictionaryData(std::unordered_map<std::string, std::vector<uint8_t>> dictionary) : mDictionary(dictionary) {}
+};
+
+class DictionaryBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class DictionaryFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return { REGISTER(Binary, DictionaryBinaryExporter) };
+ }
+};
+} \ No newline at end of file
diff --git a/src/factories/sm64/GeoCommands.h b/src/factories/sm64/GeoCommands.h
new file mode 100644
index 0000000..e10e2a0
--- /dev/null
+++ b/src/factories/sm64/GeoCommands.h
@@ -0,0 +1,436 @@
+#pragma once
+
+#include "n64/CommandMacros.h"
+
+typedef float Vec2f[2];
+typedef float Vec3f[3]; // X, Y, Z, where Y is up
+typedef int16_t Vec3s[3];
+typedef int32_t Vec3i[3];
+typedef float Vec4f[4];
+typedef int16_t Vec4s[4];
+
+#define cur_geo_cmd_u8(offset) \
+ (cmd[CMD_PROCESS_OFFSET(offset)])
+
+#define cur_geo_cmd_s16(offset) \
+ BSWAP16((*(int16_t *) &cmd[CMD_PROCESS_OFFSET(offset)]))
+
+#define cur_geo_cmd_i32(offset) \
+ (*(int32_t *) &cmd[CMD_PROCESS_OFFSET(offset)])
+
+#define cur_geo_cmd_u32(offset) \
+ BSWAP32((*(uint32_t *) &cmd[CMD_PROCESS_OFFSET(offset)]))
+
+#define CMD_NOP(c) GeoCommand::c: writer->Write((uint32_t) GeoCommand::c); cmd += 0x04 << CMD_SIZE_SHIFT; print_cmd(c, #c); break;
+//#define CMD_NOP(c) GeoCommand::c: cmd += 0x04 << CMD_SIZE_SHIFT; print_cmd(c, #c); break;
+#define CMD_INFO(c) GeoCommand::c: print_cmd(c, #c);
+#define next_s16_in_geo_script(src) ((uint32_t)(*(*src)++))
+
+#define cur_geo_cmd_s32(offset) \
+ (*(s32 *) &cmd[CMD_PROCESS_OFFSET(offset)])
+
+/**
+ * 0x00: Branch and store return address
+ * 0x04: scriptTarget, segment address of geo layout
+ */
+#define GEO_BRANCH_AND_LINK(scriptTarget) \
+ CMD_BBH(0x00, 0x00, 0x0000), \
+ CMD_PTR(scriptTarget)
+
+/**
+ * 0x01: Terminate geo layout
+ * 0x01-0x03: unused
+ */
+#define GEO_END() \
+ CMD_BBH(0x01, 0x00, 0x0000)
+
+/**
+ * 0x02: Branch
+ * 0x01: if 1, store next geo layout address on stack
+ * 0x02-0x03: unused
+ * 0x04: scriptTarget, segment address of geo layout
+ */
+#define GEO_BRANCH(type, scriptTarget) \
+ CMD_BBH(0x02, type, 0x0000), \
+ CMD_PTR(scriptTarget)
+
+/**
+ * 0x03: Return from branch
+ * 0x01-0x03: unused
+ */
+#define GEO_RETURN() \
+ CMD_BBH(0x03, 0x00, 0x0000)
+
+/**
+ * 0x04: Open node
+ * 0x01-0x03: unused
+ */
+#define GEO_OPEN_NODE() \
+ CMD_BBH(0x04, 0x00, 0x0000)
+
+/**
+ * 0x05: Close node
+ * 0x01-0x03: unused
+ */
+#define GEO_CLOSE_NODE() \
+ CMD_BBH(0x05, 0x00, 0x0000)
+
+/**
+ * 0x06: Register the current node at the given index in the gGeoViews array
+ * 0x01: unused
+ * 0x02: s16 index
+ */
+#define GEO_ASSIGN_AS_VIEW(index) \
+ CMD_BBH(0x06, 0x00, index)
+
+/**
+ * 0x07: Update current scene graph node flags
+ * 0x01: u8 operation (0 = reset, 1 = set, 2 = clear)
+ * 0x02: s16 bits
+ */
+#define GEO_UPDATE_NODE_FLAGS(operation, flagBits) \
+ CMD_BBH(0x07, operation, flagBits)
+
+/**
+ * 0x08: Create screen area scene graph node
+ * 0x01: unused
+ * 0x02: s16 num entries (+2) to allocate
+ * 0x04: s16 x
+ * 0x06: s16 y
+ * 0x08: s16 width
+ * 0x0A: s16 height
+ */
+#define GEO_NODE_SCREEN_AREA(numEntries, x, y, width, height) \
+ CMD_BBH(0x08, 0x00, numEntries), \
+ CMD_HH(x, y), \
+ CMD_HH(width, height)
+
+/**
+ * 0x09: Create orthographic projection scene graph node
+ * 0x02: s16 scale as percentage
+ */
+#define GEO_NODE_ORTHO(scale) \
+ CMD_BBH(0x09, 0x00, scale)
+
+/**
+ * 0x0A: Create camera frustum scene graph node
+ * 0x01: u8 if nonzero, enable function field
+ * 0x02: s16 field of view
+ * 0x04: s16 near
+ * 0x06: s16 far
+ * 0x08: [GraphNodeFunc function]
+*/
+#define GEO_CAMERA_FRUSTUM(fov, near, far) \
+ CMD_BBH(0x0A, 0x00, fov), \
+ CMD_HH(near, far)
+
+#define GEO_CAMERA_FRUSTUM_WITH_FUNC(fov, near, far, func) \
+ CMD_BBH(0x0A, 0x01, fov), \
+ CMD_HH(near, far), \
+ CMD_PTR(func)
+
+/**
+ * 0x0B: Create a root scene graph node
+ * 0x01-0x03: unused
+ */
+#define GEO_NODE_START() \
+ CMD_BBH(0x0B, 0x00, 0x0000)
+
+/**
+ * 0x0C: Create zbuffer-toggling scene graph node
+ * 0x01: u8 enableZBuffer (1 = on, 0 = off)
+ * 0x02-0x03: unused
+ */
+#define GEO_ZBUFFER(enable) \
+ CMD_BBH(0x0C, enable, 0x0000)
+
+/**
+ * 0x0D: Create render range scene graph node
+ * 0x01-0x03: unused
+ * 0x04: s16 minDistance
+ * 0x06: s16 maxDistance
+ */
+#define GEO_RENDER_RANGE(minDistance, maxDistance) \
+ CMD_BBH(0x0D, 0x00, 0x0000), \
+ CMD_HH(minDistance, maxDistance)
+
+/**
+ * 0x0E: Create switch-case scene graph node
+ * 0x01: unused
+ * 0x02: s16 numCases
+ * 0x04: GraphNodeFunc caseSelectorFunc
+ */
+#define GEO_SWITCH_CASE(count, function) \
+ CMD_BBH(0x0E, 0x00, count), \
+ CMD_PTR(function)
+
+/**
+ * 0x0F: Create a camera scene graph node.
+ * 0x01: unused
+ * 0x02: s16 camera type
+ * 0x04: s16 posX
+ * 0x06: s16 posY
+ * 0x08: s16 posZ
+ * 0x0A: s16 focusX
+ * 0x0C: s16 focusY
+ * 0x0E: s16 focusZ
+ * 0x10: GraphNodeFunc function
+ */
+#define GEO_CAMERA(type, x1, y1, z1, x2, y2, z2, function) \
+ CMD_BBH(0x0F, 0x00, type), \
+ CMD_HHHHHH(x1, y1, z1, x2, y2, z2), \
+ CMD_PTR(function)
+
+/**
+ * 0x10: Create translation & rotation scene graph node with optional display list
+ * Four different versions of 0x10
+ * cmd+0x01: u8 params
+ * 0b1000_0000: if set, enable displayList field and drawingLayer
+ * 0b0111_0000: fieldLayout (determines how rest of data is formatted
+ * 0b0000_1111: drawingLayer
+ *
+ * fieldLayout = 0: Translate & Rotate
+ * 0x04: s16 xTranslation
+ * 0x06: s16 yTranslation
+ * 0x08: s16 zTranslation
+ * 0x0A: s16 xRotation
+ * 0x0C: s16 yRotation
+ * 0x0E: s16 zRotation
+ * 0x10: [u32 displayList: if MSbit of params set, display list segmented address]
+ */
+#define GEO_TRANSLATE_ROTATE(layer, tx, ty, tz, rx, ry, rz) \
+ CMD_BBH(0x10, (0x00 | layer), 0x0000), \
+ CMD_HHHHHH(tx, ty, tz, rx, ry, rz)
+#define GEO_TRANSLATE_ROTATE_WITH_DL(layer, tx, ty, tz, rx, ry, rz, displayList) \
+ CMD_BBH(0x10, (0x00 | layer | 0x80), 0x0000), \
+ CMD_HHHHHH(tx, ty, tz, rx, ry, rz), \
+ CMD_PTR(displayList)
+
+/**
+ * fieldLayout = 1: Translate
+ * 0x02: s16 xTranslation
+ * 0x04: s16 yTranslation
+ * 0x06: s16 zTranslation
+ * 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
+ */
+#define GEO_TRANSLATE(layer, tx, ty, tz) \
+ CMD_BBH(0x10, (0x10 | layer), tx), \
+ CMD_HH(ty, tz)
+#define GEO_TRANSLATE_WITH_DL(layer, tx, ty, tz, displayList) \
+ CMD_BBH(0x10, (0x10 | layer | 0x80), tx), \
+ CMD_HH(ty, tz), \
+ CMD_PTR(displayList)
+
+/**
+ * fieldLayout = 2: Rotate
+ * 0x02: s16 xRotation
+ * 0x04: s16 yRotation
+ * 0x06: s16 zRotation
+ * 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
+ */
+#define GEO_ROTATE(layer, rx, ry, rz) \
+ CMD_BBH(0x10, (0x20 | layer), rx), \
+ CMD_HH(ry, rz)
+#define GEO_ROTATE_WITH_DL(layer, rx, ry, rz, displayList) \
+ CMD_BBH(0x10, (0x20 | layer | 0x80), rx), \
+ CMD_HH(ry, rz), \
+ CMD_PTR(displayList)
+
+/**
+ * fieldLayout = 3: Rotate Y
+ * 0x02: s16 yRotation
+ * 0x04: [u32 displayList: if MSbit of params set, display list segmented address]
+ */
+#define GEO_ROTATE_Y(layer, ry) \
+ CMD_BBH(0x10, (0x30 | layer), ry)
+#define GEO_ROTATE_Y_WITH_DL(layer, ry, displayList) \
+ CMD_BBH(0x10, (0x30 | layer | 0x80), ry), \
+ CMD_PTR(displayList)
+
+/**
+ * 0x11: Create translation scene graph node with optional display list
+ * 0x01: u8 params
+ * 0b1000_0000: if set, enable displayList field and drawingLayer
+ * 0b0000_1111: drawingLayer
+ * 0x02: s16 translationX
+ * 0x04: s16 translationY
+ * 0x06: s16 translationZ
+ * 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
+ */
+#define GEO_TRANSLATE_NODE(layer, ux, uy, uz) \
+ CMD_BBH(0x11, layer, ux), \
+ CMD_HH(uy, uz)
+#define GEO_TRANSLATE_NODE_WITH_DL(layer, ux, uy, uz, displayList) \
+ CMD_BBH(0x11, (layer | 0x80), ux), \
+ CMD_HH(uy, uz), \
+ CMD_PTR(displayList)
+
+/**
+ * 0x12: Create rotation scene graph node with optional display list
+ * 0x01: u8 params
+ * 0b1000_0000: if set, enable displayList field and drawingLayer
+ * 0b0000_1111: drawingLayer
+ * 0x02: s16 rotationX
+ * 0x04: s16 rotationY
+ * 0x06: s16 rotationZ
+ * 0x08: [u32 displayList: if MSbit of params set, display list segmented address]
+ */
+#define GEO_ROTATION_NODE(layer, ux, uy, uz) \
+ CMD_BBH(0x12, layer, ux), \
+ CMD_HH(uy, uz)
+#define GEO_ROTATION_NODE_WITH_DL(layer, ux, uy, uz, displayList) \
+ CMD_BBH(0x12, (layer | 0x80), ux), \
+ CMD_HH(uy, uz), \
+ CMD_PTR(displayList)
+
+/**
+ * 0x13: Create a scene graph node that is rotated by the object's animation.
+ * 0x01: u8 drawingLayer
+ * 0x02: s16 xTranslation
+ * 0x04: s16 yTranslation
+ * 0x06: s16 zTranslation
+ * 0x08: u32 displayList: dislay list segmented address
+ */
+#define GEO_ANIMATED_PART(layer, x, y, z, displayList) \
+ CMD_BBH(0x13, layer, x), \
+ CMD_HH(y, z), \
+ CMD_PTR(displayList)
+
+/**
+ * 0x14: Create billboarding node with optional display list
+ * 0x01: u8 params
+ * 0b1000_0000: if set, enable displayList field and drawingLayer
+ * 0b0000_1111: drawingLayer
+ * 0x02: s16 xTranslation
+ * 0x04: s16 yTranslation
+ * 0x06: s16 zTranslation
+ * 0x08: [u32 displayList: if MSbit of params is set, display list segmented address]
+ */
+#define GEO_BILLBOARD_WITH_PARAMS(layer, tx, ty, tz) \
+ CMD_BBH(0x14, layer, tx), \
+ CMD_HH(ty, tz)
+#define GEO_BILLBOARD_WITH_PARAMS_AND_DL(layer, tx, ty, tz, displayList) \
+ CMD_BBH(0x14, (layer | 0x80), tx), \
+ CMD_HH(ty, tz), \
+ CMD_PTR(displayList)
+#define GEO_BILLBOARD() \
+ GEO_BILLBOARD_WITH_PARAMS(0, 0, 0, 0)
+
+/**
+ * 0x15: Create plain display list scene graph node
+ * 0x01: u8 drawingLayer
+ * 0x02-0x03: unused
+ * 0x04: u32 displayList: display list segmented address
+ */
+#define GEO_DISPLAY_LIST(layer, displayList) \
+ CMD_BBH(0x15, layer, 0x0000), \
+ CMD_PTR(displayList)
+
+/**
+ * 0x16: Create shadow scene graph node
+ * 0x01: unused
+ * 0x02: s16 shadowType (cast to u8)
+ * 0x04: s16 shadowSolidity (cast to u8)
+ * 0x06: s16 shadowScale
+ */
+#define GEO_SHADOW(type, solidity, scale) \
+ CMD_BBH(0x16, 0x00, type), \
+ CMD_HH(solidity, scale)
+
+/**
+ * 0x17: Create render object scene graph node
+ * 0x01-0x03: unused
+ */
+#define GEO_RENDER_OBJ() \
+ CMD_BBH(0x17, 0x00, 0x0000)
+
+/**
+ * 0x18: Create dynamically generated displaylist scene graph node
+ * 0x01: unused
+ * 0x02: s16 parameter
+ * 0x04: GraphNodeFunc function
+ */
+#define GEO_ASM(param, function) \
+ CMD_BBH(0x18, 0x00, param), \
+ CMD_PTR(function)
+
+/**
+ * 0x19: Create background scene graph node
+ * 0x02: s16 background: background ID, or RGBA5551 color if backgroundFunc is null
+ * 0x04: GraphNodeFunc backgroundFunc
+ */
+#define GEO_BACKGROUND(background, function) \
+ CMD_BBH(0x19, 0x00, background), \
+ CMD_PTR(function)
+#define GEO_BACKGROUND_COLOR(background) \
+ GEO_BACKGROUND(background, NULL)
+
+/**
+ * 0x1A: No operation
+ */
+#define GEO_NOP_1A() \
+ CMD_BBH(0x1A, 0x00, 0x0000), \
+ CMD_HH(0x0000, 0x0000)
+
+/**
+ * 0x1B: Copy the shared children from an object parent node from a specific view
+ * to a newly created object parent.
+ * 0x02: s16 index of array
+ */
+#define GEO_COPY_VIEW(index) \
+ CMD_BBH(0x1B, 0x00, index)
+
+/**
+ * 0x1C: Create a held object scene graph node
+ * cmd+0x01: u8 unused
+ * cmd+0x02: s16 offsetX
+ * cmd+0x04: s16 offsetY
+ * cmd+0x06: s16 offsetZ
+ * cmd+0x08: GraphNodeFunc nodeFunc
+ */
+#define GEO_HELD_OBJECT(param, ux, uy, uz, nodeFunc) \
+ CMD_BBH(0x1C, param, ux), \
+ CMD_HH(uy, uz), \
+ CMD_PTR(nodeFunc)
+
+/**
+ * 0x1D: Create scale scene graph node with optional display list
+ * 0x01: u8 params
+ * 0b1000_0000: if set, enable displayList field and drawingLayer
+ * 0b0000_1111: drawingLayer
+ * 0x02-0x03: unused
+ * 0x04: u32 scale (0x10000 = 1.0)
+ * 0x08: [u32 displayList: if MSbit of params is set, display list segment address]
+ */
+#define GEO_SCALE(layer, scale) \
+ CMD_BBH(0x1D, layer, 0x0000), \
+ CMD_W(scale)
+#define GEO_SCALE_WITH_DL(layer, scale, displayList) \
+ CMD_BBH(0x1D, (layer | 0x80), 0x0000), \
+ CMD_W(scale), \
+ CMD_PTR(displayList)
+
+/**
+ * 0x1E: No operation
+ */
+#define GEO_NOP_1E() \
+ CMD_BBH(0x1E, 0x00, 0x0000), \
+ CMD_HH(0x0000, 0x0000)
+
+/**
+ * 0x1F: No operation
+ */
+#define GEO_NOP_1F() \
+ CMD_BBH(0x1F, 0x00, 0x0000), \
+ CMD_HH(0x0000, 0x0000), \
+ CMD_HH(0x0000, 0x0000), \
+ CMD_HH(0x0000, 0x0000)
+
+/**
+ * 0x20: Create a scene graph node that specifies for an object the radius that
+ * is used for frustum culling.
+ * 0x01: unused
+ * 0x02: s16 cullingRadius
+ */
+#define GEO_CULLING_RADIUS(cullingRadius) \
+ CMD_BBH(0x20, 0x00, cullingRadius) \ No newline at end of file
diff --git a/src/factories/sm64/GeoFactory.cpp.old b/src/factories/sm64/GeoFactory.cpp.old
new file mode 100644
index 0000000..e30f73a
--- /dev/null
+++ b/src/factories/sm64/GeoFactory.cpp.old
@@ -0,0 +1,594 @@
+#include "SGeoFactory.h"
+
+#include "spdlog/spdlog.h"
+#include "utils/MIODecoder.h"
+#include "GeoCommands.h"
+#include "Companion.h"
+#include <iostream>
+
+namespace fs = std::filesystem;
+
+enum GeoCommand {
+ BRANCH_AND_LINK,
+ END,
+ BRANCH,
+ RETURN,
+ OPEN_NODE,
+ CLOSE_NODE,
+ ASSIGN_AS_VIEW,
+ UPDATE_NODE_FLAGS,
+ NODE_ROOT,
+ NODE_ORTHO_PROJECTION,
+ NODE_PERSPECTIVE,
+ NODE_START,
+ NODE_MASTER_LIST,
+ NODE_LEVEL_OF_DETAIL,
+ NODE_SWITCH_CASE,
+ NODE_CAMERA,
+ NODE_TRANSLATION_ROTATION,
+ NODE_TRANSLATION,
+ NODE_ROTATION,
+ NODE_ANIMATED_PART,
+ NODE_BILLBOARD,
+ NODE_DISPLAY_LIST,
+ NODE_SHADOW,
+ NODE_OBJECT_PARENT,
+ NODE_ASM,
+ NODE_BACKGROUND,
+ NOP,
+ COPY_VIEW,
+ NODE_HELD_OBJ,
+ NODE_SCALE,
+ NOP2,
+ NOP3,
+ NODE_CULLING_RADIUS,
+ // Custom
+ BRANCH_AND_LINK_OTR,
+ BRANCH_OTR,
+ NODE_SWITCH_CASE_OTR,
+ NODE_CAMERA_OTR,
+ NODE_TRANSLATION_ROTATION_OTR,
+ NODE_TRANSLATION_OTR,
+ NODE_ROTATION_OTR,
+ NODE_ANIMATED_PART_OTR,
+ NODE_BILLBOARD_OTR,
+ NODE_DISPLAY_LIST_OTR,
+ NODE_ASM_OTR,
+ NODE_BACKGROUND_OTR,
+ NODE_HELD_OBJ_OTR,
+ NODE_SCALE_OTR
+};
+
+Vec3s gVec3sZero = { 0, 0, 0 };
+
+int16_t *read_vec3s_to_vec3f(Vec3f dst, int16_t *src) {
+ dst[0] = next_s16_in_geo_script(&src);
+ dst[1] = next_s16_in_geo_script(&src);
+ dst[2] = next_s16_in_geo_script(&src);
+ return src;
+}
+
+int16_t *read_vec3s(Vec3s dst, int16_t *src) {
+ dst[0] = next_s16_in_geo_script(&src);
+ dst[1] = next_s16_in_geo_script(&src);
+ dst[2] = next_s16_in_geo_script(&src);
+ return src;
+}
+
+int16_t *read_vec3s_angle(Vec3s dst, int16_t *src) {
+ dst[0] = next_s16_in_geo_script(&src);
+ dst[1] = next_s16_in_geo_script(&src);
+ dst[2] = next_s16_in_geo_script(&src);
+ return src;
+}
+
+void vec3s_copy(Vec3s dest, Vec3s src) {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+}
+
+void vec3s_set(Vec3s dest, int16_t x, int16_t y, int16_t z) {
+ dest[0] = x;
+ dest[1] = y;
+ dest[2] = z;
+}
+
+int current_tab_size = 0;
+
+static inline void print_cmd(GeoCommand cmd, std::string c){
+ if(cmd == GeoCommand::CLOSE_NODE){
+ current_tab_size--;
+ }
+
+ for(int i = 0; i < current_tab_size; i++){
+ std::cout << "\t";
+ }
+
+ if(cmd == GeoCommand::OPEN_NODE){
+ current_tab_size++;
+ }
+
+ std::cout << "GEO_" << c << "()" << std::endl;
+}
+
+typedef uint32_t GeoLayout;
+
+bool SGeoFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+
+ WriteHeader(writer, LUS::ResourceType::Blob, 0);
+
+ auto offset = data["offset"].as<size_t>();
+ auto cmd = (uint8_t*) buffer.data() + offset;
+ auto processing = true;
+
+ std::vector<GeoLayout> layout;
+ auto geo_writer = new LUS::BinaryWriter();
+
+#define GeoWrite(x) layout.insert(layout.end(), {x})
+
+ while(processing){
+ auto opcode = cmd[0x00];
+ switch (opcode) {
+ case CMD_INFO(BRANCH_AND_LINK) {
+ geo_writer->Write((uint8_t) BRANCH_AND_LINK_OTR);
+ uint32_t ptr = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x04)));
+ auto decl = Companion::Instance->GetNodeByAddr(ptr);
+
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found geo: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find geo at 0x{:X}", ptr);
+ geo_writer->Write((uint64_t) 0);
+ }
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(BRANCH) {
+ geo_writer->Write((uint8_t) BRANCH_OTR);
+ geo_writer->Write(cur_geo_cmd_u8(0x01));
+
+ int32_t ptr = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x04)));
+ auto decl = Companion::Instance->GetNodeByAddr(ptr);
+
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found geo: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find geo at 0x{:X}", ptr);
+ geo_writer->Write((uint64_t) 0);
+ }
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(END)
+ geo_writer->Write((uint8_t) END);
+ processing = false;
+ break;
+ case CMD_INFO(RETURN)
+ geo_writer->Write((uint8_t) RETURN);
+ processing = false;
+ break;
+ case CMD_NOP(OPEN_NODE)
+ case CMD_NOP(CLOSE_NODE)
+ case CMD_INFO(ASSIGN_AS_VIEW) {
+ geo_writer->Write(ASSIGN_AS_VIEW);
+ geo_writer->Write(cur_geo_cmd_s16(0x02));
+ break;
+ }
+ case CMD_INFO(UPDATE_NODE_FLAGS) {
+ geo_writer->Write((uint8_t) UPDATE_NODE_FLAGS);
+ geo_writer->Write(cur_geo_cmd_u8(0x01));
+ geo_writer->Write(cur_geo_cmd_s16(0x02));
+ break;
+ }
+ case CMD_INFO(NODE_ROOT) {
+ auto a1 = cur_geo_cmd_s16(0x02);
+ auto a2 = cur_geo_cmd_s16(0x04);
+ auto a3 = cur_geo_cmd_s16(0x06);
+ auto a4 = cur_geo_cmd_s16(0x08);
+ auto a5 = cur_geo_cmd_s16(0x0A);
+ GeoWrite(GEO_NODE_SCREEN_AREA(a1, a2, a3, a4, a5));
+ cmd += 0x0C << CMD_SIZE_SHIFT;
+ processing = false;
+ }
+ case CMD_INFO(NODE_ORTHO_PROJECTION) {
+ geo_writer->Write((uint8_t) NODE_ORTHO_PROJECTION);
+ geo_writer->Write(cur_geo_cmd_s16(0x02));
+ cmd += 0x04 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_PERSPECTIVE) {
+ geo_writer->Write((uint8_t) NODE_PERSPECTIVE);
+ auto param = cur_geo_cmd_u8(0x01);
+ auto fov = cur_geo_cmd_s16(0x02);
+ auto near = cur_geo_cmd_s16(0x04);
+ auto far = cur_geo_cmd_s16(0x06);
+
+ geo_writer->Write(param);
+ geo_writer->Write(fov);
+ geo_writer->Write(near);
+ geo_writer->Write(far);
+
+ if (param != 0) {
+ auto func = cur_geo_cmd_u32(0x08);
+ geo_writer->Write(func);
+ cmd += 4 << CMD_SIZE_SHIFT;
+ }
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_NOP(NODE_START)
+ case CMD_INFO(NODE_MASTER_LIST) {
+ geo_writer->Write((uint8_t) NODE_MASTER_LIST);
+ geo_writer->Write(cur_geo_cmd_u8(0x01));
+ cmd += 0x04 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_LEVEL_OF_DETAIL) {
+ geo_writer->Write((uint8_t) NODE_LEVEL_OF_DETAIL);
+ int16_t minDistance = cur_geo_cmd_s16(0x04);
+ int16_t maxDistance = cur_geo_cmd_s16(0x06);
+
+ geo_writer->Write(minDistance);
+ geo_writer->Write(maxDistance);
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_SWITCH_CASE) {
+ geo_writer->Write((uint8_t) NODE_SWITCH_CASE_OTR);
+ auto cs = cur_geo_cmd_s16(0x02);
+ auto ptr = cur_geo_cmd_u32(0x04);
+
+ geo_writer->Write(cs);
+ geo_writer->Write(ptr);
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_CAMERA) {
+ geo_writer->Write((uint8_t) NODE_CAMERA_OTR);
+ auto cmd_pos = (int16_t *) &cmd[4];
+ auto mode = cur_geo_cmd_s16(0x02);
+
+ geo_writer->Write(mode);
+
+ Vec3f pos, focus;
+
+ cmd_pos = read_vec3s_to_vec3f(pos, cmd_pos);
+ read_vec3s_to_vec3f(focus, cmd_pos);
+
+ geo_writer->Write(pos[0]);
+ geo_writer->Write(pos[1]);
+ geo_writer->Write(pos[2]);
+ geo_writer->Write(focus[0]);
+ geo_writer->Write(focus[1]);
+ geo_writer->Write(focus[2]);
+
+ auto ptr = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x10)));
+ geo_writer->Write(ptr);
+
+ cmd += 0x14 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_TRANSLATION_ROTATION) {
+ geo_writer->Write(NODE_TRANSLATION_ROTATION_OTR);
+ auto params = cur_geo_cmd_u8(0x01);
+ auto cmd_pos = (int16_t*) cmd;
+
+ Vec3s translation, rotation;
+
+ geo_writer->Write(params);
+
+ switch ((params & 0x70) >> 4) {
+ case 0:
+ cmd_pos = read_vec3s(translation, &cmd_pos[2]);
+ geo_writer->Write(translation[0]);
+ geo_writer->Write(translation[1]);
+ geo_writer->Write(translation[2]);
+ cmd_pos = read_vec3s_angle(rotation, cmd_pos);
+ geo_writer->Write(rotation[0]);
+ geo_writer->Write(rotation[1]);
+ geo_writer->Write(rotation[2]);
+ break;
+ case 1:
+ cmd_pos = read_vec3s(translation, &cmd_pos[1]);
+ geo_writer->Write(translation[0]);
+ geo_writer->Write(translation[1]);
+ geo_writer->Write(translation[2]);
+ break;
+ case 2:
+ cmd_pos = read_vec3s_angle(rotation, &cmd_pos[1]);
+ geo_writer->Write(rotation[0]);
+ geo_writer->Write(rotation[1]);
+ geo_writer->Write(rotation[2]);
+ break;
+ case 3:
+ cmd_pos += 2 << CMD_SIZE_SHIFT;
+ break;
+ }
+
+ if (params & 0x80) {
+ auto dlist = SEGMENT_OFFSET(BSWAP32(*(uint32_t*) &cmd_pos[0]));
+ auto decl = Companion::Instance->GetNodeByAddr(dlist);
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", dlist, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find display list at 0x{:X}", dlist);
+ geo_writer->Write((uint64_t) 0);
+ }
+ cmd_pos += 2 << CMD_SIZE_SHIFT;
+ }
+
+ cmd = (uint8_t*) cmd_pos;
+ break;
+ }
+ case CMD_INFO(NODE_TRANSLATION) {
+ geo_writer->Write(NODE_TRANSLATION_OTR);
+ auto params = cur_geo_cmd_u8(0x01);
+ auto cmd_pos = (int16_t*) cmd;
+
+ Vec3s translation;
+ cmd_pos = read_vec3s(translation, &cmd_pos[1]);
+
+ geo_writer->Write(translation[0]);
+ geo_writer->Write(translation[1]);
+ geo_writer->Write(translation[2]);
+
+ if (params & 0x80) {
+ auto dlist = SEGMENT_OFFSET(BSWAP32(*(uint32_t*) &cmd_pos[0]));
+ auto decl = Companion::Instance->GetNodeByAddr(dlist);
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", dlist, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find display list at 0x{:X}", dlist);
+ geo_writer->Write((uint64_t) 0);
+ }
+ cmd_pos += 2 << CMD_SIZE_SHIFT;
+ }
+
+ cmd = (uint8_t*) cmd_pos;
+ break;
+ }
+ case CMD_INFO(NODE_ROTATION) {
+ geo_writer->Write(NODE_ROTATION_OTR);
+ auto params = cur_geo_cmd_u8(0x01);
+ auto cmd_pos = (int16_t*) cmd;
+
+ Vec3s sp2c;
+ cmd_pos = read_vec3s(sp2c, &cmd_pos[1]);
+
+ geo_writer->Write(sp2c[0]);
+ geo_writer->Write(sp2c[1]);
+ geo_writer->Write(sp2c[2]);
+
+ if (params & 0x80) {
+ auto dlist = SEGMENT_OFFSET(BSWAP32(*(uint32_t*) &cmd_pos[0]));
+ auto decl = Companion::Instance->GetNodeByAddr(dlist);
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", dlist, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find display list at 0x{:X}", dlist);
+ geo_writer->Write((uint64_t) 0);
+ }
+ cmd_pos += 2 << CMD_SIZE_SHIFT;
+ }
+
+ cmd = (uint8_t*) cmd_pos;
+ break;
+ }
+ case CMD_INFO(NODE_ANIMATED_PART) {
+ geo_writer->Write(NODE_ANIMATED_PART_OTR);
+
+ auto layer = cur_geo_cmd_u8(0x01);
+ auto ptr = cur_geo_cmd_u32(0x08);
+
+ geo_writer->Write(layer);
+ geo_writer->Write(ptr);
+
+ auto dlist = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x08)));
+ auto decl = Companion::Instance->GetNodeByAddr(dlist);
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", dlist, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find display list at 0x{:X}", dlist);
+ geo_writer->Write((uint64_t) 0);
+ }
+
+ cmd += 0x0C << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_BILLBOARD) {
+ geo_writer->Write(NODE_BILLBOARD_OTR);
+
+ Vec3s translation;
+ auto params = cur_geo_cmd_u8(0x01);
+ auto cmd_pos = (int16_t*) cmd;
+
+ cmd_pos = read_vec3s(translation, &cmd_pos[1]);
+ geo_writer->Write(params);
+ if (params & 0x80) {
+ auto dlist = SEGMENT_OFFSET(BSWAP32(*(uint32_t*) &cmd_pos[0]));
+ auto decl = Companion::Instance->GetNodeByAddr(dlist);
+ if (decl.has_value()) {
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", dlist, hash,
+ std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find display list at 0x{:X}", dlist);
+ geo_writer->Write((uint64_t) 0);
+ }
+
+ cmd_pos += 2 << CMD_SIZE_SHIFT;
+ }
+
+ cmd = (uint8_t*) cmd_pos;
+ break;
+ }
+ case CMD_INFO(NODE_DISPLAY_LIST) {
+ geo_writer->Write((uint8_t) NODE_DISPLAY_LIST_OTR);
+
+ int32_t layer = cur_geo_cmd_u8(0x01);
+ auto ptr = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x04)));
+
+ geo_writer->Write(layer);
+
+ auto decl = Companion::Instance->GetNodeByAddr(ptr);
+
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find display list at 0x{:X}", ptr);
+ geo_writer->Write((uint64_t) 0);
+ }
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_SHADOW) {
+ geo_writer->Write((uint8_t) NODE_SHADOW);
+ auto type = cur_geo_cmd_s16(0x02);
+ auto solidity = cur_geo_cmd_s16(0x04);
+ auto scale = cur_geo_cmd_s16(0x06);
+
+ geo_writer->Write(type);
+ geo_writer->Write(solidity);
+ geo_writer->Write(scale);
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_NOP(NODE_OBJECT_PARENT)
+ case CMD_INFO(NODE_ASM) {
+ geo_writer->Write(NODE_ASM_OTR);
+ auto param = cur_geo_cmd_s16(0x02);
+ auto ptr = cur_geo_cmd_u32(0x04);
+
+ geo_writer->Write(param);
+ geo_writer->Write(SEGMENT_OFFSET(BSWAP32(ptr)));
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_BACKGROUND) {
+ geo_writer->Write((uint8_t) NODE_BACKGROUND_OTR);
+ auto bg = cur_geo_cmd_s16(0x02);
+ geo_writer->Write(bg);
+
+ auto ptr = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x04)));
+ geo_writer->Write(ptr);
+
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NOP) {
+ geo_writer->Write((uint8_t) NOP);
+ geo_writer->Write((uint32_t) 0);
+ geo_writer->Write((uint32_t) 0);
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(COPY_VIEW) {
+ geo_writer->Write((uint32_t) COPY_VIEW);
+ auto idx = cur_geo_cmd_s16(0x02);
+ geo_writer->Write(idx);
+ break;
+ }
+ case CMD_INFO(NODE_HELD_OBJ) {
+ geo_writer->Write((uint8_t) NODE_HELD_OBJ_OTR);
+
+ auto idx = cur_geo_cmd_u8(0x01);
+ geo_writer->Write(idx);
+
+ Vec3s c_offset;
+ read_vec3s(c_offset, (int16_t*) &cmd[0x02]);
+
+ geo_writer->Write(c_offset[0]);
+ geo_writer->Write(c_offset[1]);
+ geo_writer->Write(c_offset[2]);
+
+ auto ptr = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x08)));
+ geo_writer->Write(ptr);
+
+ cmd += 0x0C << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_SCALE) {
+ geo_writer->Write(NODE_SCALE_OTR);
+ auto params = cur_geo_cmd_u8(0x01);
+ auto scale = cur_geo_cmd_u32(0x04);
+
+ geo_writer->Write(params);
+ geo_writer->Write(scale);
+
+ if (params & 0x80) {
+ auto dlist = SEGMENT_OFFSET(BSWAP32(cur_geo_cmd_u32(0x08)));
+ auto decl = Companion::Instance->GetNodeByAddr(dlist);
+ if(decl.has_value()){
+ uint64_t hash = CRC64(std::get<0>(decl.value()).c_str());
+ SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", dlist, hash, std::get<0>(decl.value()));
+ geo_writer->Write(hash);
+ } else {
+ SPDLOG_INFO("Warning: Could not find display list at 0x{:X}", dlist);
+ geo_writer->Write((uint64_t) 0);
+ }
+ cmd += 4 << CMD_SIZE_SHIFT;
+ }
+ break;
+ }
+ case CMD_INFO(NOP2) {
+ geo_writer->Write((uint8_t) NOP2);
+ geo_writer->Write((uint32_t) 0);
+ geo_writer->Write((uint32_t) 0);
+ cmd += 0x08 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NOP3) {
+ geo_writer->Write((uint8_t) NOP3);
+ geo_writer->Write((uint32_t) 0);
+ geo_writer->Write((uint32_t) 0);
+ geo_writer->Write((uint32_t) 0);
+ cmd += 0x10 << CMD_SIZE_SHIFT;
+ break;
+ }
+ case CMD_INFO(NODE_CULLING_RADIUS) {
+ geo_writer->Write((uint8_t) NODE_CULLING_RADIUS);
+ auto radius = cur_geo_cmd_s16(0x02);
+ geo_writer->Write(radius);
+ break;
+ }
+ default:
+ std::cout << "Unknown command: " << std::hex << (int) cmd[0x00] << std::endl;
+ break;
+ }
+ }
+
+ auto size = geo_writer->GetLength();
+ auto data_ptr = geo_writer->ToVector();
+// auto s = size + layout.size() * sizeof(GeoLayout);
+// writer->Write(s);
+// writer->Write(data_ptr.data(), size);
+
+ writer->Write((uint32_t) layout.size());
+ writer->Write((char*) layout.data(), layout.size() * sizeof(GeoLayout));
+ geo_writer->Close();
+
+ return true;
+}
diff --git a/src/factories/debug/MIO0Factory.h b/src/factories/sm64/GeoFactory.h.old
index 7df6ee9..331e072 100644
--- a/src/factories/debug/MIO0Factory.h
+++ b/src/factories/sm64/GeoFactory.h.old
@@ -2,8 +2,8 @@
#include "../RawFactory.h"
-class MIO0Factory : public RawFactory {
+class SGeoFactory : public RawFactory {
public:
- MIO0Factory() = default;
+ SGeoFactory() = default;
bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
}; \ No newline at end of file
diff --git a/src/factories/sm64/SAnimFactory.cpp b/src/factories/sm64/SAnimFactory.cpp
deleted file mode 100644
index 06d5944..0000000
--- a/src/factories/sm64/SAnimFactory.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "SAnimFactory.h"
-
-#include "spdlog/spdlog.h"
-#include "utils/MIODecoder.h"
-#include "binarytools/BinaryReader.h"
-
-namespace fs = std::filesystem;
-
-void WriteAnimationHeader(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- auto offset = data["offset"].as<uint32_t>();
- auto size = data["size"].as<uint32_t>();
-
- LUS::BinaryReader reader((char*) buffer.data() + offset, size);
- reader.SetEndianness(LUS::Endianness::Big);
-
- auto flags = reader.ReadInt16();
- auto animYTransDivisor = reader.ReadInt16();
- auto startFrame = reader.ReadInt16();
- auto loopStart = reader.ReadInt16();
- auto loopEnd = reader.ReadInt16();
- auto unusedBoneCount = reader.ReadInt16();
- reader.ReadUInt32();
- reader.ReadUInt32();
- auto length = reader.ReadUInt32();
-
- SPDLOG_INFO("Flags: {}", flags);
- SPDLOG_INFO("Anim-Y Trans Divisor: {}", animYTransDivisor);
- SPDLOG_INFO("Start Frame: {}", startFrame);
- SPDLOG_INFO("Loop Start: {}", loopStart);
- SPDLOG_INFO("Loop End: {}", loopEnd);
- SPDLOG_INFO("Unused Bone Count: {}", unusedBoneCount);
- SPDLOG_INFO("Length: {}", length);
-
- WRITE_I16(flags);
- WRITE_I16(animYTransDivisor);
- WRITE_I16(startFrame);
- WRITE_I16(loopStart);
- WRITE_I16(loopEnd);
- WRITE_I16(unusedBoneCount);
- WRITE_U64(length);
- reader.Close();
-}
-
-void WriteAnimationIndex(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- auto offset = data["offset"].as<uint32_t>();
- auto size = data["size"].as<uint32_t>();
-
- LUS::BinaryReader reader((char*) buffer.data() + offset, size);
- reader.SetEndianness(LUS::Endianness::Big);
- size_t entries = size / sizeof(uint16_t);
- SPDLOG_INFO("Found Indices: {}", entries);
- WRITE_U32(entries);
- for(size_t id = 0; id < entries; id++) {
- WRITE_I16(reader.ReadInt16());
- }
- reader.Close();
-}
-
-void WriteAnimationValues(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- auto offset = data["offset"].as<uint32_t>();
- auto size = data["size"].as<uint32_t>();
-
- LUS::BinaryReader reader((char*) buffer.data() + offset, size);
- reader.SetEndianness(LUS::Endianness::Big);
- size_t entries = size / sizeof(uint16_t);
- SPDLOG_INFO("Found Values: {}", entries);
- WRITE_U32(entries);
- for(size_t id = 0; id < entries; id++) {
- WRITE_U16(reader.ReadUInt16());
- }
- reader.Close();
-}
-
-bool SAnimFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- WRITE_HEADER(LUS::ResourceType::Anim, 0);
-
- auto header = data["header"];
- auto values = data["values"];
- auto index = data["indices"];
-
- WriteAnimationHeader(writer, header, buffer);
- WriteAnimationIndex(writer, index, buffer);
- WriteAnimationValues(writer, values, buffer);
-
- return true;
-}
diff --git a/src/factories/sm64/SAnimFactory.h b/src/factories/sm64/SAnimFactory.h
deleted file mode 100644
index a5fa529..0000000
--- a/src/factories/sm64/SAnimFactory.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "factories/RawFactory.h"
-
-class SAnimFactory : public RawFactory {
-public:
- SAnimFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
-}; \ No newline at end of file
diff --git a/src/factories/sm64/SDialogFactory.cpp b/src/factories/sm64/SDialogFactory.cpp
deleted file mode 100644
index 474690a..0000000
--- a/src/factories/sm64/SDialogFactory.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#include <iostream>
-#include "SDialogFactory.h"
-
-#include "spdlog/spdlog.h"
-#include "utils/MIODecoder.h"
-#include "binarytools/BinaryReader.h"
-
-namespace fs = std::filesystem;
-
-static size_t id = 0;
-
-bool SDialogFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
-
- WRITE_HEADER(LUS::ResourceType::SDialog, 0);
-
- auto offset = data["offset"].as<size_t>();
- auto mio0 = data["mio0"].as<size_t>();
-
- std::vector<uint8_t> text;
- auto decoded = MIO0Decoder::Decode(buffer, offset);
- auto bytes = (uint8_t*) decoded.data();
- LUS::BinaryReader reader(decoded.data(), decoded.size());
- reader.SetEndianness(LUS::Endianness::Big);
- reader.Seek(mio0, LUS::SeekOffsetType::Start);
-
- auto unused = reader.ReadUInt32();
- auto linesPerBox = reader.ReadUByte();
- // Padding
- reader.Read(1);
- auto leftOffset = reader.ReadInt16();
- auto width = reader.ReadInt16();
- // Padding
- reader.Read(2);
- auto str = SEGMENT_OFFSET(reader.ReadInt32());
-
- while(bytes[str] != 0xFF){
- auto c = bytes[str++];
- text.push_back(c);
- }
- text.push_back(0xFF);
-
- SPDLOG_INFO("Unused: {}", unused);
- SPDLOG_INFO("Lines per box: {}", linesPerBox);
- SPDLOG_INFO("Left offset: {}", leftOffset);
- SPDLOG_INFO("Width: {}", width);
- SPDLOG_INFO("Size: {}", text.size());
-
- WRITE_U32(unused);
- WRITE_I8(linesPerBox);
- WRITE_I16(leftOffset);
- WRITE_I16(width);
-
- WRITE_U32(text.size());
- WRITE_ARRAY(text.data(), text.size());
-
- if(id == 85){
- int bp = 0;
- }
-
- id++;
- return true;
-} \ No newline at end of file
diff --git a/src/factories/sm64/SDialogFactory.h b/src/factories/sm64/SDialogFactory.h
deleted file mode 100644
index a1f58a9..0000000
--- a/src/factories/sm64/SDialogFactory.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "../RawFactory.h"
-
-class SDialogFactory : public RawFactory {
-public:
- SDialogFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
-}; \ No newline at end of file
diff --git a/src/factories/sm64/SDictionaryFactory.cpp b/src/factories/sm64/SDictionaryFactory.cpp
deleted file mode 100644
index e9d598f..0000000
--- a/src/factories/sm64/SDictionaryFactory.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "SDictionaryFactory.h"
-
-#include "utils/MIODecoder.h"
-
-namespace fs = std::filesystem;
-
-bool SDictionaryFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
-
- WRITE_HEADER(LUS::ResourceType::Dictionary, 0);
-
- auto entries = data["keys"].size();
- WRITE_U32(entries);
-
- // Iterate on yaml keys
- for (auto it = data["keys"].begin(); it != data["keys"].end(); ++it) {
- auto key = it->first.as<std::string>();
- auto offset = it->second.as<size_t>();
-
- std::vector<uint8_t> text;
- auto bytes = (uint8_t*) buffer.data();
-
- while(bytes[offset] != 0xFF){
- auto c = bytes[offset++];
- text.push_back(c);
- }
-
- text.push_back(0xFF);
-
- writer->Write(key);
- WRITE_U32(text.size());
- WRITE_ARRAY(text.data(), text.size());
- }
-
- return true;
-}
diff --git a/src/factories/sm64/SDictionaryFactory.h b/src/factories/sm64/SDictionaryFactory.h
deleted file mode 100644
index 9dd5753..0000000
--- a/src/factories/sm64/SDictionaryFactory.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "../RawFactory.h"
-
-class SDictionaryFactory : public RawFactory {
-public:
- SDictionaryFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
-}; \ No newline at end of file
diff --git a/src/factories/sm64/STextFactory.cpp b/src/factories/sm64/STextFactory.cpp
deleted file mode 100644
index e6b27ee..0000000
--- a/src/factories/sm64/STextFactory.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "STextFactory.h"
-
-#include "utils/MIODecoder.h"
-
-namespace fs = std::filesystem;
-
-bool STextFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
-
- WRITE_HEADER(LUS::ResourceType::Blob, 0);
-
- auto offset = data["offset"].as<size_t>();
- auto mio0 = data["mio0"].as<size_t>();
-
- std::vector<uint8_t> text;
- auto decoded = MIO0Decoder::Decode(buffer, offset);
- auto bytes = (uint8_t*) decoded.data();
-
- while(bytes[mio0] != 0xFF){
- auto c = bytes[mio0++];
- text.push_back(c);
- }
- text.push_back(0xFF);
-
- WRITE_U32(text.size());
- WRITE_ARRAY(text.data(), text.size());
-
- return true;
-}
diff --git a/src/factories/sm64/STextFactory.h b/src/factories/sm64/STextFactory.h
deleted file mode 100644
index 7f9fe00..0000000
--- a/src/factories/sm64/STextFactory.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "../RawFactory.h"
-
-class STextFactory : public RawFactory {
-public:
- STextFactory() = default;
- bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
-}; \ No newline at end of file
diff --git a/src/factories/sm64/TextFactory.cpp b/src/factories/sm64/TextFactory.cpp
new file mode 100644
index 0000000..6fcda1e
--- /dev/null
+++ b/src/factories/sm64/TextFactory.cpp
@@ -0,0 +1,29 @@
+#include "TextFactory.h"
+#include "utils/MIODecoder.h"
+
+void SM64::TextBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto writer = LUS::BinaryWriter();
+ auto data = std::static_pointer_cast<RawBuffer>(raw)->mBuffer;
+
+ WriteHeader(writer, LUS::ResourceType::Blob, 0);
+ writer.Write((uint32_t) data.size());
+ writer.Write((char*) data.data(), data.size());
+ writer.Finish(write);
+}
+
+std::optional<std::shared_ptr<IParsedData>> SM64::TextFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
+ auto offset = data["offset"].as<size_t>();
+ auto mio0 = data["mio0"].as<size_t>();
+
+ std::vector<uint8_t> text;
+ auto decoded = MIO0Decoder::Decode(buffer, mio0);
+ auto bytes = (uint8_t*) decoded.data();
+
+ while(bytes[offset] != 0xFF){
+ auto c = bytes[offset++];
+ text.push_back(c);
+ }
+ text.push_back(0xFF);
+
+ return std::make_shared<RawBuffer>(text);
+} \ No newline at end of file
diff --git a/src/factories/sm64/TextFactory.h b/src/factories/sm64/TextFactory.h
new file mode 100644
index 0000000..9c030b7
--- /dev/null
+++ b/src/factories/sm64/TextFactory.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "../BaseFactory.h"
+#include "../../types/RawBuffer.h"
+
+namespace SM64 {
+class TextBinaryExporter : public BaseExporter {
+ void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class TextFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return { REGISTER(Binary, TextBinaryExporter) };
+ }
+};
+}; \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 9001fcb..7cab502 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -5,39 +5,69 @@
#ifdef STANDALONE
Companion* Companion::Instance;
-void BindOTRMode(CLI::App& app){
- auto otr = app.add_subcommand("otr", "Extracts the rom to a folder");
+int main(int argc, char *argv[]) {
+ CLI::App app{"Torch - [T]orch is [O]ur [R]esource [C]onversion [H]elper\n\
+ * It extracts from a baserom and generates code or an otr.\n\
+ * It can also generate an otr from a folder of assets.\n"
+ };
+ std::string mode;
std::string filename;
- otr->add_option("rom", filename, "sm64 us rom")->required()->check(CLI::ExistingFile);
+ std::string target;
+ std::string folder;
+ bool otrMode = false;
+ bool debug = false;
+ bool header = false;
+
+ app.require_subcommand();
+
+ /* Generate an OTR */
+ auto otr = app.add_subcommand("otr", "OTR - Generates an otr\n");
+
+ otr->add_option("<baserom.z64>", filename, "")->required()->check(CLI::ExistingFile);
+
+ otr->add_flag("-t,--target", target, "OTR output destination");
+ otr->add_flag("-o,--otr", otrMode, "OTR Mode");
+ otr->add_flag("-d,--dir", folder, "Generate OTR from a directory of assets");
+ otr->add_flag("-z,--zeader", header, "Generates a header");
+ otr->add_flag("-v,--verbose", debug, "Verbose Debug Mode");
otr->parse_complete_callback([&]() {
- auto instance = Companion::Instance = new Companion(filename);
- instance->Init();
- });
-}
+ auto instance = Companion::Instance = new Companion(filename, otrMode, debug);
+
+ if (header) {
+ instance->Init(ExportType::Header);
+ } else {
+ instance->Init(ExportType::Binary);
+ }
+
+ if (!folder.empty()) {
+ Companion::Pack(folder, target);
+ }
-void BindPackMode(CLI::App& app){
- auto pack = app.add_subcommand("pack", "Packs the rom from a folder");
- std::string folder;
- pack->add_option("folder", folder, "Folder")->required()->check(CLI::ExistingDirectory);
- std::string output;
- pack->add_option("output", output, "MPQ Output")->required();
- pack->parse_complete_callback([&]() {
- Companion::Pack(folder, output);
});
-}
-int main(int argc, char *argv[]) {
- CLI::App app{"CubeOS - Rom extractor"};
+ /* Generate C code */
+ auto code = app.add_subcommand("code", "Code - Generates C code\n");
- BindOTRMode(app);
- BindPackMode(app);
+ code->add_option("<baserom.z64>", filename, "")->required()->check(CLI::ExistingFile);
+
+ code->add_flag("-v,--verbose", debug, "Verbose Debug Mode; adds offsets to C code");
+ code->parse_complete_callback([&]() {
+ auto instance = Companion::Instance = new Companion(filename, otrMode, debug);
+ instance->Init(ExportType::Code);
+ });
try {
app.parse(argc, argv);
} catch (const CLI::ParseError &e) {
+ std::cout << app.help() << std::endl;
return app.exit(e);
}
+ // No arguments --> display help.
+ if (argc == 1) {
+ std::cout << app.help() << std::endl;
+ }
+
return 0;
}
#endif \ No newline at end of file
diff --git a/src/n64/Cartridge.h b/src/n64/Cartridge.h
index 9450239..82dd5b1 100644
--- a/src/n64/Cartridge.h
+++ b/src/n64/Cartridge.h
@@ -2,6 +2,7 @@
#include <vector>
#include <string>
+#include <cstdint>
namespace N64 {
enum class CountryCode {
diff --git a/src/n64/CommandMacros.h b/src/n64/CommandMacros.h
new file mode 100644
index 0000000..5466907
--- /dev/null
+++ b/src/n64/CommandMacros.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <cstdint>
+
+#define _SHIFTL(v, s, w) ((uint32_t)(((uint32_t)(v) & ((0x01 << (w)) - 1)) << (s)))
+#define _SHIFTR(v, s, w) ((uint32_t)(((uint32_t)(v) >> (s)) & ((0x01 << (w)) - 1)))
+
+#define CMD_SIZE_SHIFT (sizeof(uint32_t) >> 3)
+#define CMD_PROCESS_OFFSET(offset) (((offset) & 3) | (((offset) & ~3) << CMD_SIZE_SHIFT))
+
+#define CMD_BBBB(a, b, c, d) (_SHIFTL(a, 0, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(c, 16, 8) | _SHIFTL(d, 24, 8))
+#define CMD_BBH(a, b, c) (_SHIFTL(a, 0, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(c, 16, 16))
+#define CMD_HH(a, b) (_SHIFTL(a, 0, 16) | _SHIFTL(b, 16, 16))
+#define CMD_W(a) (a)
+#define CMD_PTR(a) ((uintptr_t)(a))
+
+#define CMD_HHHHHH(a, b, c, d, e, f) CMD_HH(a, b), CMD_HH(c, d), CMD_HH(e, f)
diff --git a/src/n64/gbi-otr.h b/src/n64/gbi-otr.h
new file mode 100644
index 0000000..74d707e
--- /dev/null
+++ b/src/n64/gbi-otr.h
@@ -0,0 +1,140 @@
+#pragma once
+
+// CUSTOM OTR COMMANDS
+#define G_SETTIMG_OTR_HASH 0x20
+#define G_SETFB 0x21
+#define G_RESETFB 0x22
+#define G_SETTIMG_FB 0x23
+#define G_VTX_OTR_FILEPATH 0x24
+#define G_SETTIMG_OTR_FILEPATH 0x25
+#define G_TRI1_OTR 0x26
+#define G_DL_OTR_FILEPATH 0x27
+#define G_PUSHCD 0x28
+#define G_MTX_OTR2 0x29
+#define G_DL_OTR_HASH 0x31
+#define G_VTX_OTR_HASH 0x32
+#define G_MARKER 0x33
+#define G_INVALTEXCACHE 0x34
+#define G_BRANCH_Z_OTR 0x35
+#define G_MTX_OTR 0x36
+#define G_TEXRECT_WIDE 0x37
+#define G_FILLWIDERECT 0x38
+
+/* GFX Effects */
+#define G_SETGRAYSCALE 0x39
+#define G_EXTRAGEOMETRYMODE 0x3a
+#define G_SETINTENSITY 0x40
+#define G_SETFILTERING 0x41
+
+#define gDPFillWideRectangle(pkt, ulx, uly, lrx, lry) \
+{ \
+ Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt); \
+ _g0->words.w0 = _SHIFTL(G_FILLWIDERECT, 24, 8) | _SHIFTL((lrx), 2, 22); \
+ _g0->words.w1 = _SHIFTL((lry), 2, 22); \
+ _g1->words.w0 = _SHIFTL((ulx), 2, 22); \
+ _g1->words.w1 = _SHIFTL((uly), 2, 22); \
+}
+
+#define gSPWideTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{ \
+ Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt), *_g2 = (Gfx*)(pkt); \
+ \
+ _g0->words.w0 = _SHIFTL(G_TEXRECT_WIDE, 24, 8) | _SHIFTL((xh), 0, 24); \
+ _g0->words.w1 = _SHIFTL((yh), 0, 24); \
+ _g1->words.w0 = (_SHIFTL(tile, 24, 3) | _SHIFTL((xl), 0, 24)); \
+ _g1->words.w1 = _SHIFTL((yl), 0, 24); \
+ _g2->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \
+ _g2->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \
+}
+
+#define gsSPWideTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{ { \
+ (_SHIFTL(G_TEXRECT_WIDE, 24, 8) | _SHIFTL((xh), 0, 24)), \
+ _SHIFTL((yh), 0, 24), \
+} }, \
+ { { \
+ (_SHIFTL((tile), 24, 3) | _SHIFTL((xl), 0, 24)), \
+ _SHIFTL((yl), 0, 24), \
+ } }, \
+{ \
+ { _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) } \
+}
+
+#define gSPExtraGeometryMode(pkt, c, s) \
+_DW({ \
+ Gfx* _g = (Gfx*)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_EXTRAGEOMETRYMODE, 24, 8) | _SHIFTL(~(u32)(c), 0, 24); \
+ _g->words.w1 = (u32)(s); \
+})
+
+#define gSPSetExtraGeometryMode(pkt, word) gSPExtraGeometryMode((pkt), 0, word)
+#define gSPClearExtraGeometryMode(pkt, word) gSPExtraGeometryMode((pkt), word, 0)
+
+#define __gSPInvalidateTexCache(pkt, addr) \
+ _DW({ \
+ Gfx* _g = (Gfx*)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_INVALTEXCACHE, 24, 8); \
+ _g->words.w1 = addr; \
+ })
+
+#define gsSPInvalidateTexCache() \
+ { _SHIFTL(G_INVALTEXCACHE, 24, 8), 0 }
+
+#define gsSPSetFB(pkt, fb) \
+ { \
+ Gfx* _g = (Gfx*)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETFB, 24, 8); \
+ _g->words.w1 = fb; \
+ }
+
+#define gsSPResetFB(pkt) \
+ { \
+ Gfx* _g = (Gfx*)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_RESETFB, 24, 8); \
+ _g->words.w1 = 0; \
+ }
+
+#define gSPGrayscale(pkt, state) \
+ { \
+ Gfx* _g = (Gfx*)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETGRAYSCALE, 24, 8); \
+ _g->words.w1 = state; \
+ }
+
+#define gsSPGrayscale(state) \
+ { (_SHIFTL(G_SETGRAYSCALE, 24, 8)), (state) }
+
+#define gSPDisableFiltering(pkt, state) \
+ { \
+ Gfx* _g = (Gfx*)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETFILTERING, 24, 8); \
+ _g->words.w1 = state; \
+ }
+
+#define gsSPDisableFiltering(state) \
+ { (_SHIFTL(G_SETFILTERING, 24, 8)), (state) }
+
+#define gsSP1TriangleOTR(v0, v1, v2, flag) \
+ { _SHIFTL(G_TRI1_OTR, 24, 8) | __gsSP1Triangle_w1f(v0, v1, v2, flag), 0 }
+
+#define gsSPVertexOTR(v, n, v0) \
+ { (_SHIFTL(G_VTX_OTR_HASH, 24, 8) | _SHIFTL((n), 12, 8) | _SHIFTL((v0) + (n), 1, 7)), (uintptr_t)(v) }
+
+#define gsSPBranchListOTRHash(dl) gsDma1p(G_DL_OTR_HASH, dl, 0, G_DL_NOPUSH)
+#define gsSPBranchListOTRFilePath(dl) gsDma1p(G_DL_OTR_FILEPATH, dl, 0, G_DL_NOPUSH)
+#define gsSPDisplayListOTRHash(dl) gsDma1p(G_DL_OTR_HASH, dl, 0, G_DL_PUSH)
+#define gsSPDisplayListOTRFilePath(dl) gsDma1p(G_DL_OTR_FILEPATH, dl, 0, G_DL_PUSH)
+#define gDPSetGrayscaleColor(pkt, r, g, b, lerp) DPRGBColor(pkt, G_SETINTENSITY, r, g, b, lerp)
+#define gsDPSetGrayscaleColor(r, g, b, a) sDPRGBColor(G_SETINTENSITY, r, g, b, a)
+
+#define gsDPSetCombineLERP_NoMacros(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \
+ { \
+ _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(GCCc0w0(a0, c0, Aa0, Ac0) | GCCc1w0(a1, c1), 0, 24), \
+ (unsigned int)(GCCc0w1(b0, d0, Ab0, Ad0) | GCCc1w1(b1, Aa1, Ac1, d1, Ab1, Ad1)) \
+ }
diff --git a/src/n64/gbi.h b/src/n64/gbi.h
new file mode 100644
index 0000000..4f8596a
--- /dev/null
+++ b/src/n64/gbi.h
@@ -0,0 +1,4801 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+/**************************************************************************
+ *
+ * $Revision: 1.141 $
+ * $Date: 1999/09/03 03:43:08 $
+ * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/gbi.h,v $
+ *
+ **************************************************************************/
+
+#ifndef _GBI_H_
+#define _GBI_H_
+
+#include "gbi-otr.h"
+
+/*
+ * To use the F3DEX ucodes, define F3DEX_GBI before include this file.
+ *
+ * #define F3DEX_GBI
+ * #include <ultra64.h>
+ *
+ * or
+ *
+ * cc -c -DF3DEX_GBI -I.... foo.c
+ *
+ */
+
+/**************************************************************************
+ *
+ * Graphics Binary Interface
+ *
+ **************************************************************************/
+
+/*
+ * Graphics Commands, 'xxx' parts may be generated from ucode
+ *
+ * The command format is
+ *
+ * |00xxxxxx| = DMA 0,..,127
+ * |10xxxxxx| = Immediate Mode -65,..,-128
+ * |11xxxxxx| = RDP cmds -1,..,-64
+ *
+ * Note: in order for the RSP microcode to process RDP commands opaquely,
+ * we need to further identify those RDP commands that need DRAM address
+ * "fixup". To do this, we have the dummy command G_RDP_ADDR_FIXUP, and
+ * all |RDP commands| less than this are commands with embedded DRAM
+ * addresses. Further, the format of these commands should be similar so
+ * only one fixup routine is needed.
+ *
+ * Further explanation:
+ * The names of the commands are somewhat misleading. Here is clarification:
+ *
+ * - a 'DMA' type command has a pointer to additional data and
+ * causes a DMA transfer to bring that into DMEM.
+ *
+ * - an 'Immediate' type command isn't really 'immediate', in the
+ * traditional sense. This just means that the entire command fits
+ * in the 64-bit word, and the ucode can execute it 'immediately'
+ * without additional memory transfers.
+ *
+ * - an 'RDP' command is identified as such because the RDP
+ * commands can be passed-thru the RSP and sent to the RDP
+ * directly. One further confusing thing, is that some 'DP'
+ * macros below actually generate immediate commands, not
+ * not direct DP commands.
+ *
+ * IMPLEMENTATION NOTE:
+ * There is another group of RDP commands that includes the triangle commands
+ * generated by the RSP code. These are the raw commands the rasterizer
+ * hardware chews on, with slope info, etc. They will follow the RDP
+ * ordering...
+ *
+ * IMPLEMENTATION NOTE:
+ * The RDP hardware has some of these bit patterns wired up. If the hardware
+ * changes, we must adjust this table, likewise we can't change/add things
+ * once the hardware is frozen. (actually, the RDP hardware only looks at
+ * the lower 6 bits of the command byte)
+ *
+ */
+
+#ifdef F3DEX_GBI_2E
+# ifndef F3DEX_GBI_2
+# define F3DEX_GBI_2
+# endif
+# define GBI_FLOATS
+#endif
+
+#ifdef F3DEX_GBI_2
+# ifndef F3DEX_GBI
+# define F3DEX_GBI
+# endif
+#define G_NOOP 0x00
+#define G_RDPHALF_2 0xf1
+#define G_SETOTHERMODE_H 0xe3
+#define G_SETOTHERMODE_L 0xe2
+#define G_RDPHALF_1 0xe1
+#define G_SPNOOP 0xe0
+#define G_ENDDL 0xdf
+#define G_DL 0xde
+#define G_LOAD_UCODE 0xdd
+#define G_MOVEMEM 0xdc
+#define G_MOVEWORD 0xdb
+#define G_MTX 0xda
+#define G_GEOMETRYMODE 0xd9
+#define G_POPMTX 0xd8
+#define G_TEXTURE 0xd7
+#define G_DMA_IO 0xd6
+#define G_SPECIAL_1 0xd5
+#define G_SPECIAL_2 0xd4
+#define G_SPECIAL_3 0xd3
+
+#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
+#else /* F3DEX_GBI_2 */
+
+/* DMA commands: */
+#define G_SPNOOP 0 /* handle 0 gracefully */
+#define G_MTX 1
+#define G_RESERVED0 2 /* not implemeted */
+#define G_MOVEMEM 3 /* move a block of memory (up to 4 words) to dmem */
+#define G_VTX 4
+#define G_RESERVED1 5 /* not implemeted */
+#define G_DL 6
+#define G_RESERVED2 7 /* not implemeted */
+#define G_RESERVED3 8 /* not implemeted */
+#define G_SPRITE2D_BASE 9 /* sprite command */
+
+/* IMMEDIATE commands: */
+#define G_IMMFIRST -65
+#define G_TRI1 (G_IMMFIRST-0)
+#define G_CULLDL (G_IMMFIRST-1)
+#define G_POPMTX (G_IMMFIRST-2)
+#define G_MOVEWORD (G_IMMFIRST-3)
+#define G_TEXTURE (G_IMMFIRST-4)
+#define G_SETOTHERMODE_H (G_IMMFIRST-5)
+#define G_SETOTHERMODE_L (G_IMMFIRST-6)
+#define G_ENDDL (G_IMMFIRST-7)
+#define G_SETGEOMETRYMODE (G_IMMFIRST-8)
+#define G_CLEARGEOMETRYMODE (G_IMMFIRST-9)
+#define G_LINE3D (G_IMMFIRST-10)
+#define G_RDPHALF_1 (G_IMMFIRST-11)
+#define G_RDPHALF_2 (G_IMMFIRST-12)
+#if (defined(F3DEX_GBI)||defined(F3DLP_GBI))
+# define G_MODIFYVTX (G_IMMFIRST-13)
+# define G_TRI2 (G_IMMFIRST-14)
+# define G_BRANCH_Z (G_IMMFIRST-15)
+# define G_LOAD_UCODE (G_IMMFIRST-16)
+#else
+# define G_RDPHALF_CONT (G_IMMFIRST-13)
+#endif
+
+/* We are overloading 2 of the immediate commands
+ to keep the byte alignment of dmem the same */
+
+#define G_SPRITE2D_SCALEFLIP (G_IMMFIRST-1)
+#define G_SPRITE2D_DRAW (G_IMMFIRST-2)
+
+/* RDP commands: */
+#define G_NOOP 0xc0 /* 0 */
+
+#endif /* F3DEX_GBI_2 */
+
+/* RDP commands: */
+#define G_SETCIMG 0xff /* -1 */
+#define G_SETZIMG 0xfe /* -2 */
+#define G_SETTIMG 0xfd /* -3 */
+#define G_SETCOMBINE 0xfc /* -4 */
+#define G_SETENVCOLOR 0xfb /* -5 */
+#define G_SETPRIMCOLOR 0xfa /* -6 */
+#define G_SETBLENDCOLOR 0xf9 /* -7 */
+#define G_SETFOGCOLOR 0xf8 /* -8 */
+#define G_SETFILLCOLOR 0xf7 /* -9 */
+#define G_FILLRECT 0xf6 /* -10 */
+#define G_SETTILE 0xf5 /* -11 */
+#define G_LOADTILE 0xf4 /* -12 */
+#define G_LOADBLOCK 0xf3 /* -13 */
+#define G_SETTILESIZE 0xf2 /* -14 */
+#define G_LOADTLUT 0xf0 /* -16 */
+#define G_RDPSETOTHERMODE 0xef /* -17 */
+#define G_SETPRIMDEPTH 0xee /* -18 */
+#define G_SETSCISSOR 0xed /* -19 */
+#define G_SETCONVERT 0xec /* -20 */
+#define G_SETKEYR 0xeb /* -21 */
+#define G_SETKEYGB 0xea /* -22 */
+#define G_RDPFULLSYNC 0xe9 /* -23 */
+#define G_RDPTILESYNC 0xe8 /* -24 */
+#define G_RDPPIPESYNC 0xe7 /* -25 */
+#define G_RDPLOADSYNC 0xe6 /* -26 */
+#define G_TEXRECTFLIP 0xe5 /* -27 */
+#define G_TEXRECT 0xe4 /* -28 */
+
+
+/*
+ * The following commands are the "generated" RDP commands; the user
+ * never sees them, the RSP microcode generates them.
+ *
+ * The layout of the bits is magical, to save work in the ucode.
+ * These id's are -56, -52, -54, -50, -55, -51, -53, -49, ...
+ * edge, shade, texture, zbuff bits: estz
+ */
+#define G_TRI_FILL 0xc8 /* fill triangle: 11001000 */
+#define G_TRI_SHADE 0xcc /* shade triangle: 11001100 */
+#define G_TRI_TXTR 0xca /* texture triangle: 11001010 */
+#define G_TRI_SHADE_TXTR 0xce /* shade, texture triangle: 11001110 */
+#define G_TRI_FILL_ZBUFF 0xc9 /* fill, zbuff triangle: 11001001 */
+#define G_TRI_SHADE_ZBUFF 0xcd /* shade, zbuff triangle: 11001101 */
+#define G_TRI_TXTR_ZBUFF 0xcb /* texture, zbuff triangle: 11001011 */
+#define G_TRI_SHADE_TXTR_ZBUFF 0xcf /* shade, txtr, zbuff trngl: 11001111 */
+
+/*
+ * A TRI_FILL triangle is just the edges. You need to set the DP
+ * to use primcolor, in order to see anything. (it is NOT a triangle
+ * that gets rendered in 'fill mode'. Triangles can't be rendered
+ * in 'fill mode')
+ *
+ * A TRI_SHADE is a gouraud triangle that has colors interpolated.
+ * Flat-shaded triangles (from the software) are still gouraud shaded,
+ * it's just the colors are all the same and the deltas are 0.
+ *
+ * Other triangle types, and combinations are more obvious.
+ */
+
+/* masks to build RDP triangle commands: */
+#define G_RDP_TRI_FILL_MASK 0x08
+#define G_RDP_TRI_SHADE_MASK 0x04
+#define G_RDP_TRI_TXTR_MASK 0x02
+#define G_RDP_TRI_ZBUFF_MASK 0x01
+
+/*
+ * HACK:
+ * This is a dreadful hack. For version 1.0 hardware, there are still
+ * some 'bowtie' hangs. This parameter can be increased to avoid
+ * the hangs. Every increase of 4 chops one scanline off of every
+ * triangle. Values of 4,8,12 should be sufficient to avoid any
+ * bowtie hang.
+ *
+ * Change this value, then recompile ALL of your program (including static
+ * display lists!)
+ *
+ * THIS WILL BE REMOVED FOR HARDWARE VERSION 2.0!
+ */
+#define BOWTIE_VAL 0
+
+
+/* gets added to RDP command, in order to test for addres fixup: */
+#define G_RDP_ADDR_FIXUP 3 /* |RDP cmds| <= this, do addr fixup */
+#ifdef _LANGUAGE_ASSEMBLY
+#define G_RDP_TEXRECT_CHECK ((-1*G_TEXRECTFLIP)& 0xff)
+#endif
+
+/* macros for command parsing: */
+#define GDMACMD(x) (x)
+#define GIMMCMD(x) (G_IMMFIRST-(x))
+#define GRDPCMD(x) (0xff-(x))
+
+#define G_DMACMDSIZ 128
+#define G_IMMCMDSIZ 64
+#define G_RDPCMDSIZ 64
+
+/*
+ * Coordinate shift values, number of bits of fraction
+ */
+#define G_TEXTURE_IMAGE_FRAC 2
+#define G_TEXTURE_SCALE_FRAC 16
+#define G_SCALE_FRAC 8
+#define G_ROTATE_FRAC 16
+
+/*
+ * Parameters to graphics commands
+ */
+
+/*
+ * Data packing macros
+ */
+
+/*
+ * Maximum z-buffer value, used to initialize the z-buffer.
+ * Note : this number is NOT the viewport z-scale constant.
+ * See the comment next to G_MAXZ for more info.
+ */
+#define G_MAXFBZ 0x3fff /* 3b exp, 11b mantissa */
+
+#define GPACK_RGBA5551(r, g, b, a) ((((r)<<8) & 0xf800) | \
+ (((g)<<3) & 0x7c0) | \
+ (((b)>>2) & 0x3e) | ((a) & 0x1))
+#define GPACK_ZDZ(z, dz) ((z) << 2 | (dz))
+
+/*
+ * G_MTX: parameter flags
+ */
+#ifdef F3DEX_GBI_2
+# define G_MTX_MODELVIEW 0x00 /* matrix types */
+# define G_MTX_PROJECTION 0x04
+# define G_MTX_MUL 0x00 /* concat or load */
+# define G_MTX_LOAD 0x02
+# define G_MTX_NOPUSH 0x00 /* push or not */
+# define G_MTX_PUSH 0x01
+#else /* F3DEX_GBI_2 */
+# define G_MTX_MODELVIEW 0x00 /* matrix types */
+# define G_MTX_PROJECTION 0x01
+# define G_MTX_MUL 0x00 /* concat or load */
+# define G_MTX_LOAD 0x02
+# define G_MTX_NOPUSH 0x00 /* push or not */
+# define G_MTX_PUSH 0x04
+#endif /* F3DEX_GBI_2 */
+
+/*
+ * flags for G_SETGEOMETRYMODE
+ * (this rendering state is maintained in RSP)
+ *
+ * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE:
+ * The weird bit-ordering is for the micro-code: the lower byte
+ * can be OR'd in with G_TRI_SHADE (11001100) to construct
+ * the triangle command directly. Don't break it...
+ *
+ * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE:
+ * The high byte is OR'd with 0x703 to form the clip code mask.
+ * If it is set to 0x04, this will cause near clipping to occur.
+ * If it is zero, near clipping will not occur.
+ *
+ * Further explanation:
+ * G_SHADE is necessary in order to see the color that you passed
+ * down with the vertex. If G_SHADE isn't set, you need to set the DP
+ * appropriately and use primcolor to see anything.
+ *
+ * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle.
+ * If it is not set, then do 'flat shading', where only one vertex color
+ * is used (and all 3 vertices are set to that same color by the ucode)
+ * See the man page for gSP1Triangle().
+ *
+ */
+#define G_ZBUFFER 0x00000001
+#define G_SHADE 0x00000004 /* enable Gouraud interp */
+/* rest of low byte reserved for setup ucode */
+#ifdef F3DEX_GBI_2
+# define G_TEXTURE_ENABLE 0x00000000 /* Ignored */
+# define G_SHADING_SMOOTH 0x00200000 /* flat or smooth shaded */
+# define G_CULL_FRONT 0x00000200
+# define G_CULL_BACK 0x00000400
+# define G_CULL_BOTH 0x00000600 /* To make code cleaner */
+#else
+# define G_TEXTURE_ENABLE 0x00000002 /* Microcode use only */
+# define G_SHADING_SMOOTH 0x00000200 /* flat or smooth shaded */
+# define G_CULL_FRONT 0x00001000
+# define G_CULL_BACK 0x00002000
+# define G_CULL_BOTH 0x00003000 /* To make code cleaner */
+#endif
+#define G_FOG 0x00010000
+#define G_LIGHTING 0x00020000
+#define G_TEXTURE_GEN 0x00040000
+#define G_TEXTURE_GEN_LINEAR 0x00080000
+#define G_LOD 0x00100000 /* NOT IMPLEMENTED */
+#if (defined(F3DEX_GBI)||defined(F3DLP_GBI))
+# define G_CLIPPING 0x00800000
+#else
+# define G_CLIPPING 0x00000000
+#endif
+
+#ifdef _LANGUAGE_ASSEMBLY
+#define G_FOG_H (G_FOG/0x10000)
+#define G_LIGHTING_H (G_LIGHTING/0x10000)
+#define G_TEXTURE_GEN_H (G_TEXTURE_GEN/0x10000)
+#define G_TEXTURE_GEN_LINEAR_H (G_TEXTURE_GEN_LINEAR/0x10000)
+#define G_LOD_H (G_LOD/0x10000) /* NOT IMPLEMENTED */
+#if (defined(F3DEX_GBI)||defined(F3DLP_GBI))
+# define G_CLIPPING_H (G_CLIPPING/0x10000)
+#endif
+#endif
+
+/* Need these defined for Sprite Microcode */
+#ifdef _LANGUAGE_ASSEMBLY
+#define G_TX_LOADTILE 7
+#define G_TX_RENDERTILE 0
+
+#define G_TX_NOMIRROR 0
+#define G_TX_WRAP 0
+#define G_TX_MIRROR 0x1
+#define G_TX_CLAMP 0x2
+#define G_TX_NOMASK 0
+#define G_TX_NOLOD 0
+#endif
+
+/*
+ * G_SETIMG fmt: set 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
+
+/*
+ * G_SETIMG siz: set image pixel size
+ */
+#define G_IM_SIZ_4b 0
+#define G_IM_SIZ_8b 1
+#define G_IM_SIZ_16b 2
+#define G_IM_SIZ_32b 3
+#define G_IM_SIZ_DD 5
+
+#define G_IM_SIZ_4b_BYTES 0
+#define G_IM_SIZ_4b_TILE_BYTES G_IM_SIZ_4b_BYTES
+#define G_IM_SIZ_4b_LINE_BYTES G_IM_SIZ_4b_BYTES
+
+#define G_IM_SIZ_8b_BYTES 1
+#define G_IM_SIZ_8b_TILE_BYTES G_IM_SIZ_8b_BYTES
+#define G_IM_SIZ_8b_LINE_BYTES G_IM_SIZ_8b_BYTES
+
+#define G_IM_SIZ_16b_BYTES 2
+#define G_IM_SIZ_16b_TILE_BYTES G_IM_SIZ_16b_BYTES
+#define G_IM_SIZ_16b_LINE_BYTES G_IM_SIZ_16b_BYTES
+
+#define G_IM_SIZ_32b_BYTES 4
+#define G_IM_SIZ_32b_TILE_BYTES 2
+#define G_IM_SIZ_32b_LINE_BYTES 2
+
+#define G_IM_SIZ_4b_LOAD_BLOCK G_IM_SIZ_16b
+#define G_IM_SIZ_8b_LOAD_BLOCK G_IM_SIZ_16b
+#define G_IM_SIZ_16b_LOAD_BLOCK G_IM_SIZ_16b
+#define G_IM_SIZ_32b_LOAD_BLOCK G_IM_SIZ_32b
+
+#define G_IM_SIZ_4b_SHIFT 2
+#define G_IM_SIZ_8b_SHIFT 1
+#define G_IM_SIZ_16b_SHIFT 0
+#define G_IM_SIZ_32b_SHIFT 0
+
+#define G_IM_SIZ_4b_INCR 3
+#define G_IM_SIZ_8b_INCR 1
+#define G_IM_SIZ_16b_INCR 0
+#define G_IM_SIZ_32b_INCR 0
+
+/*
+ * G_SETCOMBINE: color combine modes
+ */
+/* Color combiner constants: */
+#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_CENTER 6
+#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_NOISE 7
+#define G_CCMUX_K4 7
+#define G_CCMUX_K5 15
+#define G_CCMUX_1 6
+#define G_CCMUX_0 31
+
+/* Alpha combiner constants: */
+#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_LOD_FRACTION 0
+#define G_ACMUX_PRIM_LOD_FRAC 6
+#define G_ACMUX_1 6
+#define G_ACMUX_0 7
+
+/* typical CC cycle 1 modes */
+#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_MODULATEI TEXEL0, 0, SHADE, 0, 0, 0, 0, SHADE
+#define G_CC_MODULATEIDECALA TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0
+#define G_CC_MODULATEIFADE TEXEL0, 0, SHADE, 0, 0, 0, 0, ENVIRONMENT
+
+#define G_CC_MODULATERGB G_CC_MODULATEI
+#define G_CC_MODULATERGBDECALA G_CC_MODULATEIDECALA
+#define G_CC_MODULATERGBFADE G_CC_MODULATEIFADE
+
+#define G_CC_MODULATEIA TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0
+#define G_CC_MODULATEIFADEA TEXEL0, 0, SHADE, 0, TEXEL0, 0, ENVIRONMENT, 0
+
+#define G_CC_MODULATEFADE TEXEL0, 0, SHADE, 0, ENVIRONMENT, 0, TEXEL0, 0
+
+#define G_CC_MODULATERGBA G_CC_MODULATEIA
+#define G_CC_MODULATERGBFADEA G_CC_MODULATEIFADEA
+
+#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_FADE SHADE, 0, ENVIRONMENT, 0, SHADE, 0, ENVIRONMENT, 0
+#define G_CC_FADEA TEXEL0, 0, ENVIRONMENT, 0, TEXEL0, 0, ENVIRONMENT, 0
+
+#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_DECALFADE 0, 0, 0, TEXEL0, 0, 0, 0, ENVIRONMENT
+
+#define G_CC_DECALFADEA 0, 0, 0, TEXEL0, TEXEL0, 0, ENVIRONMENT, 0
+
+#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_BLENDRGBFADEA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, ENVIRONMENT
+
+#define G_CC_ADDRGB TEXEL0, 0, TEXEL0, SHADE, 0, 0, 0, SHADE
+#define G_CC_ADDRGBDECALA TEXEL0, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0
+#define G_CC_ADDRGBFADE TEXEL0, 0, TEXEL0, SHADE, 0, 0, 0, ENVIRONMENT
+
+#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_SHADEDECALA 0, 0, 0, SHADE, 0, 0, 0, TEXEL0
+#define G_CC_SHADEFADEA 0, 0, 0, SHADE, 0, 0, 0, ENVIRONMENT
+
+#define G_CC_BLENDPE PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, SHADE, 0
+#define G_CC_BLENDPEDECALA PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, TEXEL0
+
+/* oddball modes */
+#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_TWOCOLORTEX PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE
+/* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */
+#define _G_CC_SPARSEST PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0, PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0
+#define G_CC_TEMPLERP TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0
+
+/* typical CC cycle 1 modes, usually followed by other cycle 2 modes */
+#define G_CC_TRILERP TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0
+#define G_CC_INTERFERENCE TEXEL0, 0, TEXEL1, 0, TEXEL0, 0, TEXEL1, 0
+
+/*
+ * One-cycle color convert operation
+ */
+#define G_CC_1CYUV2RGB TEXEL0, K4, K5, TEXEL0, 0, 0, 0, SHADE
+
+/*
+ * NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock.
+ * Therefore, CC looks for step1 results in TEXEL1
+ */
+#define G_CC_YUV2RGB TEXEL1, K4, K5, TEXEL1, 0, 0, 0, 0
+
+/* typical CC cycle 2 modes */
+#define G_CC_PASS2 0, 0, 0, COMBINED, 0, 0, 0, COMBINED
+#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_DECALRGBA2 COMBINED, SHADE, COMBINED_ALPHA, SHADE, 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_CHROMA_KEY2 TEXEL0, CENTER, SCALE, 0, 0, 0, 0, 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
+
+/*
+ * G_SETOTHERMODE_L sft: shift count
+ */
+#define G_MDSFT_ALPHACOMPARE 0
+#define G_MDSFT_ZSRCSEL 2
+#define G_MDSFT_RENDERMODE 3
+#define G_MDSFT_BLENDER 16
+
+/*
+ * G_SETOTHERMODE_H sft: shift count
+ */
+#define G_MDSFT_BLENDMASK 0 /* unsupported */
+#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_COLORDITHER 22 /* unsupported in HW 2.0 */
+#define G_MDSFT_PIPELINE 23
+
+/* G_SETOTHERMODE_H gPipelineMode */
+#define G_PM_1PRIMITIVE (1 << G_MDSFT_PIPELINE)
+#define G_PM_NPRIMITIVE (0 << G_MDSFT_PIPELINE)
+
+/* G_SETOTHERMODE_H gSetCycleType */
+#define G_CYC_1CYCLE (0 << G_MDSFT_CYCLETYPE)
+#define G_CYC_2CYCLE (1 << G_MDSFT_CYCLETYPE)
+#define G_CYC_COPY (2 << G_MDSFT_CYCLETYPE)
+#define G_CYC_FILL (3 << G_MDSFT_CYCLETYPE)
+
+/* G_SETOTHERMODE_H gSetTexturePersp */
+#define G_TP_NONE (0 << G_MDSFT_TEXTPERSP)
+#define G_TP_PERSP (1 << G_MDSFT_TEXTPERSP)
+
+/* G_SETOTHERMODE_H gSetTextureDetail */
+#define G_TD_CLAMP (0 << G_MDSFT_TEXTDETAIL)
+#define G_TD_SHARPEN (1 << G_MDSFT_TEXTDETAIL)
+#define G_TD_DETAIL (2 << G_MDSFT_TEXTDETAIL)
+
+/* G_SETOTHERMODE_H gSetTextureLOD */
+#define G_TL_TILE (0 << G_MDSFT_TEXTLOD)
+#define G_TL_LOD (1 << G_MDSFT_TEXTLOD)
+
+/* G_SETOTHERMODE_H gSetTextureLUT */
+#define G_TT_NONE (0 << G_MDSFT_TEXTLUT)
+#define G_TT_RGBA16 (2 << G_MDSFT_TEXTLUT)
+#define G_TT_IA16 (3 << G_MDSFT_TEXTLUT)
+
+/* G_SETOTHERMODE_H gSetTextureFilter */
+#define G_TF_POINT (0 << G_MDSFT_TEXTFILT)
+#define G_TF_AVERAGE (3 << G_MDSFT_TEXTFILT)
+#define G_TF_BILERP (2 << G_MDSFT_TEXTFILT)
+
+/* G_SETOTHERMODE_H gSetTextureConvert */
+#define G_TC_CONV (0 << G_MDSFT_TEXTCONV)
+#define G_TC_FILTCONV (5 << G_MDSFT_TEXTCONV)
+#define G_TC_FILT (6 << G_MDSFT_TEXTCONV)
+
+/* G_SETOTHERMODE_H gSetCombineKey */
+#define G_CK_NONE (0 << G_MDSFT_COMBKEY)
+#define G_CK_KEY (1 << G_MDSFT_COMBKEY)
+
+/* G_SETOTHERMODE_H gSetColorDither */
+#define G_CD_MAGICSQ (0 << G_MDSFT_RGBDITHER)
+#define G_CD_BAYER (1 << G_MDSFT_RGBDITHER)
+#define G_CD_NOISE (2 << G_MDSFT_RGBDITHER)
+
+#ifndef _HW_VERSION_1
+#define G_CD_DISABLE (3 << G_MDSFT_RGBDITHER)
+#define G_CD_ENABLE G_CD_NOISE /* HW 1.0 compatibility mode */
+#else
+#define G_CD_ENABLE (1 << G_MDSFT_COLORDITHER)
+#define G_CD_DISABLE (0 << G_MDSFT_COLORDITHER)
+#endif
+
+/* G_SETOTHERMODE_H gSetAlphaDither */
+#define G_AD_PATTERN (0 << G_MDSFT_ALPHADITHER)
+#define G_AD_NOTPATTERN (1 << G_MDSFT_ALPHADITHER)
+#define G_AD_NOISE (2 << G_MDSFT_ALPHADITHER)
+#define G_AD_DISABLE (3 << G_MDSFT_ALPHADITHER)
+
+/* G_SETOTHERMODE_L gSetAlphaCompare */
+#define G_AC_NONE (0 << G_MDSFT_ALPHACOMPARE)
+#define G_AC_THRESHOLD (1 << G_MDSFT_ALPHACOMPARE)
+#define G_AC_DITHER (3 << G_MDSFT_ALPHACOMPARE)
+
+/* G_SETOTHERMODE_L gSetDepthSource */
+#define G_ZS_PIXEL (0 << G_MDSFT_ZSRCSEL)
+#define G_ZS_PRIM (1 << G_MDSFT_ZSRCSEL)
+
+/* G_SETOTHERMODE_L gSetRenderMode */
+#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 /* used to be 0x8000 */
+
+#define G_BL_CLR_IN 0
+#define G_BL_CLR_MEM 1
+#define G_BL_CLR_BL 2
+#define G_BL_CLR_FOG 3
+#define G_BL_1MA 0
+#define G_BL_A_MEM 1
+#define G_BL_A_IN 0
+#define G_BL_A_FOG 1
+#define G_BL_A_SHADE 2
+#define G_BL_1 2
+#define G_BL_0 3
+
+#define GBL_c1(m1a, m1b, m2a, m2b) \
+ (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18
+#define GBL_c2(m1a, m1b, m2a, m2b) \
+ (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16
+
+#define RM_AA_ZB_OPA_SURF(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_RA_ZB_OPA_SURF(clk) \
+ AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_ZB_XLU_SURF(clk) \
+ AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \
+ FORCE_BL | ZMODE_XLU | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_OPA_DECAL(clk) \
+ AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL | \
+ ZMODE_DEC | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_RA_ZB_OPA_DECAL(clk) \
+ AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | \
+ ZMODE_DEC | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_ZB_XLU_DECAL(clk) \
+ AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \
+ FORCE_BL | ZMODE_DEC | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_OPA_INTER(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
+ ALPHA_CVG_SEL | ZMODE_INTER | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_RA_ZB_OPA_INTER(clk) \
+ AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \
+ ALPHA_CVG_SEL | ZMODE_INTER | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_ZB_XLU_INTER(clk) \
+ AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \
+ FORCE_BL | ZMODE_INTER | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_XLU_LINE(clk) \
+ AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \
+ ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_DEC_LINE(clk) \
+ AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | \
+ ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_TEX_EDGE(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
+ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_ZB_TEX_INTER(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
+ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_ZB_SUB_SURF(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_ZB_PCL_SURF(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
+ ZMODE_OPA | G_AC_DITHER | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_OPA_TERR(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_TEX_TERR(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
+ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_ZB_SUB_TERR(clk) \
+ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+
+#define RM_AA_OPA_SURF(clk) \
+ AA_EN | IM_RD | CVG_DST_CLAMP | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_RA_OPA_SURF(clk) \
+ AA_EN | CVG_DST_CLAMP | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_XLU_SURF(clk) \
+ AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | \
+ ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_XLU_LINE(clk) \
+ AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \
+ ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_DEC_LINE(clk) \
+ AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA | \
+ ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_TEX_EDGE(clk) \
+ AA_EN | IM_RD | CVG_DST_CLAMP | \
+ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_SUB_SURF(clk) \
+ AA_EN | IM_RD | CVG_DST_FULL | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_AA_PCL_SURF(clk) \
+ AA_EN | IM_RD | CVG_DST_CLAMP | \
+ ZMODE_OPA | G_AC_DITHER | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_OPA_TERR(clk) \
+ AA_EN | IM_RD | CVG_DST_CLAMP | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_TEX_TERR(clk) \
+ AA_EN | IM_RD | CVG_DST_CLAMP | \
+ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_AA_SUB_TERR(clk) \
+ AA_EN | IM_RD | CVG_DST_FULL | \
+ ZMODE_OPA | ALPHA_CVG_SEL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+
+#define RM_ZB_OPA_SURF(clk) \
+ Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | \
+ ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_ZB_XLU_SURF(clk) \
+ Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_ZB_OPA_DECAL(clk) \
+ Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)
+
+#define RM_ZB_XLU_DECAL(clk) \
+ Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_ZB_CLD_SURF(clk) \
+ Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_ZB_OVL_SURF(clk) \
+ Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_ZB_PCL_SURF(clk) \
+ Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | \
+ G_AC_DITHER | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)
+
+
+#define RM_OPA_SURF(clk) \
+ CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)
+
+#define RM_XLU_SURF(clk) \
+ IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_TEX_EDGE(clk) \
+ CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL |\
+ ZMODE_OPA | TEX_EDGE | AA_EN | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)
+
+#define RM_CLD_SURF(clk) \
+ IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)
+
+#define RM_PCL_SURF(clk) \
+ CVG_DST_FULL | FORCE_BL | ZMODE_OPA | \
+ G_AC_DITHER | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)
+
+#define RM_ADD(clk) \
+ IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1)
+
+#define RM_NOOP(clk) \
+ GBL_c##clk(0, 0, 0, 0)
+
+#define RM_VISCVG(clk) \
+ IM_RD | FORCE_BL | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM)
+
+/* for rendering to an 8-bit framebuffer */
+#define RM_OPA_CI(clk) \
+ CVG_DST_CLAMP | ZMODE_OPA | \
+ GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)
+
+/* Custom version of RM_AA_ZB_XLU_SURF with Z_UPD */
+#define RM_CUSTOM_AA_ZB_XLU_SURF(clk) \
+ RM_AA_ZB_XLU_SURF(clk) | Z_UPD
+
+
+#define G_RM_AA_ZB_OPA_SURF RM_AA_ZB_OPA_SURF(1)
+#define G_RM_AA_ZB_OPA_SURF2 RM_AA_ZB_OPA_SURF(2)
+#define G_RM_AA_ZB_XLU_SURF RM_AA_ZB_XLU_SURF(1)
+#define G_RM_AA_ZB_XLU_SURF2 RM_AA_ZB_XLU_SURF(2)
+#define G_RM_AA_ZB_OPA_DECAL RM_AA_ZB_OPA_DECAL(1)
+#define G_RM_AA_ZB_OPA_DECAL2 RM_AA_ZB_OPA_DECAL(2)
+#define G_RM_AA_ZB_XLU_DECAL RM_AA_ZB_XLU_DECAL(1)
+#define G_RM_AA_ZB_XLU_DECAL2 RM_AA_ZB_XLU_DECAL(2)
+#define G_RM_AA_ZB_OPA_INTER RM_AA_ZB_OPA_INTER(1)
+#define G_RM_AA_ZB_OPA_INTER2 RM_AA_ZB_OPA_INTER(2)
+#define G_RM_AA_ZB_XLU_INTER RM_AA_ZB_XLU_INTER(1)
+#define G_RM_AA_ZB_XLU_INTER2 RM_AA_ZB_XLU_INTER(2)
+#define G_RM_AA_ZB_XLU_LINE RM_AA_ZB_XLU_LINE(1)
+#define G_RM_AA_ZB_XLU_LINE2 RM_AA_ZB_XLU_LINE(2)
+#define G_RM_AA_ZB_DEC_LINE RM_AA_ZB_DEC_LINE(1)
+#define G_RM_AA_ZB_DEC_LINE2 RM_AA_ZB_DEC_LINE(2)
+#define G_RM_AA_ZB_TEX_EDGE RM_AA_ZB_TEX_EDGE(1)
+#define G_RM_AA_ZB_TEX_EDGE2 RM_AA_ZB_TEX_EDGE(2)
+#define G_RM_AA_ZB_TEX_INTER RM_AA_ZB_TEX_INTER(1)
+#define G_RM_AA_ZB_TEX_INTER2 RM_AA_ZB_TEX_INTER(2)
+#define G_RM_AA_ZB_SUB_SURF RM_AA_ZB_SUB_SURF(1)
+#define G_RM_AA_ZB_SUB_SURF2 RM_AA_ZB_SUB_SURF(2)
+#define G_RM_AA_ZB_PCL_SURF RM_AA_ZB_PCL_SURF(1)
+#define G_RM_AA_ZB_PCL_SURF2 RM_AA_ZB_PCL_SURF(2)
+#define G_RM_AA_ZB_OPA_TERR RM_AA_ZB_OPA_TERR(1)
+#define G_RM_AA_ZB_OPA_TERR2 RM_AA_ZB_OPA_TERR(2)
+#define G_RM_AA_ZB_TEX_TERR RM_AA_ZB_TEX_TERR(1)
+#define G_RM_AA_ZB_TEX_TERR2 RM_AA_ZB_TEX_TERR(2)
+#define G_RM_AA_ZB_SUB_TERR RM_AA_ZB_SUB_TERR(1)
+#define G_RM_AA_ZB_SUB_TERR2 RM_AA_ZB_SUB_TERR(2)
+
+#define G_RM_RA_ZB_OPA_SURF RM_RA_ZB_OPA_SURF(1)
+#define G_RM_RA_ZB_OPA_SURF2 RM_RA_ZB_OPA_SURF(2)
+#define G_RM_RA_ZB_OPA_DECAL RM_RA_ZB_OPA_DECAL(1)
+#define G_RM_RA_ZB_OPA_DECAL2 RM_RA_ZB_OPA_DECAL(2)
+#define G_RM_RA_ZB_OPA_INTER RM_RA_ZB_OPA_INTER(1)
+#define G_RM_RA_ZB_OPA_INTER2 RM_RA_ZB_OPA_INTER(2)
+
+#define G_RM_AA_OPA_SURF RM_AA_OPA_SURF(1)
+#define G_RM_AA_OPA_SURF2 RM_AA_OPA_SURF(2)
+#define G_RM_AA_XLU_SURF RM_AA_XLU_SURF(1)
+#define G_RM_AA_XLU_SURF2 RM_AA_XLU_SURF(2)
+#define G_RM_AA_XLU_LINE RM_AA_XLU_LINE(1)
+#define G_RM_AA_XLU_LINE2 RM_AA_XLU_LINE(2)
+#define G_RM_AA_DEC_LINE RM_AA_DEC_LINE(1)
+#define G_RM_AA_DEC_LINE2 RM_AA_DEC_LINE(2)
+#define G_RM_AA_TEX_EDGE RM_AA_TEX_EDGE(1)
+#define G_RM_AA_TEX_EDGE2 RM_AA_TEX_EDGE(2)
+#define G_RM_AA_SUB_SURF RM_AA_SUB_SURF(1)
+#define G_RM_AA_SUB_SURF2 RM_AA_SUB_SURF(2)
+#define G_RM_AA_PCL_SURF RM_AA_PCL_SURF(1)
+#define G_RM_AA_PCL_SURF2 RM_AA_PCL_SURF(2)
+#define G_RM_AA_OPA_TERR RM_AA_OPA_TERR(1)
+#define G_RM_AA_OPA_TERR2 RM_AA_OPA_TERR(2)
+#define G_RM_AA_TEX_TERR RM_AA_TEX_TERR(1)
+#define G_RM_AA_TEX_TERR2 RM_AA_TEX_TERR(2)
+#define G_RM_AA_SUB_TERR RM_AA_SUB_TERR(1)
+#define G_RM_AA_SUB_TERR2 RM_AA_SUB_TERR(2)
+
+#define G_RM_RA_OPA_SURF RM_RA_OPA_SURF(1)
+#define G_RM_RA_OPA_SURF2 RM_RA_OPA_SURF(2)
+
+#define G_RM_ZB_OPA_SURF RM_ZB_OPA_SURF(1)
+#define G_RM_ZB_OPA_SURF2 RM_ZB_OPA_SURF(2)
+#define G_RM_ZB_XLU_SURF RM_ZB_XLU_SURF(1)
+#define G_RM_ZB_XLU_SURF2 RM_ZB_XLU_SURF(2)
+#define G_RM_ZB_OPA_DECAL RM_ZB_OPA_DECAL(1)
+#define G_RM_ZB_OPA_DECAL2 RM_ZB_OPA_DECAL(2)
+#define G_RM_ZB_XLU_DECAL RM_ZB_XLU_DECAL(1)
+#define G_RM_ZB_XLU_DECAL2 RM_ZB_XLU_DECAL(2)
+#define G_RM_ZB_CLD_SURF RM_ZB_CLD_SURF(1)
+#define G_RM_ZB_CLD_SURF2 RM_ZB_CLD_SURF(2)
+#define G_RM_ZB_OVL_SURF RM_ZB_OVL_SURF(1)
+#define G_RM_ZB_OVL_SURF2 RM_ZB_OVL_SURF(2)
+#define G_RM_ZB_PCL_SURF RM_ZB_PCL_SURF(1)
+#define G_RM_ZB_PCL_SURF2 RM_ZB_PCL_SURF(2)
+
+#define G_RM_OPA_SURF RM_OPA_SURF(1)
+#define G_RM_OPA_SURF2 RM_OPA_SURF(2)
+#define G_RM_XLU_SURF RM_XLU_SURF(1)
+#define G_RM_XLU_SURF2 RM_XLU_SURF(2)
+#define G_RM_CLD_SURF RM_CLD_SURF(1)
+#define G_RM_CLD_SURF2 RM_CLD_SURF(2)
+#define G_RM_TEX_EDGE RM_TEX_EDGE(1)
+#define G_RM_TEX_EDGE2 RM_TEX_EDGE(2)
+#define G_RM_PCL_SURF RM_PCL_SURF(1)
+#define G_RM_PCL_SURF2 RM_PCL_SURF(2)
+#define G_RM_ADD RM_ADD(1)
+#define G_RM_ADD2 RM_ADD(2)
+#define G_RM_NOOP RM_NOOP(1)
+#define G_RM_NOOP2 RM_NOOP(2)
+#define G_RM_VISCVG RM_VISCVG(1)
+#define G_RM_VISCVG2 RM_VISCVG(2)
+#define G_RM_OPA_CI RM_OPA_CI(1)
+#define G_RM_OPA_CI2 RM_OPA_CI(2)
+
+#define G_RM_CUSTOM_AA_ZB_XLU_SURF RM_CUSTOM_AA_ZB_XLU_SURF(1)
+#define G_RM_CUSTOM_AA_ZB_XLU_SURF2 RM_CUSTOM_AA_ZB_XLU_SURF(2)
+
+
+#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)
+
+/*
+ * G_SETCONVERT: K0-5
+ */
+#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
+
+/*
+ * G_SETSCISSOR: interlace mode
+ */
+#define G_SC_NON_INTERLACE 0
+#define G_SC_ODD_INTERLACE 3
+#define G_SC_EVEN_INTERLACE 2
+
+/* flags to inhibit pushing of the display list (on branch) */
+#define G_DL_PUSH 0x00
+#define G_DL_NOPUSH 0x01
+
+/*
+ * BEGIN C-specific section: (typedef's)
+ */
+#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
+
+/*
+ * Data Structures
+ *
+ * NOTE:
+ * The DMA transfer hardware requires 64-bit aligned, 64-bit multiple-
+ * sized transfers. This important hardware optimization is unfortunately
+ * reflected in the programming interface, with some structures
+ * padded and alignment enforced.
+ *
+ * Since structures are aligned to the boundary of the "worst-case"
+ * element, we can't depend on the C compiler to align things
+ * properly.
+ *
+ * 64-bit structure alignment is enforced by wrapping structures with
+ * unions that contain a dummy "long long int". Why this works is
+ * explained in the ANSI C Spec, or on page 186 of the second edition
+ * of K&R, "The C Programming Language".
+ *
+ * The price we pay for this is a little awkwardness referencing the
+ * structures through the union. There is no memory penalty, since
+ * all the structures are at least 64-bits the dummy alignment field
+ * does not increase the size of the union.
+ *
+ * Static initialization of these union structures works because
+ * the ANSI C spec states that static initialization for unions
+ * works by using the first union element. We put the dummy alignment
+ * field last for this reason.
+ *
+ * (it's possible a newer 64-bit compiler from MIPS might make this
+ * easier with a flag, but we can't wait for it...)
+ *
+ */
+
+/*
+ * Vertex (set up for use with colors)
+ */
+typedef struct {
+#ifndef GBI_FLOATS
+ short ob[3]; /* x, y, z */
+#else
+ float ob[3]; /* x, y, z */
+#endif
+ unsigned short flag;
+ short tc[2]; /* texture coord */
+ unsigned char cn[4]; /* color & alpha */
+} Vtx_t;
+
+/*
+ * Vertex (set up for use with normals)
+ */
+typedef struct {
+#ifndef GBI_FLOATS
+ short ob[3]; /* x, y, z */
+#else
+ float ob[3]; /* x, y, z */
+#endif
+ unsigned short flag;
+ short tc[2]; /* texture coord */
+ signed char n[3]; /* normal */
+ unsigned char a; /* alpha */
+} Vtx_tn;
+
+typedef union {
+ Vtx_t v; /* Use this one for colors */
+ Vtx_tn n; /* Use this one for normals */
+ long long int force_structure_alignment;
+} Vtx;
+
+/*
+ * Sprite structure
+ */
+
+typedef struct {
+ void *SourceImagePointer;
+ void *TlutPointer;
+ short Stride;
+ short SubImageWidth;
+ short SubImageHeight;
+ char SourceImageType;
+ char SourceImageBitSize;
+ short SourceImageOffsetS;
+ short SourceImageOffsetT;
+ /* 20 bytes for above */
+
+ /* padding to bring structure size to 64 bit allignment */
+ char dummy[4];
+
+} uSprite_t;
+
+typedef union {
+ uSprite_t s;
+
+ /* Need to make sure this is 64 bit aligned */
+ long long int force_structure_allignment[3];
+} uSprite;
+
+/*
+ * Triangle face
+ */
+typedef struct {
+ unsigned char flag;
+ unsigned char v[3];
+} Tri;
+
+#ifndef GBI_FLOATS
+/*
+ * 4x4 matrix, fixed point s15.16 format.
+ * First 8 words are integer portion of the 4x4 matrix
+ * Last 8 words are the fraction portion of the 4x4 matrix
+ */
+typedef int32_t Mtx_t[4][4];
+
+typedef union {
+ Mtx_t m;
+ long long int force_structure_alignment;
+} Mtx;
+#else
+typedef struct {
+ float m[4][4];
+} Mtx;
+#endif
+
+/*
+ * Viewport
+ */
+
+/*
+ *
+ * This magic value is the maximum INTEGER z-range of the hardware
+ * (there are also 16-bits of fraction, which are introduced during
+ * any transformations). This is not just a good idea, it's the law.
+ * Feeding the hardware eventual z-coordinates (after any transforms
+ * or scaling) bigger than this, will not work.
+ *
+ * This number is DIFFERENT than G_MAXFBZ, which is the maximum value
+ * you want to use to initialize the z-buffer.
+ *
+ * The reason these are different is mildly interesting, but too long
+ * to explain here. It is basically the result of optimizations in the
+ * hardware. A more generic API might hide this detail from the users,
+ * but we don't have the ucode to do that...
+ *
+ */
+#define G_MAXZ 0x03ff /* 10 bits of integer screen-Z precision */
+
+/*
+ * The viewport structure elements have 2 bits of fraction, necessary
+ * to accomodate the sub-pixel positioning scaling for the hardware.
+ * This can also be exploited to handle odd-sized viewports.
+ *
+ * Accounting for these fractional bits, using the default projection
+ * and viewing matrices, the viewport structure is initialized thusly:
+ *
+ * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, G_MAXZ, 0,
+ * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, 0, 0,
+ */
+typedef struct {
+ short vscale[4]; /* scale, 2 bits fraction */
+ short vtrans[4]; /* translate, 2 bits fraction */
+ /* both the above arrays are padded to 64-bit boundary */
+} Vp_t;
+
+typedef union {
+ Vp_t vp;
+ long long int force_structure_alignment;
+} Vp;
+
+/*
+ * MOVEMEM indices
+ *
+ * Each of these indexes an entry in a dmem table
+ * which points to a 1-4 word block of dmem in
+ * which to store a 1-4 word DMA.
+ *
+ */
+#ifdef F3DEX_GBI_2
+/* 0,4 are reserved by G_MTX */
+# 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 /* NOTE: this is in moveword table */
+# define G_MVO_LOOKATX (0*24)
+# define G_MVO_LOOKATY (1*24)
+# define G_MVO_L0 (2*24)
+# define G_MVO_L1 (3*24)
+# define G_MVO_L2 (4*24)
+# define G_MVO_L3 (5*24)
+# define G_MVO_L4 (6*24)
+# define G_MVO_L5 (7*24)
+# define G_MVO_L6 (8*24)
+# define G_MVO_L7 (9*24)
+#else /* F3DEX_GBI_2 */
+# define G_MV_VIEWPORT 0x80
+# define G_MV_LOOKATY 0x82
+# define G_MV_LOOKATX 0x84
+# define G_MV_L0 0x86
+# define G_MV_L1 0x88
+# define G_MV_L2 0x8a
+# define G_MV_L3 0x8c
+# define G_MV_L4 0x8e
+# define G_MV_L5 0x90
+# define G_MV_L6 0x92
+# define G_MV_L7 0x94
+# define G_MV_TXTATT 0x96
+# define G_MV_MATRIX_1 0x9e /* NOTE: this is in moveword table */
+# define G_MV_MATRIX_2 0x98
+# define G_MV_MATRIX_3 0x9a
+# define G_MV_MATRIX_4 0x9c
+#endif /* F3DEX_GBI_2 */
+
+/*
+ * MOVEWORD indices
+ *
+ * Each of these indexes an entry in a dmem table
+ * which points to a word in dmem in dmem where
+ * an immediate word will be stored.
+ *
+ */
+#define G_MW_MATRIX 0x00 /* NOTE: also used by movemem */
+#define G_MW_NUMLIGHT 0x02
+#define G_MW_CLIP 0x04
+#define G_MW_SEGMENT 0x06
+#define G_MW_FOG 0x08
+#define G_MW_LIGHTCOL 0x0a
+#ifdef F3DEX_GBI_2
+# define G_MW_FORCEMTX 0x0c
+#else /* F3DEX_GBI_2 */
+# define G_MW_POINTS 0x0c
+#endif /* F3DEX_GBI_2 */
+#define G_MW_PERSPNORM 0x0e
+
+/*
+ * These are offsets from the address in the dmem table
+ */
+#define G_MWO_NUMLIGHT 0x00
+#define G_MWO_CLIP_RNX 0x04
+#define G_MWO_CLIP_RNY 0x0c
+#define G_MWO_CLIP_RPX 0x14
+#define G_MWO_CLIP_RPY 0x1c
+#define G_MWO_SEGMENT_0 0x00
+#define G_MWO_SEGMENT_1 0x01
+#define G_MWO_SEGMENT_2 0x02
+#define G_MWO_SEGMENT_3 0x03
+#define G_MWO_SEGMENT_4 0x04
+#define G_MWO_SEGMENT_5 0x05
+#define G_MWO_SEGMENT_6 0x06
+#define G_MWO_SEGMENT_7 0x07
+#define G_MWO_SEGMENT_8 0x08
+#define G_MWO_SEGMENT_9 0x09
+#define G_MWO_SEGMENT_A 0x0a
+#define G_MWO_SEGMENT_B 0x0b
+#define G_MWO_SEGMENT_C 0x0c
+#define G_MWO_SEGMENT_D 0x0d
+#define G_MWO_SEGMENT_E 0x0e
+#define G_MWO_SEGMENT_F 0x0f
+#define G_MWO_FOG 0x00
+#define G_MWO_aLIGHT_1 0x00
+#define G_MWO_bLIGHT_1 0x04
+#ifdef F3DEX_GBI_2
+#define G_MWO_aLIGHT_2 0x18
+#define G_MWO_bLIGHT_2 0x1c
+#define G_MWO_aLIGHT_3 0x30
+#define G_MWO_bLIGHT_3 0x34
+#define G_MWO_aLIGHT_4 0x48
+#define G_MWO_bLIGHT_4 0x4c
+#define G_MWO_aLIGHT_5 0x60
+#define G_MWO_bLIGHT_5 0x64
+#define G_MWO_aLIGHT_6 0x78
+#define G_MWO_bLIGHT_6 0x7c
+#define G_MWO_aLIGHT_7 0x90
+#define G_MWO_bLIGHT_7 0x94
+#define G_MWO_aLIGHT_8 0xa8
+#define G_MWO_bLIGHT_8 0xac
+#else
+#define G_MWO_aLIGHT_2 0x20
+#define G_MWO_bLIGHT_2 0x24
+#define G_MWO_aLIGHT_3 0x40
+#define G_MWO_bLIGHT_3 0x44
+#define G_MWO_aLIGHT_4 0x60
+#define G_MWO_bLIGHT_4 0x64
+#define G_MWO_aLIGHT_5 0x80
+#define G_MWO_bLIGHT_5 0x84
+#define G_MWO_aLIGHT_6 0xa0
+#define G_MWO_bLIGHT_6 0xa4
+#define G_MWO_aLIGHT_7 0xc0
+#define G_MWO_bLIGHT_7 0xc4
+#define G_MWO_aLIGHT_8 0xe0
+#define G_MWO_bLIGHT_8 0xe4
+#endif
+#define G_MWO_MATRIX_XX_XY_I 0x00
+#define G_MWO_MATRIX_XZ_XW_I 0x04
+#define G_MWO_MATRIX_YX_YY_I 0x08
+#define G_MWO_MATRIX_YZ_YW_I 0x0c
+#define G_MWO_MATRIX_ZX_ZY_I 0x10
+#define G_MWO_MATRIX_ZZ_ZW_I 0x14
+#define G_MWO_MATRIX_WX_WY_I 0x18
+#define G_MWO_MATRIX_WZ_WW_I 0x1c
+#define G_MWO_MATRIX_XX_XY_F 0x20
+#define G_MWO_MATRIX_XZ_XW_F 0x24
+#define G_MWO_MATRIX_YX_YY_F 0x28
+#define G_MWO_MATRIX_YZ_YW_F 0x2c
+#define G_MWO_MATRIX_ZX_ZY_F 0x30
+#define G_MWO_MATRIX_ZZ_ZW_F 0x34
+#define G_MWO_MATRIX_WX_WY_F 0x38
+#define G_MWO_MATRIX_WZ_WW_F 0x3c
+#define G_MWO_POINT_RGBA 0x10
+#define G_MWO_POINT_ST 0x14
+#define G_MWO_POINT_XYSCREEN 0x18
+#define G_MWO_POINT_ZSCREEN 0x1c
+
+/*
+ * Light structure.
+ *
+ * Note: only directional (infinite) lights are currently supported.
+ *
+ * Note: the weird order is for the DMEM alignment benefit of
+ * the microcode.
+ *
+ */
+
+typedef struct {
+ unsigned char col[3]; /* diffuse light value (rgba) */
+ char pad1;
+ unsigned char colc[3]; /* copy of diffuse light value (rgba) */
+ char pad2;
+ signed char dir[3]; /* direction of light (normalized) */
+ char pad3;
+} Light_t;
+
+typedef struct {
+ unsigned char col[3]; /* ambient light value (rgba) */
+ char pad1;
+ unsigned char colc[3]; /* copy of ambient light value (rgba) */
+ char pad2;
+} Ambient_t;
+
+typedef struct {
+ int x1,y1,x2,y2; /* texture offsets for highlight 1/2 */
+} Hilite_t;
+
+typedef union {
+ Light_t l;
+ long long int force_structure_alignment[2];
+} Light;
+
+typedef union {
+ Ambient_t l;
+ long long int force_structure_alignment[1];
+} Ambient;
+
+typedef struct {
+ Ambient a;
+ Light l[7];
+} Lightsn;
+
+typedef struct {
+ Ambient a;
+ Light l[1];
+} Lights0;
+
+typedef struct {
+ Ambient a;
+ Light l[1];
+} 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];
+} Lights7;
+
+typedef struct {
+ Light l[2];
+} LookAt;
+
+typedef union {
+ Hilite_t h;
+ long int force_structure_alignment[4];
+} Hilite;
+
+#define gdSPDefLights0(ar,ag,ab) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ { 0, 0, 0},0,{ 0, 0, 0},0,{ 0, 0, 0},0}}} }
+#define gdSPDefLights1(ar,ag,ab,r1,g1,b1,x1,y1,z1) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}} }
+#define gdSPDefLights2(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \
+ {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}} }
+#define gdSPDefLights3(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \
+ {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \
+ {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}} }
+#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) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \
+ {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \
+ {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \
+ {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}} }
+#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) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \
+ {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \
+ {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \
+ {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}, \
+ {{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}}} }
+
+
+#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) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \
+ {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \
+ {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \
+ {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}, \
+ {{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}}, \
+ {{ {r6,g6,b6},0,{r6,g6,b6},0,{x6,y6,z6},0}}} }
+
+
+#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) \
+ { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \
+ {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \
+ {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \
+ {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \
+ {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}, \
+ {{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}}, \
+ {{ {r6,g6,b6},0,{r6,g6,b6},0,{x6,y6,z6},0}}, \
+ {{ {r7,g7,b7},0,{r7,g7,b7},0,{x7,y7,z7},0}}} }
+
+
+#define gdSPDefLookAt(rightx,righty,rightz,upx,upy,upz) \
+ { {{ {{0,0,0},0,{0,0,0},0,{rightx,righty,rightz},0}}, \
+ { {{0,0x80,0},0,{0,0x80,0},0,{upx,upy,upz},0}}} }
+
+/* Don't declare these for F3D_OLD to avoid bss reordering */
+#ifndef F3D_OLD
+/*
+ * Graphics DMA Packet
+ */
+typedef struct {
+ int cmd:8;
+ unsigned int par:8;
+ unsigned int len:16;
+ uintptr_t addr;
+} Gdma;
+
+/*
+ * Graphics Immediate Mode Packet types
+ */
+typedef struct {
+ int cmd:8;
+ int pad:24;
+ Tri tri;
+} Gtri;
+
+typedef struct {
+ int cmd:8;
+ int pad1:24;
+ int pad2:24;
+ unsigned char param:8;
+} Gpopmtx;
+
+/*
+ * typedef struct {
+ * int cmd:8;
+ * int pad0:24;
+ * int pad1:4;
+ * int number:4;
+ * int base:24;
+ * } Gsegment;
+ */
+typedef struct {
+ int cmd:8;
+ int pad0:8;
+ int mw_index:8;
+ int number:8;
+ int pad1:8;
+ int base:24;
+} Gsegment;
+
+typedef struct {
+ int cmd:8;
+ int pad0:8;
+ int sft:8;
+ int len:8;
+ unsigned int data:32;
+} GsetothermodeL;
+
+typedef struct {
+ int cmd:8;
+ int pad0:8;
+ int sft:8;
+ int len:8;
+ unsigned int data:32;
+} GsetothermodeH;
+
+typedef struct {
+ unsigned char cmd;
+ unsigned char lodscale;
+ unsigned char tile;
+ unsigned char on;
+ unsigned short s;
+ unsigned short t;
+} Gtexture;
+
+typedef struct {
+ int cmd:8;
+ int pad:24;
+ Tri line;
+} Gline3D;
+
+typedef struct {
+ int cmd:8;
+ int pad1:24;
+ short int pad2;
+ short int scale;
+} Gperspnorm;
+
+
+/*
+ * RDP Packet types
+ */
+typedef struct {
+ int cmd:8;
+ unsigned int fmt:3;
+ unsigned int siz:2;
+ unsigned int pad:7;
+ unsigned int wd:12; /* really only 10 bits, extra */
+ uintptr_t dram; /* to account for 1024 */
+} Gsetimg;
+
+typedef struct {
+ int cmd:8;
+ unsigned int muxs0:24;
+ unsigned int muxs1:32;
+} Gsetcombine;
+
+typedef struct {
+ int cmd:8;
+ unsigned char pad;
+ unsigned char prim_min_level;
+ unsigned char prim_level;
+ unsigned long color;
+} Gsetcolor;
+
+typedef struct {
+ int cmd:8;
+ int x0:10;
+ int x0frac:2;
+ int y0:10;
+ int y0frac:2;
+ unsigned int pad:8;
+ int x1:10;
+ int x1frac:2;
+ int y1:10;
+ int y1frac:2;
+} Gfillrect;
+
+typedef struct {
+ int cmd:8;
+ unsigned int fmt:3;
+ unsigned int siz:2;
+ unsigned int pad0:1;
+ unsigned int line:9;
+ unsigned int tmem:9;
+ unsigned int pad1:5;
+ unsigned int tile:3;
+ unsigned int palette:4;
+ unsigned int ct:1;
+ unsigned int mt:1;
+ unsigned int maskt:4;
+ unsigned int shiftt:4;
+ unsigned int cs:1;
+ unsigned int ms:1;
+ unsigned int masks:4;
+ unsigned int shifts:4;
+} Gsettile;
+
+typedef struct {
+ int cmd:8;
+ unsigned int sl:12;
+ unsigned int tl:12;
+ int pad:5;
+ unsigned int tile:3;
+ unsigned int sh:12;
+ unsigned int th:12;
+} Gloadtile;
+
+typedef Gloadtile Gloadblock;
+
+typedef Gloadtile Gsettilesize;
+
+typedef Gloadtile Gloadtlut;
+
+typedef struct {
+ unsigned int cmd:8; /* command */
+ unsigned int xl:12; /* X coordinate of upper left */
+ unsigned int yl:12; /* Y coordinate of upper left */
+ unsigned int pad1:5; /* Padding */
+ unsigned int tile:3; /* Tile descriptor index */
+ unsigned int xh:12; /* X coordinate of lower right */
+ unsigned int yh:12; /* Y coordinate of lower right */
+ unsigned int s:16; /* S texture coord at top left */
+ unsigned int t:16; /* T texture coord at top left */
+ unsigned int dsdx:16;/* Change in S per change in X */
+ unsigned int dtdy:16;/* Change in T per change in Y */
+} Gtexrect;
+
+/*
+ * Textured rectangles are 128 bits not 64 bits
+ */
+typedef struct {
+ unsigned long w0;
+ unsigned long w1;
+ unsigned long w2;
+ unsigned long w3;
+} TexRect;
+#endif
+
+#define MakeTexRect(xh,yh,flip,tile,xl,yl,s,t,dsdx,dtdy) \
+ G_TEXRECT, xh, yh, 0, flip, 0, tile, xl, yl, s, t, dsdx, dtdy
+
+/*
+ * Generic Gfx Packet
+ */
+typedef struct {
+ uint32_t w0;
+ uint32_t w1;
+} Gwords;
+
+/*
+ * This union is the fundamental type of the display list.
+ * It is, by law, exactly 64 bits in size.
+ *
+ * (Edit: except on 64-bit, where it is exactly 128 bit. On little-endian or
+ * 64-bit systems, only the 'words' member may be accessed; the rest of the
+ * structs don't have matching layouts for now.)
+ */
+typedef union {
+ Gwords words;
+#if !defined(F3D_OLD) && IS_BIG_ENDIAN && !IS_64_BIT
+ Gdma dma;
+ Gtri tri;
+ Gline3D line;
+ Gpopmtx popmtx;
+ Gsegment segment;
+ GsetothermodeH setothermodeH;
+ GsetothermodeL setothermodeL;
+ Gtexture texture;
+ Gperspnorm perspnorm;
+ Gsetimg setimg;
+ Gsetcombine setcombine;
+ Gsetcolor setcolor;
+ Gfillrect fillrect; /* use for setscissor also */
+ Gsettile settile;
+ Gloadtile loadtile; /* use for loadblock also, th is dxt */
+ Gsettilesize settilesize;
+ Gloadtlut loadtlut;
+#endif
+ long long int force_structure_alignment;
+} Gfx;
+
+/*
+ * Macros to assemble the graphics display list
+ */
+
+/*
+ * DMA macros
+ */
+#define gDma0p(pkt, c, s, l) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \
+ _g->words.w1 = (uintptr_t)(s); \
+}
+
+#define gsDma0p(c, s, l) \
+{{ \
+ _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (uintptr_t)(s) \
+}}
+
+#define gDma1p(pkt, c, s, l, p) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
+ _SHIFTL((l), 0, 16)); \
+ _g->words.w1 = (uintptr_t)(s); \
+}
+
+#define gsDma1p(c, s, l, p) \
+{{ \
+ (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
+ _SHIFTL((l), 0, 16)), \
+ (uintptr_t)(s) \
+}}
+
+#define gDma2p(pkt, c, adrs, len, idx, ofs) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
+ _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)); \
+ _g->words.w1 = (uintptr_t)(adrs); \
+}
+#define gsDma2p(c, adrs, len, idx, ofs) \
+{{ \
+ (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
+ _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)), \
+ (uintptr_t)(adrs) \
+}}
+
+#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0)
+#define gsSPNoOp() gsDma0p(G_SPNOOP, 0, 0)
+
+#ifdef F3DEX_GBI_2
+# define gSPMatrix(pkt, m, p) \
+ gDma2p((pkt),G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0)
+# define gsSPMatrix(m, p) \
+ gsDma2p( G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0)
+#else /* F3DEX_GBI_2 */
+# define gSPMatrix(pkt, m, p) gDma1p(pkt, G_MTX, m, sizeof(Mtx), p)
+# define gsSPMatrix(m, p) gsDma1p(G_MTX, m, sizeof(Mtx), p)
+#endif /* F3DEX_GBI_2 */
+
+#if defined(F3DEX_GBI_2)
+/*
+ * F3DEX_GBI_2: G_VTX GBI format was changed.
+ *
+ * +--------+----+---+---+----+------+-+
+ * G_VTX | cmd:8 |0000| n:8 |0000|v0+n:7|0|
+ * +-+---+--+----+---+---+----+------+-+
+ * | |seg| address |
+ * +-+---+-----------------------------+
+ */
+# define gSPVertex(pkt, v, n, v0) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = \
+ _SHIFTL(G_VTX,24,8)|_SHIFTL((n),12,8)|_SHIFTL((v0)+(n),1,7); \
+ _g->words.w1 = (uintptr_t)(v); \
+}
+# define gsSPVertex(v, n, v0) \
+{{ \
+ (_SHIFTL(G_VTX,24,8)|_SHIFTL((n),12,8)|_SHIFTL((v0)+(n),1,7)), \
+ (uintptr_t)(v) \
+}}
+#elif (defined(F3DEX_GBI)||defined(F3DLP_GBI))
+/*
+ * F3DEX_GBI: G_VTX GBI format was changed to support 64 vertice.
+ *
+ * +--------+--------+------+----------+
+ * G_VTX | cmd:8 | v0:8 | n:6 |length:10 |
+ * +-+---+--+--------+------+----------+
+ * | |seg| address |
+ * +-+---+-----------------------------+
+ */
+# define gSPVertex(pkt, v, n, v0) \
+ gDma1p((pkt),G_VTX,(v),((n)<<10)|(sizeof(Vtx)*(n)-1),(v0)*2)
+# define gsSPVertex(v, n, v0) \
+ gsDma1p(G_VTX,(v),((n)<<10)|(sizeof(Vtx)*(n)-1),(v0)*2)
+#else
+# define gSPVertex(pkt, v, n, v0) \
+ gDma1p(pkt, G_VTX, v, sizeof(Vtx)*(n),((n)-1)<<4|(v0))
+# define gsSPVertex(v, n, v0) \
+ gsDma1p(G_VTX, v, sizeof(Vtx)*(n), ((n)-1)<<4|(v0))
+#endif
+
+
+#ifdef F3DEX_GBI_2
+# define gSPViewport(pkt, v) \
+ gDma2p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0)
+# define gsSPViewport(v) \
+ gsDma2p( G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0)
+#else /* F3DEX_GBI_2 */
+# define gSPViewport(pkt,v) \
+ gDma1p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT)
+# define gsSPViewport(v) \
+ gsDma1p( G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT)
+#endif /* F3DEX_GBI_2 */
+
+#define gSPDisplayList(pkt,dl) gDma1p(pkt,G_DL,dl,0,G_DL_PUSH)
+#define gsSPDisplayList( dl) gsDma1p( G_DL,dl,0,G_DL_PUSH)
+
+#define gSPBranchList(pkt,dl) gDma1p(pkt,G_DL,dl,0,G_DL_NOPUSH)
+#define gsSPBranchList( dl) gsDma1p( G_DL,dl,0,G_DL_NOPUSH)
+
+#define gSPSprite2DBase(pkt, s) gDma1p(pkt, G_SPRITE2D_BASE, s, sizeof(uSprite), 0)
+#define gsSPSprite2DBase(s) gsDma1p(G_SPRITE2D_BASE, s, sizeof(uSprite), 0)
+
+/*
+ * RSP short command (no DMA required) macros
+ */
+#define gImmp0(pkt, c) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL((c), 24, 8); \
+}
+
+#define gsImmp0(c) \
+{{ \
+ _SHIFTL((c), 24, 8) \
+}}
+
+#define gImmp1(pkt, c, p0) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL((c), 24, 8); \
+ _g->words.w1 = (uintptr_t)(p0); \
+}
+
+#define gsImmp1(c, p0) \
+{{ \
+ _SHIFTL((c), 24, 8), (uintptr_t)(p0) \
+}}
+
+#define gImmp2(pkt, c, p0, p1) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL((c), 24, 8); \
+ _g->words.w1 = _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8); \
+}
+
+#define gsImmp2(c, p0, p1) \
+{{ \
+ _SHIFTL((c), 24, 8), _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8)\
+}}
+
+#define gImmp3(pkt, c, p0, p1, p2) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL((c), 24, 8); \
+ _g->words.w1 = (_SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) | \
+ _SHIFTL((p2), 0, 8)); \
+}
+
+#define gsImmp3(c, p0, p1, p2) \
+{{ \
+ _SHIFTL((c), 24, 8), (_SHIFTL((p0), 16, 16) | \
+ _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8))\
+}}
+
+#define gImmp21(pkt, c, p0, p1, dat) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | \
+ _SHIFTL((p1), 0, 8)); \
+ _g->words.w1 = (uintptr_t) (dat); \
+}
+
+#define gsImmp21(c, p0, p1, dat) \
+{{ \
+ _SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8),\
+ (uintptr_t) (dat) \
+}}
+
+#ifdef F3DEX_GBI_2
+#define gMoveWd(pkt, index, offset, data) \
+ gDma1p((pkt), G_MOVEWORD, data, offset, index)
+#define gsMoveWd( index, offset, data) \
+ gsDma1p( G_MOVEWORD, data, offset, index)
+#else /* F3DEX_GBI_2 */
+#define gMoveWd(pkt, index, offset, data) \
+ gImmp21((pkt), G_MOVEWORD, offset, index, data)
+#define gsMoveWd( index, offset, data) \
+ gsImmp21( G_MOVEWORD, offset, index, data)
+#endif /* F3DEX_GBI_2 */
+
+/* Sprite immediate macros, there is also a sprite dma macro above */
+
+#define gSPSprite2DScaleFlip(pkt, sx, sy, fx, fy) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) | \
+ _SHIFTL((fx), 8, 8) | \
+ _SHIFTL((fy), 0, 8)); \
+ _g->words.w1 = (_SHIFTL((sx), 16, 16) | \
+ _SHIFTL((sy), 0, 16)); \
+}
+
+#define gsSPSprite2DScaleFlip(sx, sy, fx, fy) \
+{{ \
+ (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) | \
+ _SHIFTL((fx), 8, 8) | \
+ _SHIFTL((fy), 0, 8)), \
+ (_SHIFTL((sx), 16, 16) | \
+ _SHIFTL((sy), 0, 16)) \
+}}
+
+#define gSPSprite2DDraw(pkt, px, py) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)); \
+ _g->words.w1 = (_SHIFTL((px), 16, 16) | \
+ _SHIFTL((py), 0, 16)); \
+}
+
+#define gsSPSprite2DDraw(px, py) \
+{{ \
+ (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)), \
+ (_SHIFTL((px), 16, 16) | \
+ _SHIFTL((py), 0, 16)) \
+}}
+
+
+/*
+ * Note: the SP1Triangle() and line macros multiply the vertex indices
+ * by 10, this is an optimization for the microcode.
+ */
+#if (defined(F3DLP_GBI)||defined(F3DEX_GBI))
+# define __gsSP1Triangle_w1(v0, v1, v2) \
+ (_SHIFTL((v0)*2,16,8)|_SHIFTL((v1)*2,8,8)|_SHIFTL((v2)*2,0,8))
+# define __gsSP1Triangle_w1f(v0, v1, v2, flag) \
+ (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2): \
+ ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v0): \
+ __gsSP1Triangle_w1(v2, v0, v1))
+# define __gsSPLine3D_w1(v0, v1, wd) \
+ (_SHIFTL((v0)*2,16,8)|_SHIFT((v1)*2,8,8)|_SHIFT((wd),0,8))
+# define __gsSPLine3D_w1f(v0, v1, wd, flag) \
+ (((flag) == 0) ? __gsSPLine3D_w1(v0, v1, wd): \
+ __gsSPLine3D_w1(v1, v0, wd))
+# define __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag) \
+ (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2): \
+ ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v3): \
+ ((flag) == 2) ? __gsSP1Triangle_w1(v2, v3, v0): \
+ __gsSP1Triangle_w1(v3, v0, v1))
+# define __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \
+ (((flag) == 0) ? __gsSP1Triangle_w1(v0, v2, v3): \
+ ((flag) == 1) ? __gsSP1Triangle_w1(v1, v3, v0): \
+ ((flag) == 2) ? __gsSP1Triangle_w1(v2, v0, v1): \
+ __gsSP1Triangle_w1(v3, v1, v2))
+#else
+# define __gsSP1Triangle_w1f(v0, v1, v2, flag) \
+ (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| \
+ _SHIFTL((v1)*10, 8,8)|_SHIFTL((v2)*10, 0,8))
+# define __gsSPLine3D_w1f(v0, v1, wd, flag) \
+ (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| \
+ _SHIFTL((v1)*10, 8,8)|_SHIFTL((wd), 0,8))
+#endif
+
+#ifdef F3DEX_GBI_2
+/***
+ *** 1 Triangle
+ ***/
+#define gSP1Triangle(pkt, v0, v1, v2, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_TRI1, 24, 8)| \
+ __gsSP1Triangle_w1f(v0, v1, v2, flag); \
+ _g->words.w1 = 0; \
+}
+#define gsSP1Triangle(v0, v1, v2, flag) \
+{{ \
+ _SHIFTL(G_TRI1, 24, 8)|__gsSP1Triangle_w1f(v0, v1, v2, flag), \
+ 0 \
+}}
+
+/***
+ *** Line
+ ***/
+#define gSPLine3D(pkt, v0, v1, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8)| \
+ __gsSPLine3D_w1f(v0, v1, 0, flag); \
+ _g->words.w1 = 0; \
+}
+#define gsSPLine3D(v0, v1, flag) \
+{{ \
+ _SHIFTL(G_LINE3D, 24, 8)|__gsSPLine3D_w1f(v0, v1, 0, flag), \
+ 0 \
+}}
+
+/***
+ *** LineW
+ ***/
+/* these macros are the same as SPLine3D, except they have an
+ * additional parameter for width. The width is added to the "minimum"
+ * thickness, which is 1.5 pixels. The units for width are in
+ * half-pixel units, so a width of 1 translates to (.5 + 1.5) or
+ * a 2.0 pixels wide line.
+ */
+#define gSPLineW3D(pkt, v0, v1, wd, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8)| \
+ __gsSPLine3D_w1f(v0, v1, wd, flag); \
+ _g->words.w1 = 0; \
+}
+#define gsSPLineW3D(v0, v1, wd, flag) \
+{{ \
+ _SHIFTL(G_LINE3D, 24, 8)|__gsSPLine3D_w1f(v0, v1, wd, flag), \
+ 0 \
+}}
+
+/***
+ *** 1 Quadrangle
+ ***/
+#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_QUAD, 24, 8)| \
+ __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)); \
+ _g->words.w1 = __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag); \
+}
+
+#define gsSP1Quadrangle(v0, v1, v2, v3, flag) \
+{{ \
+ (_SHIFTL(G_QUAD, 24, 8)| \
+ __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \
+ __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \
+}}
+#else /* F3DEX_GBI_2 */
+
+/***
+ *** 1 Triangle
+ ***/
+#define gSP1Triangle(pkt, v0, v1, v2, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_TRI1, 24, 8); \
+ _g->words.w1 = __gsSP1Triangle_w1f(v0, v1, v2, flag); \
+}
+#define gsSP1Triangle(v0, v1, v2, flag) \
+{{ \
+ _SHIFTL(G_TRI1, 24, 8), \
+ __gsSP1Triangle_w1f(v0, v1, v2, flag) \
+}}
+
+/***
+ *** Line
+ ***/
+#define gSPLine3D(pkt, v0, v1, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8); \
+ _g->words.w1 = __gsSPLine3D_w1f(v0, v1, 0, flag); \
+}
+#define gsSPLine3D(v0, v1, flag) \
+{{ \
+ _SHIFTL(G_LINE3D, 24, 8), \
+ __gsSPLine3D_w1f(v0, v1, 0, flag) \
+}}
+
+/***
+ *** LineW
+ ***/
+/* these macros are the same as SPLine3D, except they have an
+ * additional parameter for width. The width is added to the "minimum"
+ * thickness, which is 1.5 pixels. The units for width are in
+ * half-pixel units, so a width of 1 translates to (.5 + 1.5) or
+ * a 2.0 pixels wide line.
+ */
+#define gSPLineW3D(pkt, v0, v1, wd, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8); \
+ _g->words.w1 = __gsSPLine3D_w1f(v0, v1, wd, flag); \
+}
+#define gsSPLineW3D(v0, v1, wd, flag) \
+{{ \
+ _SHIFTL(G_LINE3D, 24, 8), \
+ __gsSPLine3D_w1f(v0, v1, wd, flag) \
+}}
+
+/***
+ *** 1 Quadrangle
+ ***/
+#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8)| \
+ __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)); \
+ _g->words.w1 = __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag); \
+}
+
+#define gsSP1Quadrangle(v0, v1, v2, v3, flag) \
+{{ \
+ (_SHIFTL(G_TRI2, 24, 8)| \
+ __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \
+ __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \
+}}
+#endif /* F3DEX_GBI_2 */
+
+#if (defined(F3DLP_GBI)||defined(F3DEX_GBI))
+/***
+ *** 2 Triangles
+ ***/
+#define gSP2Triangles(pkt, v00, v01, v02, flag0, v10, v11, v12, flag1) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8)| \
+ __gsSP1Triangle_w1f(v00, v01, v02, flag0)); \
+ _g->words.w1 = __gsSP1Triangle_w1f(v10, v11, v12, flag1); \
+}
+
+#define gsSP2Triangles(v00, v01, v02, flag0, v10, v11, v12, flag1) \
+{{ \
+ (_SHIFTL(G_TRI2, 24, 8)| \
+ __gsSP1Triangle_w1f(v00, v01, v02, flag0)), \
+ __gsSP1Triangle_w1f(v10, v11, v12, flag1) \
+}}
+#else
+#define gSP2Triangles(pkt, v00, v01, v02, flag0, v10, v11, v12, flag1) \
+{ \
+ gSP1Triangle(pkt, v00, v01, v02, flag0); \
+ gSP1Triangle(pkt, v10, v11, v12, flag1); \
+}
+#define gsSP2Triangles(v00, v01, v02, flag0, v10, v11, v12, flag1) \
+ gsSP1Triangle(v00, v01, v02, flag0), \
+ gsSP1Triangle(v10, v11, v12, flag1)
+#endif /* F3DEX_GBI/F3DLP_GBI */
+
+#if (defined(F3DEX_GBI)||defined(F3DLP_GBI))
+#define gSPCullDisplayList(pkt,vstart,vend) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \
+ _SHIFTL((vstart)*2, 0, 16); \
+ _g->words.w1 = _SHIFTL((vend)*2, 0, 16); \
+}
+
+#define gsSPCullDisplayList(vstart,vend) \
+{{ \
+ _SHIFTL(G_CULLDL, 24, 8) | _SHIFTL((vstart)*2, 0, 16), \
+ _SHIFTL((vend)*2, 0, 16) \
+}}
+
+#else
+#define gSPCullDisplayList(pkt,vstart,vend) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \
+ ((0x0f & (vstart))*40); \
+ _g->words.w1 = (unsigned int)((0x0f & ((vend)+1))*40); \
+}
+
+#define gsSPCullDisplayList(vstart,vend) \
+{{ \
+ _SHIFTL(G_CULLDL, 24, 8) | ((0x0f & (vstart))*40), \
+ ((0x0f & ((vend)+1))*40) \
+}}
+#endif
+
+#define gSPSegment(pkt, segment, base) \
+ gMoveWd(pkt, G_MW_SEGMENT, (segment)*4, base)
+#define gsSPSegment(segment, base) \
+ gsMoveWd( G_MW_SEGMENT, (segment)*4, base)
+
+/*
+ * Clipping Macros
+ */
+#define FR_NEG_FRUSTRATIO_1 0x00000001
+#define FR_POS_FRUSTRATIO_1 0x0000ffff
+#define FR_NEG_FRUSTRATIO_2 0x00000002
+#define FR_POS_FRUSTRATIO_2 0x0000fffe
+#define FR_NEG_FRUSTRATIO_3 0x00000003
+#define FR_POS_FRUSTRATIO_3 0x0000fffd
+#define FR_NEG_FRUSTRATIO_4 0x00000004
+#define FR_POS_FRUSTRATIO_4 0x0000fffc
+#define FR_NEG_FRUSTRATIO_5 0x00000005
+#define FR_POS_FRUSTRATIO_5 0x0000fffb
+#define FR_NEG_FRUSTRATIO_6 0x00000006
+#define FR_POS_FRUSTRATIO_6 0x0000fffa
+/*
+ * r should be one of: FRUSTRATIO_1, FRUSTRATIO_2, FRUSTRATIO_3, ... FRUSTRATIO_6
+ */
+#define gSPClipRatio(pkt, r) \
+{ \
+ gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r); \
+ gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r); \
+ gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r); \
+ gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r); \
+}
+
+#define gsSPClipRatio(r) \
+ gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r), \
+ gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r), \
+ gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r), \
+ gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r)
+
+/*
+ * Insert values into Matrix
+ *
+ * where = element of matrix (byte offset)
+ * num = new element (32 bit value replacing 2 int or 2 frac matrix
+ * componants
+ */
+#ifdef F3DEX_GBI_2
+#define gSPInsertMatrix(pkt, where, num) \
+ ERROR!! gSPInsertMatrix is no longer supported.
+#define gsSPInsertMatrix(where, num) \
+ ERROR!! gsSPInsertMatrix is no longer supported.
+#else
+#define gSPInsertMatrix(pkt, where, num) \
+ gMoveWd(pkt, G_MW_MATRIX, where, num)
+#define gsSPInsertMatrix(where, num) \
+ gsMoveWd(G_MW_MATRIX, where, num)
+#endif
+
+/*
+ * Load new matrix directly
+ *
+ * mptr = pointer to matrix
+ */
+#ifdef F3DEX_GBI_2
+#define gSPForceMatrix(pkt, mptr) \
+{ gDma2p((pkt),G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0); \
+ gMoveWd((pkt), G_MW_FORCEMTX,0,0x00010000); \
+}
+#define gsSPForceMatrix(mptr) \
+ gsDma2p(G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0), \
+ gsMoveWd(G_MW_FORCEMTX,0,0x00010000)
+
+#else /* F3DEX_GBI_2 */
+#define gSPForceMatrix(pkt, mptr) \
+{ \
+ gDma1p(pkt, G_MOVEMEM, mptr, 16, G_MV_MATRIX_1); \
+ gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2); \
+ gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3); \
+ gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4); \
+}
+#define gsSPForceMatrix(mptr) \
+ gsDma1p( G_MOVEMEM, mptr, 16, G_MV_MATRIX_1), \
+ gsDma1p( G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2), \
+ gsDma1p( G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3), \
+ gsDma1p( G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4)
+#endif /* F3DEX_GBI_2 */
+
+/*
+ * Insert values into Points
+ *
+ * point = point number 0-15
+ * where = which element of point to modify (byte offset into point)
+ * num = new value (32 bit)
+ */
+#if (defined(F3DEX_GBI)||defined(F3DLP_GBI))
+# define gSPModifyVertex(pkt, vtx, where, val) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = (_SHIFTL(G_MODIFYVTX,24,8)| \
+ _SHIFTL((where),16,8)|_SHIFTL((vtx)*2,0,16)); \
+ _g->words.w1 = (unsigned int)(val); \
+}
+# define gsSPModifyVertex(vtx, where, val) \
+{{ \
+ _SHIFTL(G_MODIFYVTX,24,8)| \
+ _SHIFTL((where),16,8)|_SHIFTL((vtx)*2,0,16), \
+ (unsigned int)(val) \
+}}
+#else
+# define gSPModifyVertex(pkt, vtx, where, val) \
+ gMoveWd(pkt, G_MW_POINTS, (vtx)*40+(where), val)
+# define gsSPModifyVertex(vtx, where, val) \
+ gsMoveWd(G_MW_POINTS, (vtx)*40+(where), val)
+#endif
+
+#if (defined(F3DEX_GBI)||defined(F3DLP_GBI))
+/*
+ * gSPBranchLessZ Branch DL if (vtx.z) less than or equal (zval).
+ *
+ * dl = DL branch to
+ * vtx = Vertex
+ * zval = Screen depth
+ * near = Near plane
+ * far = Far plane
+ * flag = G_BZ_PERSP or G_BZ_ORTHO
+ */
+
+#define G_BZ_PERSP 0
+#define G_BZ_ORTHO 1
+
+#define G_DEPTOZSrg(zval, near, far, flag, zmin, zmax) \
+(((unsigned int)FTOFIX32(((flag) == G_BZ_PERSP ? \
+ (1.0f-(float)(near)/(float)(zval)) / \
+ (1.0f-(float)(near)/(float)(far )) : \
+ ((float)(zval) - (float)(near)) / \
+ ((float)(far ) - (float)(near))))) * \
+ (((int)((zmax) - (zmin)))&~1) + (int)FTOFIX32(zmin))
+
+#define G_DEPTOZS(zval, near, far, flag) \
+ G_DEPTOZSrg(zval, near, far, flag, 0, G_MAXZ)
+
+#define gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, zmin, zmax) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8); \
+ _g->words.w1 = (uintptr_t)(dl); \
+ _g = (Gfx *)(pkt); \
+ _g->words.w0 = (_SHIFTL(G_BRANCH_Z,24,8)| \
+ _SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12)); \
+ _g->words.w1 = G_DEPTOZSrg(zval, near, far, flag, zmin, zmax); \
+}
+
+#define gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, zmin, zmax) \
+{{ _SHIFTL(G_RDPHALF_1,24,8), \
+ (uintptr_t)(dl), }}, \
+{{ _SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\
+ G_DEPTOZSrg(zval, near, far, flag, zmin, zmax), }}
+
+#define gSPBranchLessZ(pkt, dl, vtx, zval, near, far, flag) \
+ gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, 0, G_MAXZ)
+#define gsSPBranchLessZ(dl, vtx, zval, near, far, flag) \
+ gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, 0, G_MAXZ)
+
+/*
+ * gSPBranchLessZraw Branch DL if (vtx.z) less than or equal (raw zval).
+ *
+ * dl = DL branch to
+ * vtx = Vertex
+ * zval = Raw value of screen depth
+ */
+#define gSPBranchLessZraw(pkt, dl, vtx, zval) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8); \
+ _g->words.w1 = (uintptr_t)(dl); \
+ _g = (Gfx *)(pkt); \
+ _g->words.w0 = (_SHIFTL(G_BRANCH_Z,24,8)| \
+ _SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12)); \
+ _g->words.w1 = (unsigned int)(zval); \
+}
+
+#define gsSPBranchLessZraw(dl, vtx, zval) \
+{{ _SHIFTL(G_RDPHALF_1,24,8), \
+ (uintptr_t)(dl), }}, \
+{{ _SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\
+ (unsigned int)(zval), }}
+
+/*
+ * gSPLoadUcode RSP loads specified ucode.
+ *
+ * uc_start = ucode text section start
+ * uc_dstart = ucode data section start
+ */
+#define gSPLoadUcodeEx(pkt, uc_start, uc_dstart, uc_dsize) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8); \
+ _g->words.w1 = (uintptr_t)(uc_dstart); \
+ _g = (Gfx *)(pkt); \
+ _g->words.w0 = (_SHIFTL(G_LOAD_UCODE,24,8)| \
+ _SHIFTL((int)(uc_dsize)-1,0,16)); \
+ _g->words.w1 = (uintptr_t)(uc_start); \
+}
+
+#define gsSPLoadUcodeEx(uc_start, uc_dstart, uc_dsize) \
+{{ _SHIFTL(G_RDPHALF_1,24,8), \
+ (uintptr_t)(uc_dstart), }}, \
+{{ _SHIFTL(G_LOAD_UCODE,24,8)| \
+ _SHIFTL((int)(uc_dsize)-1,0,16), \
+ (uintptr_t)(uc_start), }}
+
+#define gSPLoadUcode(pkt, uc_start, uc_dstart) \
+ gSPLoadUcodeEx((pkt), (uc_start), (uc_dstart), SP_UCODE_DATA_SIZE)
+#define gsSPLoadUcode(uc_start, uc_dstart) \
+ gsSPLoadUcodeEx((uc_start), (uc_dstart), SP_UCODE_DATA_SIZE)
+
+#define gSPLoadUcodeL(pkt, ucode) \
+ gSPLoadUcode((pkt), OS_K0_TO_PHYSICAL(&##ucode##TextStart), \
+ OS_K0_TO_PHYSICAL(&##ucode##DataStart))
+#define gsSPLoadUcodeL(ucode) \
+ gsSPLoadUcode(OS_K0_TO_PHYSICAL(&##ucode##TextStart), \
+ OS_K0_TO_PHYSICAL(&##ucode##DataStart))
+#endif
+
+#ifdef F3DEX_GBI_2
+/*
+ * gSPDma_io DMA to/from DMEM/IMEM for DEBUG.
+ */
+#define gSPDma_io(pkt, flag, dmem, dram, size) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = _SHIFTL(G_DMA_IO,24,8)|_SHIFTL((flag),23,1)| \
+ _SHIFTL((dmem)/8,13,10)|_SHIFTL((size)-1,0,12); \
+ _g->words.w1 = (uintptr_t)(dram); \
+}
+
+#define gsSPDma_io(flag, dmem, dram, size) \
+{{ \
+ _SHIFTL(G_DMA_IO,24,8)|_SHIFTL((flag),23,1)| \
+ _SHIFTL((dmem)/8,13,10)|_SHIFTL((size)-1,0,12), \
+ (uintptr_t)(dram) \
+}}
+
+#define gSPDmaRead(pkt,dmem,dram,size) gSPDma_io((pkt),0,(dmem),(dram),(size))
+#define gsSPDmaRead(dmem,dram,size) gsSPDma_io(0,(dmem),(dram),(size))
+#define gSPDmaWrite(pkt,dmem,dram,size) gSPDma_io((pkt),1,(dmem),(dram),(size))
+#define gsSPDmaWrite(dmem,dram,size) gsSPDma_io(1,(dmem),(dram),(size))
+#endif
+
+/*
+ * Lighting Macros
+ */
+#ifdef F3DEX_GBI_2
+# define NUML(n) ((n)*24)
+#else
+# define NUML(n) (((n)+1)*32 + 0x80000000)
+#endif
+#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
+/*
+ * n should be one of: NUMLIGHTS_0, NUMLIGHTS_1, ..., NUMLIGHTS_7
+ * NOTE: in addition to the number of directional lights specified,
+ * there is always 1 ambient light
+ */
+#define gSPNumLights(pkt, n) \
+ gMoveWd(pkt, G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))
+#define gsSPNumLights(n) \
+ gsMoveWd( G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))
+
+#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
+/*
+ * l should point to a Light struct
+ * n should be one of: LIGHT_1, LIGHT_2, ..., LIGHT_8
+ * NOTE: the highest numbered light is always the ambient light (eg if there are
+ * 3 directional lights defined: gsSPNumLights(NUMLIGHTS_3), then lights
+ * LIGHT_1 through LIGHT_3 will be the directional lights and light
+ * LIGHT_4 will be the ambient light.
+ */
+#ifdef F3DEX_GBI_2
+# define gSPLight(pkt, l, n) \
+ gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,(n)*24+24)
+# define gsSPLight(l, n) \
+ gsDma2p( G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,(n)*24+24)
+#else /* F3DEX_GBI_2 */
+# define gSPLight(pkt, l, n) \
+ gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0)
+# define gsSPLight(l, n) \
+ gsDma1p( G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0)
+#endif /* F3DEX_GBI_2 */
+
+/*
+ * gSPLightColor changes color of light without recalculating light direction
+ * col is a 32 bit word with r,g,b,a (alpha is ignored)
+ * n should be one of LIGHT_1, LIGHT_2, ..., LIGHT_8
+ */
+#define gSPLightColor(pkt, n, col) \
+{ \
+ gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_a##n, col); \
+ gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_b##n, col); \
+}
+#define gsSPLightColor(n, col) \
+ gsMoveWd(G_MW_LIGHTCOL, G_MWO_a##n, col), \
+ gsMoveWd(G_MW_LIGHTCOL, G_MWO_b##n, col)
+
+/* These macros use a structure "name" which is init'd with the gdSPDefLights macros*/
+
+#define gSPSetLights0(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_0); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.a,2); \
+}
+#define gsSPSetLights0(name) \
+ gsSPNumLights(NUMLIGHTS_0), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.a,2)
+
+#define gSPSetLights1(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_1); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.a,2); \
+}
+#define gsSPSetLights1(name) \
+ gsSPNumLights(NUMLIGHTS_1), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.a,2)
+
+#define gSPSetLights2(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_2); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.l[1],2); \
+ gSPLight(pkt,&name.a,3); \
+}
+#define gsSPSetLights2(name) \
+ gsSPNumLights(NUMLIGHTS_2), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.l[1],2), \
+ gsSPLight(&name.a,3)
+
+#define gSPSetLights3(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_3); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.l[1],2); \
+ gSPLight(pkt,&name.l[2],3); \
+ gSPLight(pkt,&name.a,4); \
+}
+#define gsSPSetLights3(name) \
+ gsSPNumLights(NUMLIGHTS_3), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.l[1],2), \
+ gsSPLight(&name.l[2],3), \
+ gsSPLight(&name.a,4)
+
+#define gSPSetLights4(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_4); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.l[1],2); \
+ gSPLight(pkt,&name.l[2],3); \
+ gSPLight(pkt,&name.l[3],4); \
+ gSPLight(pkt,&name.a,5); \
+}
+#define gsSPSetLights4(name) \
+ gsSPNumLights(NUMLIGHTS_4), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.l[1],2), \
+ gsSPLight(&name.l[2],3), \
+ gsSPLight(&name.l[3],4), \
+ gsSPLight(&name.a,5)
+
+#define gSPSetLights5(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_5); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.l[1],2); \
+ gSPLight(pkt,&name.l[2],3); \
+ gSPLight(pkt,&name.l[3],4); \
+ gSPLight(pkt,&name.l[4],5); \
+ gSPLight(pkt,&name.a,6); \
+}
+
+#define gsSPSetLights5(name) \
+ gsSPNumLights(NUMLIGHTS_5), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.l[1],2), \
+ gsSPLight(&name.l[2],3), \
+ gsSPLight(&name.l[3],4), \
+ gsSPLight(&name.l[4],5), \
+ gsSPLight(&name.a,6)
+
+#define gSPSetLights6(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_6); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.l[1],2); \
+ gSPLight(pkt,&name.l[2],3); \
+ gSPLight(pkt,&name.l[3],4); \
+ gSPLight(pkt,&name.l[4],5); \
+ gSPLight(pkt,&name.l[5],6); \
+ gSPLight(pkt,&name.a,7); \
+}
+
+#define gsSPSetLights6(name) \
+ gsSPNumLights(NUMLIGHTS_6), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.l[1],2), \
+ gsSPLight(&name.l[2],3), \
+ gsSPLight(&name.l[3],4), \
+ gsSPLight(&name.l[4],5), \
+ gsSPLight(&name.l[5],6), \
+ gsSPLight(&name.a,7)
+
+#define gSPSetLights7(pkt,name) \
+{ \
+ gSPNumLights(pkt,NUMLIGHTS_7); \
+ gSPLight(pkt,&name.l[0],1); \
+ gSPLight(pkt,&name.l[1],2); \
+ gSPLight(pkt,&name.l[2],3); \
+ gSPLight(pkt,&name.l[3],4); \
+ gSPLight(pkt,&name.l[4],5); \
+ gSPLight(pkt,&name.l[5],6); \
+ gSPLight(pkt,&name.l[6],7); \
+ gSPLight(pkt,&name.a,8); \
+}
+
+#define gsSPSetLights7(name) \
+ gsSPNumLights(NUMLIGHTS_7), \
+ gsSPLight(&name.l[0],1), \
+ gsSPLight(&name.l[1],2), \
+ gsSPLight(&name.l[2],3), \
+ gsSPLight(&name.l[3],4), \
+ gsSPLight(&name.l[4],5), \
+ gsSPLight(&name.l[5],6), \
+ gsSPLight(&name.l[6],7), \
+ gsSPLight(&name.a,8)
+
+/*
+ * Reflection/Hiliting Macros
+ */
+#ifdef F3DEX_GBI_2
+# define gSPLookAtX(pkt, l) \
+ gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATX)
+# define gsSPLookAtX(l) \
+ gsDma2p( G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATX)
+# define gSPLookAtY(pkt, l) \
+ gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATY)
+# define gsSPLookAtY(l) \
+ gsDma2p( G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATY)
+#else /* F3DEX_GBI_2 */
+# define gSPLookAtX(pkt, l) \
+ gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX)
+# define gsSPLookAtX(l) \
+ gsDma1p( G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX)
+# define gSPLookAtY(pkt, l) \
+ gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY)
+# define gsSPLookAtY(l) \
+ gsDma1p( G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY)
+#endif /* F3DEX_GBI_2 */
+
+#define gSPLookAt(pkt, la) \
+{ \
+ gSPLookAtX(pkt,la) \
+ gSPLookAtY(pkt,(char *)(la)+16) \
+}
+#define gsSPLookAt(la) \
+ gsSPLookAtX(la), \
+ gsSPLookAtY((char *)(la)+16)
+
+#define gDPSetHilite1Tile(pkt, tile, hilite, width, height) \
+ gDPSetTileSize(pkt, tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff, \
+ ((((width)-1)*4)+(hilite)->h.x1) & 0xfff, ((((height)-1)*4)+(hilite)->h.y1) & 0xfff)
+
+#define gDPSetHilite2Tile(pkt, tile, hilite, width, height) \
+ gDPSetTileSize(pkt, tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff, \
+ ((((width)-1)*4)+(hilite)->h.x2) & 0xfff, ((((height)-1)*4)+(hilite)->h.y2) & 0xfff)
+
+
+/*
+ * FOG macros
+ * fm = z multiplier
+ * fo = z offset
+ * FOG FORMULA: alpha(fog) = (eyespace z) * fm + fo CLAMPED 0 to 255
+ * note: (eyespace z) ranges -1 to 1
+ *
+ * Alternate method of setting fog:
+ * min, max: range 0 to 1000: 0=nearplane, 1000=farplane
+ * min is where fog begins (usually less than max and often 0)
+ * max is where fog is thickest (usually 1000)
+ *
+ */
+#define gSPFogFactor(pkt, fm, fo) \
+ gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \
+ (_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16)))
+
+#define gsSPFogFactor(fm, fo) \
+ gsMoveWd(G_MW_FOG, G_MWO_FOG, \
+ (_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16)))
+
+#define gSPFogPosition(pkt, min, max) \
+ gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \
+ (_SHIFTL((128000/((max)-(min))),16,16) | \
+ _SHIFTL(((500-(min))*256/((max)-(min))),0,16)))
+
+#define gsSPFogPosition(min, max) \
+ gsMoveWd(G_MW_FOG, G_MWO_FOG, \
+ (_SHIFTL((128000/((max)-(min))),16,16) | \
+ _SHIFTL(((500-(min))*256/((max)-(min))),0,16)))
+
+#ifdef F3DEX_GBI_2
+/*
+ * Macros to turn texture on/off
+ */
+# define gSPTexture(pkt, s, t, level, tile, on) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8) | \
+ _SHIFTL(BOWTIE_VAL,16,8) | \
+ _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | \
+ _SHIFTL((on),1,7)); \
+ _g->words.w1 = (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)); \
+}
+# define gsSPTexture(s, t, level, tile, on) \
+{{ \
+ (_SHIFTL(G_TEXTURE,24,8) | _SHIFTL(BOWTIE_VAL,16,8) | \
+ _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\
+ (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)) \
+}}
+/*
+ * Different version of SPTexture macro, has an additional parameter
+ * which is currently reserved in the microcode.
+ */
+# define gSPTextureL(pkt, s, t, level, xparam, tile, on) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8) | \
+ _SHIFTL((xparam),16,8) | \
+ _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | \
+ _SHIFTL((on),1,7)); \
+ _g->words.w1 = (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)); \
+}
+# define gsSPTextureL(s, t, level, xparam, tile, on) \
+{{ \
+ (_SHIFTL(G_TEXTURE,24,8) | _SHIFTL((xparam),16,8) | \
+ _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\
+ (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)) \
+}}
+#else
+/*
+ * Macros to turn texture on/off
+ */
+# define gSPTexture(pkt, s, t, level, tile, on) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL(BOWTIE_VAL,16,8)|\
+ _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)| \
+ _SHIFTL((on),0,8)); \
+ _g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)); \
+}
+# define gsSPTexture(s, t, level, tile, on) \
+{{ \
+ (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL(BOWTIE_VAL,16,8)| \
+ _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \
+ (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)) \
+}}
+/*
+ * Different version of SPTexture macro, has an additional parameter
+ * which is currently reserved in the microcode.
+ */
+# define gSPTextureL(pkt, s, t, level, xparam, tile, on) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)| \
+ _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)| \
+ _SHIFTL((on),0,8)); \
+ _g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)); \
+}
+# define gsSPTextureL(s, t, level, xparam, tile, on) \
+{{ \
+ (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)| \
+ _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \
+ (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)) \
+}}
+#endif
+
+#ifndef F3D_OLD
+# define gSPPerspNormalize(pkt, s) gMoveWd(pkt, G_MW_PERSPNORM, 0, (s))
+# define gsSPPerspNormalize(s) gsMoveWd( G_MW_PERSPNORM, 0, (s))
+#else
+# define gSPPerspNormalize(pkt, s) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_RDPHALF_1, 24, 8); \
+ _g->words.w1 = (s); \
+}
+# define gsSPPerspNormalize(s) \
+{{ \
+ _SHIFTL(G_RDPHALF_1, 24, 8), \
+ (s) \
+}}
+#endif
+
+#ifdef F3DEX_GBI_2
+# define gSPPopMatrixN(pkt, n, num) gDma2p((pkt),G_POPMTX,(num)*64,64,2,0)
+# define gsSPPopMatrixN(n, num) gsDma2p( G_POPMTX,(num)*64,64,2,0)
+# define gSPPopMatrix(pkt, n) gSPPopMatrixN((pkt), (n), 1)
+# define gsSPPopMatrix(n) gsSPPopMatrixN( (n), 1)
+#else /* F3DEX_GBI_2 */
+# define gSPPopMatrix(pkt, n) gImmp1(pkt, G_POPMTX, n)
+# define gsSPPopMatrix(n) gsImmp1( G_POPMTX, n)
+#endif /* F3DEX_GBI_2 */
+
+#define gSPEndDisplayList(pkt) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_ENDDL, 24, 8); \
+ _g->words.w1 = 0; \
+}
+
+#define gsSPEndDisplayList() \
+{{ \
+ _SHIFTL(G_ENDDL, 24, 8), 0 \
+}}
+
+#ifdef F3DEX_GBI_2
+/*
+ * One gSPGeometryMode(pkt,c,s) GBI is equal to these two GBIs.
+ *
+ * gSPClearGeometryMode(pkt,c)
+ * gSPSetGeometryMode(pkt,s)
+ *
+ * gSPLoadGeometryMode(pkt, word) sets GeometryMode directly.
+ */
+#define gSPGeometryMode(pkt, c, s) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = _SHIFTL(G_GEOMETRYMODE,24,8)|_SHIFTL(~(u32)(c),0,24);\
+ _g->words.w1 = (u32)(s); \
+}
+
+#define gsSPGeometryMode(c, s) \
+{{ \
+ (_SHIFTL(G_GEOMETRYMODE,24,8)|_SHIFTL(~(u32)(c),0,24)),(u32)(s) \
+}}
+#define gSPSetGeometryMode(pkt, word) gSPGeometryMode((pkt),0,(word))
+#define gsSPSetGeometryMode(word) gsSPGeometryMode(0,(word))
+#define gSPClearGeometryMode(pkt, word) gSPGeometryMode((pkt),(word),0)
+#define gsSPClearGeometryMode(word) gsSPGeometryMode((word),0)
+#define gSPLoadGeometryMode(pkt, word) gSPGeometryMode((pkt),-1,(word))
+#define gsSPLoadGeometryMode(word) gsSPGeometryMode(-1,(word))
+#define gsSPGeometryModeSetFirst(c, s) gsSPGeometryMode(c, s)
+#else /* F3DEX_GBI_2 */
+#define gSPSetGeometryMode(pkt, word) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \
+ _g->words.w1 = (unsigned int)(word); \
+}
+
+#define gsSPSetGeometryMode(word) \
+{{ \
+ _SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word) \
+}}
+
+#define gSPClearGeometryMode(pkt, word) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \
+ _g->words.w1 = (unsigned int)(word); \
+}
+
+#define gsSPClearGeometryMode(word) \
+{{ \
+ _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (unsigned int)(word) \
+}}
+
+/*
+ * gsSPGeometryMode
+ * In Fast3DEX2 it is better to use this, as the RSP geometry mode
+ * is able to be set and cleared in a single command.
+ */
+#define gsSPGeometryMode(c, s) \
+ gsSPClearGeometryMode(c), \
+ gsSPSetGeometryMode(s)
+#define gsSPGeometryModeSetFirst(c, s) \
+ gsSPSetGeometryMode(s), \
+ gsSPClearGeometryMode(c)
+#endif /* F3DEX_GBI_2 */
+
+#ifdef F3DEX_GBI_2
+#define gSPSetOtherMode(pkt, cmd, sft, len, data) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ _g->words.w0 = (_SHIFTL(cmd,24,8)|_SHIFTL(32-(sft)-(len),8,8)| \
+ _SHIFTL((len)-1,0,8)); \
+ _g->words.w1 = (unsigned int)(data); \
+}
+
+#define gsSPSetOtherMode(cmd, sft, len, data) \
+{{ \
+ _SHIFTL(cmd,24,8)|_SHIFTL(32-(sft)-(len),8,8)|_SHIFTL((len)-1,0,8), \
+ (unsigned int)(data) \
+}}
+#else
+#define gSPSetOtherMode(pkt, cmd, sft, len, data) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \
+ _SHIFTL(len, 0, 8)); \
+ _g->words.w1 = (unsigned int)(data); \
+}
+
+#define gsSPSetOtherMode(cmd, sft, len, data) \
+{{ \
+ _SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \
+ (unsigned int)(data) \
+}}
+#endif
+
+/*
+ * RDP setothermode register commands - register shadowed in RSP
+ */
+#define gDPPipelineMode(pkt, mode) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)
+#define gsDPPipelineMode(mode) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)
+
+#define gDPSetCycleType(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type)
+#define gsDPSetCycleType(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type)
+
+#define gDPSetTexturePersp(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type)
+#define gsDPSetTexturePersp(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type)
+
+#define gDPSetTextureDetail(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type)
+#define gsDPSetTextureDetail(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type)
+
+#define gDPSetTextureLOD(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type)
+#define gsDPSetTextureLOD(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type)
+
+#define gDPSetTextureLUT(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type)
+#define gsDPSetTextureLUT(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type)
+
+#define gDPSetTextureFilter(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type)
+#define gsDPSetTextureFilter(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type)
+
+#define gDPSetTextureConvert(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type)
+#define gsDPSetTextureConvert(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type)
+
+#define gDPSetCombineKey(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type)
+#define gsDPSetCombineKey(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type)
+
+#ifndef _HW_VERSION_1
+#define gDPSetColorDither(pkt, mode) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode)
+#define gsDPSetColorDither(mode) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode)
+#else
+#define gDPSetColorDither(pkt, mode) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode)
+#define gsDPSetColorDither(mode) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode)
+#endif
+
+#ifndef _HW_VERSION_1
+#define gDPSetAlphaDither(pkt, mode) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode)
+#define gsDPSetAlphaDither(mode) \
+ gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode)
+#endif
+
+/* 'blendmask' is not supported anymore.
+ * The bits are reserved for future use.
+ * Fri May 26 13:45:55 PDT 1995
+ */
+#define gDPSetBlendMask(pkt, mask) gDPNoOp(pkt)
+#define gsDPSetBlendMask(mask) gsDPNoOp()
+
+#define gDPSetAlphaCompare(pkt, type) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type)
+#define gsDPSetAlphaCompare(type) \
+ gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type)
+
+#define gDPSetDepthSource(pkt, src) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src)
+#define gsDPSetDepthSource(src) \
+ gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src)
+
+#define gDPSetRenderMode(pkt, c0, c1) \
+ gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, \
+ (c0) | (c1))
+#define gsDPSetRenderMode(c0, c1) \
+ gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, \
+ (c0) | (c1))
+
+#define gSetImage(pkt, cmd, fmt, siz, width, i) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
+ _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12); \
+ _g->words.w1 = (uintptr_t)(i); \
+}
+
+#define gsSetImage(cmd, fmt, siz, width, i) \
+{{ \
+ _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
+ _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), \
+ (uintptr_t)(i) \
+}}
+
+#define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i)
+#define gsDPSetColorImage(f, s, w, i) gsSetImage(G_SETCIMG, f, s, w, i)
+
+
+/* use these for new code */
+#define gDPSetDepthImage(pkt, i) gSetImage(pkt, G_SETZIMG, 0, 0, 1, i)
+#define gsDPSetDepthImage(i) gsSetImage(G_SETZIMG, 0, 0, 1, i)
+/* kept for compatibility */
+#define gDPSetMaskImage(pkt, i) gDPSetDepthImage(pkt, i)
+#define gsDPSetMaskImage(i) gsDPSetDepthImage(i)
+
+#define gDPSetTextureImage(pkt, f, s, w, i) gSetImage(pkt, G_SETTIMG, f, s, w, i)
+#define gsDPSetTextureImage(f, s, w, i) gsSetImage(G_SETTIMG, f, s, w, i)
+
+/*
+ * RDP macros
+ */
+
+#define gDPSetCombine(pkt, muxs0, muxs1) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24);\
+ _g->words.w1 = (unsigned int)(muxs1); \
+}
+
+#define gsDPSetCombine(muxs0, muxs1) \
+{{ \
+ _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \
+ (unsigned int)(muxs1) \
+}}
+
+#define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \
+ (_SHIFTL((saRGB0), 20, 4) | _SHIFTL((mRGB0), 15, 5) | \
+ _SHIFTL((saA0), 12, 3) | _SHIFTL((mA0), 9, 3))
+
+#define GCCc1w0(saRGB1, mRGB1) \
+ (_SHIFTL((saRGB1), 5, 4) | _SHIFTL((mRGB1), 0, 5))
+
+#define GCCc0w1(sbRGB0, aRGB0, sbA0, aA0) \
+ (_SHIFTL((sbRGB0), 28, 4) | _SHIFTL((aRGB0), 15, 3) | \
+ _SHIFTL((sbA0), 12, 3) | _SHIFTL((aA0), 9, 3))
+
+#define GCCc1w1(sbRGB1, saA1, mA1, aRGB1, sbA1, aA1) \
+ (_SHIFTL((sbRGB1), 24, 4) | _SHIFTL((saA1), 21, 3) | \
+ _SHIFTL((mA1), 18, 3) | _SHIFTL((aRGB1), 6, 3) | \
+ _SHIFTL((sbA1), 3, 3) | _SHIFTL((aA1), 0, 3))
+
+#define gDPSetCombineLERP(pkt, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \
+ a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | \
+ _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0, \
+ G_ACMUX_##Aa0, G_ACMUX_##Ac0) | \
+ GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), \
+ 0, 24); \
+ _g->words.w1 = (unsigned int)(GCCc0w1(G_CCMUX_##b0, \
+ G_CCMUX_##d0, \
+ G_ACMUX_##Ab0, \
+ G_ACMUX_##Ad0) | \
+ GCCc1w1(G_CCMUX_##b1, \
+ G_ACMUX_##Aa1, \
+ G_ACMUX_##Ac1, \
+ G_CCMUX_##d1, \
+ G_ACMUX_##Ab1, \
+ G_ACMUX_##Ad1)); \
+}
+
+#define gsDPSetCombineLERP(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \
+ a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \
+{{ \
+ _SHIFTL(G_SETCOMBINE, 24, 8) | \
+ _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0, \
+ G_ACMUX_##Aa0, G_ACMUX_##Ac0) | \
+ GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), 0, 24), \
+ (unsigned int)(GCCc0w1(G_CCMUX_##b0, G_CCMUX_##d0, \
+ G_ACMUX_##Ab0, G_ACMUX_##Ad0) | \
+ GCCc1w1(G_CCMUX_##b1, G_ACMUX_##Aa1, \
+ G_ACMUX_##Ac1, G_CCMUX_##d1, \
+ G_ACMUX_##Ab1, G_ACMUX_##Ad1)) \
+}}
+
+/*
+ * SetCombineMode macros are NOT redunant. It allow the C preprocessor
+ * to substitute single parameter which includes commas in the token and
+ * rescan for higher parameter count macro substitution.
+ *
+ * eg. gsDPSetCombineMode(G_CC_MODULATE, G_CC_MODULATE) turns into
+ * gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0,
+ * TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0)
+ */
+
+#define gDPSetCombineMode(pkt, a, b) gDPSetCombineLERP(pkt, a, b)
+#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b)
+
+#define gDPSetColor(pkt, c, d) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(c, 24, 8); \
+ _g->words.w1 = (unsigned int)(d); \
+}
+
+#define gsDPSetColor(c, d) \
+{{ \
+ _SHIFTL(c, 24, 8), (unsigned int)(d) \
+}}
+
+#define DPRGBColor(pkt, cmd, r, g, b, a) \
+ gDPSetColor(pkt, cmd, \
+ (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \
+ _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)))
+#define sDPRGBColor(cmd, r, g, b, a) \
+ gsDPSetColor(cmd, \
+ (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \
+ _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)))
+
+#define gDPSetEnvColor(pkt, r, g, b, a) \
+ DPRGBColor(pkt, G_SETENVCOLOR, r,g,b,a)
+#define gsDPSetEnvColor(r, g, b, a) \
+ sDPRGBColor(G_SETENVCOLOR, r,g,b,a)
+#define gDPSetBlendColor(pkt, r, g, b, a) \
+ DPRGBColor(pkt, G_SETBLENDCOLOR, r,g,b,a)
+#define gsDPSetBlendColor(r, g, b, a) \
+ sDPRGBColor(G_SETBLENDCOLOR, r,g,b,a)
+#define gDPSetFogColor(pkt, r, g, b, a) \
+ DPRGBColor(pkt, G_SETFOGCOLOR, r,g,b,a)
+#define gsDPSetFogColor(r, g, b, a) \
+ sDPRGBColor(G_SETFOGCOLOR, r,g,b,a)
+#define gDPSetFillColor(pkt, d) \
+ gDPSetColor(pkt, G_SETFILLCOLOR, (d))
+#define gsDPSetFillColor(d) \
+ gsDPSetColor(G_SETFILLCOLOR, (d))
+
+#define gDPSetPrimDepth(pkt, z, dz) \
+ gDPSetColor(pkt, G_SETPRIMDEPTH, \
+ _SHIFTL(z, 16, 16) | _SHIFTL(dz, 0, 16))
+#define gsDPSetPrimDepth(z, dz) \
+ gsDPSetColor(G_SETPRIMDEPTH, _SHIFTL(z, 16, 16) | \
+ _SHIFTL(dz, 0, 16))
+
+#define gDPSetPrimColor(pkt, m, l, r, g, b, a) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_SETPRIMCOLOR, 24, 8) | \
+ _SHIFTL(m, 8, 8) | _SHIFTL(l, 0, 8)); \
+ _g->words.w1 = (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \
+ _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)); \
+}
+
+#define gsDPSetPrimColor(m, l, r, g, b, a) \
+{{ \
+ (_SHIFTL(G_SETPRIMCOLOR, 24, 8) | _SHIFTL(m, 8, 8) | \
+ _SHIFTL(l, 0, 8)), \
+ (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | \
+ _SHIFTL(a, 0, 8)) \
+}}
+
+/*
+ * gDPSetOtherMode (This is for expert user.)
+ *
+ * This command makes all othermode parameters set.
+ * Do not use this command in the same DL with another g*SPSetOtherMode DLs.
+ *
+ * [Usage]
+ * gDPSetOtherMode(pkt, modeA, modeB)
+ *
+ * 'modeA' is described all parameters of GroupA GBI command.
+ * 'modeB' is also described all parameters of GroupB GBI command.
+ *
+ * GroupA:
+ * gDPPipelineMode, gDPSetCycleType, gSPSetTexturePersp,
+ * gDPSetTextureDetail, gDPSetTextureLOD, gDPSetTextureLUT,
+ * gDPSetTextureFilter, gDPSetTextureConvert, gDPSetCombineKey,
+ * gDPSetColorDither, gDPSetAlphaDither
+ *
+ * GroupB:
+ * gDPSetAlphaCompare, gDPSetDepthSource, gDPSetRenderMode
+ *
+ * Use 'OR' operation to get modeA and modeB.
+ *
+ * modeA = G_PM_* | G_CYC_* | G_TP_* | G_TD_* | G_TL_* | G_TT_* | G_TF_*
+ * G_TC_* | G_CK_* | G_CD_* | G_AD_*;
+ *
+ * modeB = G_AC_* | G_ZS_* | G_RM_* | G_RM_*2;
+ */
+#define gDPSetOtherMode(pkt, mode0, mode1) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24);\
+ _g->words.w1 = (unsigned int)(mode1); \
+}
+
+#define gsDPSetOtherMode(mode0, mode1) \
+{{ \
+ _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24), \
+ (unsigned int)(mode1) \
+}}
+
+/*
+ * Texturing macros
+ */
+
+/* These are also defined defined above for Sprite Microcode */
+
+#define G_TX_LOADTILE 7
+#define G_TX_RENDERTILE 0
+
+#define G_TX_NOMIRROR 0
+#define G_TX_WRAP 0
+#define G_TX_MIRROR 0x1
+#define G_TX_CLAMP 0x2
+#define G_TX_NOMASK 0
+#define G_TX_NOLOD 0
+
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+/*
+ * Dxt is the inverse of the number of 64-bit words in a line of
+ * the texture being loaded using the load_block command. If
+ * there are any 1's to the right of the 11th fractional bit,
+ * dxt should be rounded up. The following macros accomplish
+ * this. The 4b macros are a special case since 4-bit textures
+ * are loaded as 8-bit textures. Dxt is fixed point 1.11. RJM
+ */
+#define G_TX_DXT_FRAC 11
+
+/*
+ * For RCP 2.0, the maximum number of texels that can be loaded
+ * using a load_block command is 2048. In order to load the total
+ * 4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b,
+ * then change the tile to the proper texel size after the load.
+ * The g*DPLoadTextureBlock macros already do this, so this change
+ * will be transparent if you use these macros. If you use
+ * the g*DPLoadBlock macros directly, you will need to handle this
+ * tile manipulation yourself. RJM.
+ */
+#ifdef _HW_VERSION_1
+#define G_TX_LDBLK_MAX_TXL 4095
+#else
+#define G_TX_LDBLK_MAX_TXL 2047
+#endif /* _HW_VERSION_1 */
+
+#define TXL2WORDS(txls, b_txl) MAX(1, ((txls)*(b_txl)/8))
+#define CALC_DXT(width, b_txl) \
+ (((1 << G_TX_DXT_FRAC) + TXL2WORDS(width, b_txl) - 1) / \
+ TXL2WORDS(width, b_txl))
+
+#define TXL2WORDS_4b(txls) MAX(1, ((txls)/16))
+#define CALC_DXT_4b(width) \
+ (((1 << G_TX_DXT_FRAC) + TXL2WORDS_4b(width) - 1) / \
+ TXL2WORDS_4b(width))
+
+#define gDPLoadTileGeneric(pkt, c, tile, uls, ult, lrs, lrt) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | \
+ _SHIFTL(ult, 0, 12); \
+ _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | \
+ _SHIFTL(lrt, 0, 12); \
+}
+
+#define gsDPLoadTileGeneric(c, tile, uls, ult, lrs, lrt) \
+{{ \
+ _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12), \
+ _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | _SHIFTL(lrt, 0, 12)\
+}}
+
+#define gDPSetTileSize(pkt, t, uls, ult, lrs, lrt) \
+ gDPLoadTileGeneric(pkt, G_SETTILESIZE, t, uls, ult, lrs, lrt)
+#define gsDPSetTileSize(t, uls, ult, lrs, lrt) \
+ gsDPLoadTileGeneric(G_SETTILESIZE, t, uls, ult, lrs, lrt)
+#define gDPLoadTile(pkt, t, uls, ult, lrs, lrt) \
+ gDPLoadTileGeneric(pkt, G_LOADTILE, t, uls, ult, lrs, lrt)
+#define gsDPLoadTile(t, uls, ult, lrs, lrt) \
+ gsDPLoadTileGeneric(G_LOADTILE, t, uls, ult, lrs, lrt)
+
+#define gDPSetTile(pkt, fmt, siz, line, tmem, tile, palette, cmt, \
+ maskt, shiftt, cms, masks, shifts) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) |\
+ _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | \
+ _SHIFTL(tmem, 0, 9); \
+ _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) | \
+ _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) | \
+ _SHIFTL(shiftt, 10, 4) |_SHIFTL(cms, 8, 2) | \
+ _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4); \
+}
+
+#define gsDPSetTile(fmt, siz, line, tmem, tile, palette, cmt, \
+ maskt, shiftt, cms, masks, shifts) \
+{{ \
+ (_SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) | \
+ _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | _SHIFTL(tmem, 0, 9)),\
+ (_SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) | \
+ _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) | \
+ _SHIFTL(shiftt, 10, 4) | _SHIFTL(cms, 8, 2) | \
+ _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4)) \
+}}
+
+/*
+ * For RCP 2.0, the maximum number of texels that can be loaded
+ * using a load_block command is 2048. In order to load the total
+ * 4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b,
+ * then change the tile to the proper texel size after the load.
+ * The g*DPLoadTextureBlock macros already do this, so this change
+ * will be transparent if you use these macros. If you use
+ * the g*DPLoadBlock macros directly, you will need to handle this
+ * tile manipulation yourself. RJM.
+ */
+#define gDPLoadBlock(pkt, tile, uls, ult, lrs, dxt) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_LOADBLOCK, 24, 8) | \
+ _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(tile, 24, 3) | \
+ _SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) |\
+ _SHIFTL(dxt, 0, 12)); \
+}
+
+#define gsDPLoadBlock(tile, uls, ult, lrs, dxt) \
+{{ \
+ (_SHIFTL(G_LOADBLOCK, 24, 8) | _SHIFTL(uls, 12, 12) | \
+ _SHIFTL(ult, 0, 12)), \
+ (_SHIFTL(tile, 24, 3) | \
+ _SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) | \
+ _SHIFTL(dxt, 0, 12)) \
+}}
+
+#define gDPLoadTLUTCmd(pkt, tile, count) \
+{ \
+ Gfx *_g = (Gfx *)pkt; \
+ \
+ _g->words.w0 = _SHIFTL(G_LOADTLUT, 24, 8); \
+ _g->words.w1 = _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10);\
+}
+
+#define gsDPLoadTLUTCmd(tile, count) \
+{{ \
+ _SHIFTL(G_LOADTLUT, 24, 8), \
+ _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10) \
+}}
+
+#define gDPLoadTextureBlock(pkt, timg, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1, \
+ CALC_DXT(width, siz##_BYTES)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((width) * siz##_LINE_BYTES)+7)>>3, 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+#define gDPLoadTextureBlockYuv(pkt, timg, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1, \
+ CALC_DXT(width, siz##_BYTES)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((width) * 1)+7)>>3, 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/* Load fix rww 27jun95 */
+/* The S at the end means odd lines are already word Swapped */
+
+#define gDPLoadTextureBlockS(pkt, timg, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((width) * siz##_LINE_BYTES)+7)>>3, 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/*
+ * Allow tmem address and render tile to be specified.
+ * The S at the end means odd lines are already word Swapped
+ */
+#define gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, \
+ height, pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((width) * siz##_LINE_BYTES)+7)>>3, tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+
+#define gDPLoadTextureBlockYuvS(pkt, timg, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((width) * 1)+7)>>3, 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/*
+ * allows tmem address to be specified
+ */
+#define _gDPLoadTextureBlock(pkt, timg, tmem, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \
+ 0, cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \
+ CALC_DXT(width, siz##_BYTES)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3, \
+ tmem, G_TX_RENDERTILE, pal, cmt, \
+ maskt, shiftt, cms, masks, shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/*
+ * allows tmem address and render tile to be specified
+ */
+#define _gDPLoadTextureBlockTile(pkt, timg, tmem, rtile, fmt, siz, width, \
+ height, pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0,\
+ cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \
+ CALC_DXT(width, siz##_BYTES)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3, \
+ tmem, rtile, pal, cmt, \
+ maskt, shiftt, cms, masks, shifts); \
+ gDPSetTileSize(pkt, rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/*
+ * allows tmem address and render tile to be specified
+ */
+#define gDPLoadMultiBlock(pkt, timg, tmem, rtile, fmt, siz, width, \
+ height, pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
+ gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0,\
+ cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \
+ CALC_DXT(width, siz##_BYTES)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3, \
+ tmem, rtile, pal, cmt, \
+ maskt, shiftt, cms, masks, shifts); \
+ gDPSetTileSize(pkt, rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+#define gsDPLoadTextureBlock(timg, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
+ gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, \
+ G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, \
+ masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \
+ CALC_DXT(width, siz##_BYTES)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+/* Here is the static form of the pre-swapped texture block loading */
+/* See gDPLoadTextureBlockS() for reference. Basically, just don't
+ calculate DxT, use 0 */
+
+#define gsDPLoadTextureBlockS(timg, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
+ gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0 , \
+ cmt, maskt,shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),\
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+/*
+ * Allow tmem address to be specified
+ */
+#define _gsDPLoadTextureBlock(timg, tmem, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
+ gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \
+ CALC_DXT(width, siz##_BYTES)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, \
+ ((((width) * siz##_LINE_BYTES)+7)>>3), tmem, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+
+/*
+ * Allow tmem address and render_tile to be specified
+ */
+#define _gsDPLoadTextureBlockTile(timg, tmem, rtile, fmt, siz, width, \
+ height, pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
+ gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \
+ CALC_DXT(width, siz##_BYTES)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, \
+ ((((width) * siz##_LINE_BYTES)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+
+/*
+ * Allow tmem address and render_tile to be specified, useful when loading
+ * mutilple tiles at a time.
+ */
+#define gsDPLoadMultiBlock(timg, tmem, rtile, fmt, siz, width, \
+ height, pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
+ gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \
+ 0 , cmt, maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \
+ CALC_DXT(width, siz##_BYTES)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, \
+ ((((width) * siz##_LINE_BYTES)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+/*
+ * Allows tmem and render tile to be specified. Useful when loading
+ * several tiles at a time.
+ *
+ * Here is the static form of the pre-swapped texture block loading
+ * See gDPLoadTextureBlockS() for reference. Basically, just don't
+ * calculate DxT, use 0
+ */
+
+#define gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
+ gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0 , \
+ cmt, maskt,shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \
+ (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),\
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), tmem,\
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+
+#define gDPLoadTextureBlock_4b(pkt, timg, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, \
+ cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height)+3)>>2)-1, \
+ CALC_DXT_4b(width)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/* Load fix rww 27jun95 */
+/* The S at the end means odd lines are already word Swapped */
+
+#define gDPLoadTextureBlock_4bS(pkt, timg, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, \
+ cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height)+3)>>2)-1, 0 ); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/*
+ * 4-bit load block. Useful when loading multiple tiles
+ */
+#define gDPLoadMultiBlock_4b(pkt, timg, tmem, rtile, fmt, width, height,\
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, \
+ cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height)+3)>>2)-1, \
+ CALC_DXT_4b(width)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+/*
+ * 4-bit load block. Allows tmem and render tile to be specified. Useful when
+ * loading multiple tiles. The S means odd lines are already word swapped.
+ */
+#define gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height,\
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, \
+ cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height)+3)>>2)-1, 0 ); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+
+#define _gDPLoadTextureBlock_4b(pkt, timg, tmem, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, \
+ cmt, maskt, shiftt, cms, masks, shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \
+ (((width)*(height)+3)>>2)-1, \
+ CALC_DXT_4b(width)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC) \
+}
+
+#define gsDPLoadTextureBlock_4b(timg, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \
+ gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt, \
+ maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1, \
+ CALC_DXT_4b(width)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+#define gsDPLoadTextureBlock_4bS(timg, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \
+ gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt, \
+ maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0),\
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+/*
+ * 4-bit load block. Allows tmem address and render tile to be specified.
+ * Useful when loading multiple tiles.
+ */
+#define gsDPLoadMultiBlock_4b(timg, tmem, rtile, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \
+ gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt, \
+ maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1, \
+ CALC_DXT_4b(width)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+
+/*
+ * 4-bit load block. Allows tmem address and render tile to be specified.
+ * Useful when loading multiple tiles. S means odd lines are already swapped.
+ */
+#define gsDPLoadMultiBlock_4bS(timg, tmem, rtile, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \
+ gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt, \
+ maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0),\
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(rtile, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+
+/*
+ * Allows tmem address to be specified
+ */
+#define _gsDPLoadTextureBlock_4b(timg, tmem, fmt, width, height, \
+ pal, cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \
+ gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt, \
+ maskt, shiftt, cms, masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1, \
+ CALC_DXT_4b(width)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \
+ ((width)-1) << G_TEXTURE_IMAGE_FRAC, \
+ ((height)-1) << G_TEXTURE_IMAGE_FRAC)
+
+#ifndef _HW_VERSION_1
+
+#define gDPLoadTextureTile(pkt, timg, fmt, siz, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz, width, timg); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0, \
+ G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadTile( pkt, G_TX_LOADTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC) \
+}
+
+#else /******** WORKAROUND hw 1 load tile bug ********/
+
+#define gDPLoadTextureTile(pkt, timg, fmt, siz, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+{ \
+ int _loadtile_i, _loadtile_nw; Gfx *_loadtile_temp = pkt; \
+ guDPLoadTextureTile(_loadtile_temp, timg, fmt, siz, \
+ width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt); \
+ _loadtile_nw = guGetDPLoadTextureTileSz(ult, lrt) - 1; \
+ for(_loadtile_i = 0; _loadtile_i < _loadtile_nw; _loadtile_i++) \
+ pkt; \
+}
+
+#endif /* HW_VERSION_1 */
+
+/*
+ * Load texture tile. Allows tmem address and render tile to be specified.
+ * Useful for loading multiple tiles.
+ */
+#define gDPLoadMultiTile(pkt, timg, tmem, rtile, fmt, siz, width, height,\
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, siz, width, timg); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), tmem, \
+ G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadTile( pkt, G_TX_LOADTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, rtile, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC) \
+}
+
+
+#define gsDPLoadTextureTile(timg, fmt, siz, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz, width, timg), \
+ gsDPSetTile(fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0, \
+ G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadTile( G_TX_LOADTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,\
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC)
+
+/*
+ * Load texture tile. Allows tmem address and render tile to be specified.
+ * Useful for loading multiple tiles.
+ */
+#define gsDPLoadMultiTile(timg, tmem, rtile, fmt, siz, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, siz, width, timg), \
+ gsDPSetTile(fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), \
+ tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, \
+ masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadTile( G_TX_LOADTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, siz, \
+ (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), \
+ tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(rtile, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC)
+
+#define gDPLoadTextureTile_4b(pkt, timg, fmt, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width)>>1), timg); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_8b, \
+ (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \
+ G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadTile( pkt, G_TX_LOADTILE, \
+ (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (ult)<<(G_TEXTURE_IMAGE_FRAC), \
+ (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (lrt)<<(G_TEXTURE_IMAGE_FRAC)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_4b, \
+ (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, \
+ masks, shifts); \
+ gDPSetTileSize(pkt, G_TX_RENDERTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC) \
+}
+
+/*
+ * Load texture tile. Allows tmem address and render tile to be specified.
+ * Useful for loading multiple tiles.
+ */
+#define gDPLoadMultiTile_4b(pkt, timg, tmem, rtile, fmt, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+{ \
+ gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width)>>1), timg); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_8b, \
+ (((((lrs)-(uls)+1)>>1)+7)>>3), tmem, \
+ G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPLoadSync(pkt); \
+ gDPLoadTile( pkt, G_TX_LOADTILE, \
+ (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (ult)<<(G_TEXTURE_IMAGE_FRAC), \
+ (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (lrt)<<(G_TEXTURE_IMAGE_FRAC)); \
+ gDPPipeSync(pkt); \
+ gDPSetTile(pkt, fmt, G_IM_SIZ_4b, \
+ (((((lrs)-(uls)+1)>>1)+7)>>3), tmem, \
+ rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts); \
+ gDPSetTileSize(pkt, rtile, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC) \
+}
+
+#define gsDPLoadTextureTile_4b(timg, fmt, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width)>>1), timg), \
+ gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \
+ G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadTile( G_TX_LOADTILE, \
+ (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (ult)<<(G_TEXTURE_IMAGE_FRAC), \
+ (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (lrt)<<(G_TEXTURE_IMAGE_FRAC)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \
+ G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(G_TX_RENDERTILE, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC)
+
+/*
+ * Load texture tile. Allows tmem address and render tile to be specified.
+ * Useful for loading multiple tiles.
+ */
+#define gsDPLoadMultiTile_4b(timg, tmem, rtile, fmt, width, height, \
+ uls, ult, lrs, lrt, pal, \
+ cms, cmt, masks, maskt, shifts, shiftt) \
+ \
+ gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width)>>1), timg), \
+ gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3), \
+ tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, \
+ masks, shifts), \
+ gsDPLoadSync(), \
+ gsDPLoadTile( G_TX_LOADTILE, \
+ (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (ult)<<(G_TEXTURE_IMAGE_FRAC), \
+ (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \
+ (lrt)<<(G_TEXTURE_IMAGE_FRAC)), \
+ gsDPPipeSync(), \
+ gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), \
+ tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, \
+ shifts), \
+ gsDPSetTileSize(rtile, \
+ (uls)<<G_TEXTURE_IMAGE_FRAC, \
+ (ult)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrs)<<G_TEXTURE_IMAGE_FRAC, \
+ (lrt)<<G_TEXTURE_IMAGE_FRAC)
+
+/*
+ * Load a 16-entry palette (for 4-bit CI textures)
+ * Assumes a 16 entry tlut is being loaded, palette # is 0-15
+ */
+#ifndef _HW_VERSION_1
+
+#define gDPLoadTLUT_pal16(pkt, pal, dram) \
+{ \
+ gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
+ gDPTileSync(pkt); \
+ gDPSetTile(pkt, 0, 0, 0, (256+(((pal)&0xf)*16)), \
+ G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0); \
+ gDPLoadSync(pkt); \
+ gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 15); \
+ gDPPipeSync(pkt) \
+}
+
+#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */
+
+#define gDPLoadTLUT_pal16(pkt, pal, dram) \
+ \
+ _gDPLoadTextureBlock(pkt, dram, (256+(((pal)&0xf)*16)), \
+ G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*16, 1, \
+ pal, 0, 0, 0, 0, 0, 0)
+
+#endif /* _HW_VERSION_1 */
+
+
+/*
+ * Load a 16-entry palette (for 4-bit CI textures)
+ * Assumes a 16 entry tlut is being loaded, palette # is 0-15
+ */
+#ifndef _HW_VERSION_1
+
+#define gsDPLoadTLUT_pal16(pal, dram) \
+ \
+ gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
+ gsDPTileSync(), \
+ gsDPSetTile(0, 0, 0, (256+(((pal)&0xf)*16)), \
+ G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0), \
+ gsDPLoadSync(), \
+ gsDPLoadTLUTCmd(G_TX_LOADTILE, 15), \
+ gsDPPipeSync()
+
+#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */
+
+#define gsDPLoadTLUT_pal16(pal, dram) \
+ \
+ _gsDPLoadTextureBlock(dram, (256+(((pal)&0xf)*16)), \
+ G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*16, 1, \
+ pal, 0, 0, 0, 0, 0, 0)
+
+#endif /* _HW_VERSION_1 */
+
+/*
+ * Load a 256-entry palette (for 8-bit CI textures)
+ * Assumes a 256 entry tlut is being loaded, palette # is not used
+ */
+#ifndef _HW_VERSION_1
+
+#define gDPLoadTLUT_pal256(pkt, dram) \
+{ \
+ gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
+ gDPTileSync(pkt); \
+ gDPSetTile(pkt, 0, 0, 0, 256, \
+ G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0); \
+ gDPLoadSync(pkt); \
+ gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 255); \
+ gDPPipeSync(pkt) \
+}
+
+#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */
+
+#define gDPLoadTLUT_pal256(pkt, dram) \
+ \
+ _gDPLoadTextureBlock(pkt, dram, 256, \
+ G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*256, 1, \
+ 0, 0, 0, 0, 0, 0, 0)
+
+
+#endif /* _HW_VERSION_1 */
+
+
+#ifndef _HW_VERSION_1
+
+#define gsDPLoadTLUT_pal256(dram) \
+ \
+ gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
+ gsDPTileSync(), \
+ gsDPSetTile(0, 0, 0, 256, \
+ G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0), \
+ gsDPLoadSync(), \
+ gsDPLoadTLUTCmd(G_TX_LOADTILE, 255), \
+ gsDPPipeSync()
+
+#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */
+
+#define gsDPLoadTLUT_pal256(dram) \
+ \
+ _gsDPLoadTextureBlock(dram, 256, \
+ G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*256, 1, \
+ 0, 0, 0, 0, 0, 0, 0)
+
+#endif /* _HW_VERSION_1 */
+
+
+#ifndef _HW_VERSION_1
+
+#define gDPLoadTLUT(pkt, count, tmemaddr, dram) \
+{ \
+ gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
+ gDPTileSync(pkt); \
+ gDPSetTile(pkt, 0, 0, 0, tmemaddr, \
+ G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0); \
+ gDPLoadSync(pkt); \
+ gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, ((count)-1)); \
+ gDPPipeSync(pkt); \
+}
+
+#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */
+
+#define gDPLoadTLUT(pkt, count, tmemaddr, dram) \
+ \
+ _gDPLoadTextureBlock(pkt, dram, tmemaddr, \
+ G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count, \
+ 0, 0, 0, 0, 0, 0, 0)
+
+#endif /* _HW_VERSION_1 */
+
+
+#ifndef _HW_VERSION_1
+
+#define gsDPLoadTLUT(count, tmemaddr, dram) \
+ \
+ gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
+ gsDPTileSync(), \
+ gsDPSetTile(0, 0, 0, tmemaddr, \
+ G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0), \
+ gsDPLoadSync(), \
+ gsDPLoadTLUTCmd(G_TX_LOADTILE, ((count)-1)), \
+ gsDPPipeSync()
+
+#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */
+#define gsDPLoadTLUT(count, tmemaddr, dram) \
+ \
+ _gsDPLoadTextureBlock(dram, tmemaddr, \
+ G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count, \
+ 0, 0, 0, 0, 0, 0, 0)
+
+#endif /* _HW_VERSION_1 */
+
+#define gDPSetScissor(pkt, mode, ulx, uly, lrx, lry) \
+{ \
+ Gfx *_g = (Gfx *)pkt; \
+ \
+ _g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) | \
+ _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) | \
+ _SHIFTL((int)((float)(uly)*4.0F), 0, 12); \
+ _g->words.w1 = _SHIFTL(mode, 24, 2) | \
+ _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) | \
+ _SHIFTL((int)((float)(lry)*4.0F), 0, 12); \
+}
+
+
+#define gDPSetScissorFrac(pkt, mode, ulx, uly, lrx, lry) \
+{ \
+ Gfx *_g = (Gfx *)pkt; \
+ \
+ _g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) | \
+ _SHIFTL((int)((ulx)), 12, 12) | \
+ _SHIFTL((int)((uly)), 0, 12); \
+ _g->words.w1 = _SHIFTL(mode, 24, 2) | \
+ _SHIFTL((int)((lrx)), 12, 12) | \
+ _SHIFTL((int)((lry)), 0, 12); \
+}
+
+#define gsDPSetScissor(mode, ulx, uly, lrx, lry) \
+{{ \
+ _SHIFTL(G_SETSCISSOR, 24, 8) | \
+ _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) | \
+ _SHIFTL((int)((float)(uly)*4.0F), 0, 12), \
+ _SHIFTL(mode, 24, 2) | \
+ _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) | \
+ _SHIFTL((int)((float)(lry)*4.0F), 0, 12) \
+}}
+
+#define gsDPSetScissorFrac(mode, ulx, uly, lrx, lry) \
+{{ \
+ _SHIFTL(G_SETSCISSOR, 24, 8) | \
+ _SHIFTL((int)((ulx)), 12, 12) | \
+ _SHIFTL((int)((uly)), 0, 12), \
+ _SHIFTL(mode, 24, 2) | \
+ _SHIFTL((int)(lrx), 12, 12) | \
+ _SHIFTL((int)(lry), 0, 12) \
+}}
+
+/* Fraction never used in fill */
+#ifdef F3DEX_GBI_2E
+#define gDPFillRectangle(pkt, ulx, uly, lrx, lry) \
+{ \
+ Gfx *_g0 = (Gfx *)(pkt), *_g1 = (Gfx *)(pkt); \
+ _g0->words.w0 = _SHIFTL(G_FILLRECT, 24, 8) | \
+ _SHIFTL((lrx), 2, 22); \
+ _g0->words.w1 = _SHIFTL((lry), 2, 22); \
+ _g1->words.w0 = _SHIFTL((ulx), 2, 22); \
+ _g1->words.w1 = _SHIFTL((uly), 2, 22); \
+}
+#define gsDPFillRectangle(ulx, uly, lrx, lry) \
+{{ \
+ (_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((lrx), 2, 22)), \
+ _SHIFTL((lry), 2, 22), \
+}}, \
+{{ \
+ _SHIFTL((ulx), 2, 22), \
+ _SHIFTL((uly), 2, 22), \
+}}
+#else
+#define gDPFillRectangle(pkt, ulx, uly, lrx, lry) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | \
+ _SHIFTL((lrx), 14, 10) | _SHIFTL((lry), 2, 10));\
+ _g->words.w1 = (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10));\
+}
+#define gsDPFillRectangle(ulx, uly, lrx, lry) \
+{{ \
+ (_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((lrx), 14, 10) | \
+ _SHIFTL((lry), 2, 10)), \
+ (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10)) \
+}}
+#endif
+
+/* like gDPFillRectangle but accepts negative arguments */
+#ifndef F3DEX_GBI_2E
+#define gDPScisFillRectangle(pkt, ulx, uly, lrx, lry) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | \
+ _SHIFTL(MAX((lrx),0), 14, 10) | \
+ _SHIFTL(MAX((lry),0), 2, 10)); \
+ _g->words.w1 = (_SHIFTL(MAX((ulx),0), 14, 10) | \
+ _SHIFTL(MAX((uly),0), 2, 10)); \
+}
+#endif
+
+#define gDPSetConvert(pkt, k0, k1, k2, k3, k4, k5) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_SETCONVERT, 24, 8) | \
+ _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | \
+ _SHIFTR(k2, 5, 4)); \
+ _g->words.w1 = (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | \
+ _SHIFTL(k4, 9, 9) | _SHIFTL(k5, 0, 9)); \
+}
+
+#define gsDPSetConvert(k0, k1, k2, k3, k4, k5) \
+{{ \
+ (_SHIFTL(G_SETCONVERT, 24, 8) | \
+ _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | _SHIFTR(k2, 5, 4)), \
+ (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | _SHIFTL(k4, 9, 9) | \
+ _SHIFTL(k5, 0, 9)) \
+}}
+
+#define gDPSetKeyR(pkt, cR, sR, wR) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(G_SETKEYR, 24, 8); \
+ _g->words.w1 = (_SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | \
+ _SHIFTL(sR, 0, 8)); \
+}
+
+#define gsDPSetKeyR(cR, sR, wR) \
+{{ \
+ _SHIFTL(G_SETKEYR, 24, 8), \
+ _SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | _SHIFTL(sR, 0, 8) \
+}}
+
+#define gDPSetKeyGB(pkt, cG, sG, wG, cB, sB, wB) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_SETKEYGB, 24, 8) | \
+ _SHIFTL(wG, 12, 12) | _SHIFTL(wB, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | \
+ _SHIFTL(cB, 8, 8) | _SHIFTL(sB, 0, 8)); \
+}
+
+#define gsDPSetKeyGB(cG, sG, wG, cB, sB, wB) \
+{{ \
+ (_SHIFTL(G_SETKEYGB, 24, 8) | _SHIFTL(wG, 12, 12) | \
+ _SHIFTL(wB, 0, 12)), \
+ (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | _SHIFTL(cB, 8, 8) | \
+ _SHIFTL(sB, 0, 8)) \
+}}
+
+#define gDPNoParam(pkt, cmd) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(cmd, 24, 8); \
+ _g->words.w1 = 0; \
+}
+
+#define gsDPNoParam(cmd) \
+{{ \
+ _SHIFTL(cmd, 24, 8), 0 \
+}}
+
+#define gDPParam(pkt, cmd, param) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = _SHIFTL(cmd, 24, 8); \
+ _g->words.w1 = (param); \
+}
+
+#define gsDPParam(cmd, param) \
+{{ \
+ _SHIFTL(cmd, 24, 8), (param) \
+}}
+
+/* Notice that textured rectangles are 128-bit commands, therefore
+ * gsDPTextureRectangle() should not be used in display lists
+ * under normal circumstances (use gsSPTextureRectangle()).
+ * That is also why there is no gDPTextureRectangle() macros.
+ */
+#define gsDPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{{ \
+ (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)), \
+ (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \
+}}, \
+{{ \
+ _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), \
+ _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \
+}}
+
+#define gDPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ if (pkt); \
+ _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \
+ _SHIFTL(yl, 0, 12)); \
+ _g ++; \
+ _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \
+ _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \
+}
+
+#define gsDPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{{ \
+ (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)), \
+ (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \
+}}, \
+{{ \
+ _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), \
+ _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \
+}}
+
+#define gDPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ if (pkt); \
+ _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \
+ _SHIFTL(yl, 0, 12)); \
+ _g ++; \
+ _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \
+ _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \
+}
+
+#ifdef F3D_OLD
+# define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \
+ _SHIFTL(yl, 0, 12)); \
+ gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \
+ gImmp1(pkt, G_RDPHALF_CONT, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)));\
+}
+
+#define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+ {{(_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)),\
+ (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12))}}, \
+ gsImmp1(G_RDPHALF_2, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \
+ gsImmp1(G_RDPHALF_CONT, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))
+
+/* like gSPTextureRectangle but accepts negative position arguments */
+# define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | \
+ _SHIFTL(MAX((s16)(xh),0), 12, 12) | \
+ _SHIFTL(MAX((s16)(yh),0), 0, 12)); \
+ _g->words.w1 = (_SHIFTL((tile), 24, 3) | \
+ _SHIFTL(MAX((s16)(xl),0), 12, 12) | \
+ _SHIFTL(MAX((s16)(yl),0), 0, 12)); \
+ gImmp1(pkt, G_RDPHALF_2, \
+ (_SHIFTL(((s) - \
+ (((s16)(xl) < 0) ? \
+ (((s16)(dsdx) < 0) ? \
+ (MAX((((s16)(xl)*(s16)(dsdx))>>7),0)) : \
+ (MIN((((s16)(xl)*(s16)(dsdx))>>7),0))) : 0)), \
+ 16, 16) | \
+ _SHIFTL(((t) - \
+ (((yl) < 0) ? \
+ (((s16)(dtdy) < 0) ? \
+ (MAX((((s16)(yl)*(s16)(dtdy))>>7),0)) : \
+ (MIN((((s16)(yl)*(s16)(dtdy))>>7),0))) : 0)), \
+ 0, 16))); \
+ gImmp1(pkt, G_RDPHALF_CONT, (_SHIFTL((dsdx), 16, 16) | \
+ _SHIFTL((dtdy), 0, 16))); \
+}
+
+# define gsSPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+ {{(_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)), \
+ (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12))}}, \
+ gsImmp1(G_RDPHALF_2, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \
+ gsImmp1(G_RDPHALF_CONT, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))
+
+# define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |\
+ _SHIFTL(yh, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \
+ _SHIFTL(yl, 0, 12)); \
+ gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \
+ gImmp1(pkt, G_RDPHALF_CONT, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \
+}
+#elif defined(F3DEX_GBI_2E)
+# define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
+{ \
+ Gfx *_g0 = (Gfx *)(pkt), *_g1 = (Gfx *)(pkt), *_g2 = (Gfx *)(pkt); \
+ \
+ _g0->words.w0 = _SHIFTL(G_TEXRECT, 24, 8) | \
+ _SHIFTL((xh), 0, 24); \
+ _g0->words.w1 = _SHIFTL((yh), 0, 24); \
+ _g1->words.w0 = (_SHIFTL(tile, 24, 3) | _SHIFTL((xl), 0, 24)); \
+ _g1->words.w1 = _SHIFTL((yl), 0, 24); \
+ _g2->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \
+ _g2->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \
+}
+
+# define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{{ \
+ (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL((xh), 0, 24)), \
+ _SHIFTL((yh), 0, 24), \
+}}, \
+{{ \
+ (_SHIFTL((tile), 24, 3) | _SHIFTL((xl), 0, 24)), \
+ _SHIFTL((yl), 0, 24), \
+}}, \
+{{ \
+ _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), \
+ _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \
+}}
+
+# define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{ \
+ Gfx *_g0 = (Gfx *)(pkt), *_g1 = (Gfx *)(pkt), *_g2 = (Gfx *)(pkt); \
+ \
+ _g0->words.w0 = _SHIFTL(G_TEXRECTFLIP, 24, 8) | \
+ _SHIFTL((xh), 0, 24); \
+ _g0->words.w1 = _SHIFTL((yh), 0, 24); \
+ _g1->words.w0 = (_SHIFTL(tile, 24, 3) | _SHIFTL((xl), 0, 24)); \
+ _g1->words.w1 = _SHIFTL((yl), 0, 24); \
+ _g2->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \
+ _g2->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \
+}
+#else
+# define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \
+ _SHIFTL(yl, 0, 12)); \
+ gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \
+ gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)));\
+}
+
+#define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+ {{(_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)),\
+ (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12))}}, \
+ gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \
+ gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))
+
+/* like gSPTextureRectangle but accepts negative position arguments */
+# define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | \
+ _SHIFTL(MAX((s16)(xh),0), 12, 12) | \
+ _SHIFTL(MAX((s16)(yh),0), 0, 12)); \
+ _g->words.w1 = (_SHIFTL((tile), 24, 3) | \
+ _SHIFTL(MAX((s16)(xl),0), 12, 12) | \
+ _SHIFTL(MAX((s16)(yl),0), 0, 12)); \
+ gImmp1(pkt, G_RDPHALF_1, \
+ (_SHIFTL(((s) - \
+ (((s16)(xl) < 0) ? \
+ (((s16)(dsdx) < 0) ? \
+ (MAX((((s16)(xl)*(s16)(dsdx))>>7),0)) : \
+ (MIN((((s16)(xl)*(s16)(dsdx))>>7),0))) : 0)), \
+ 16, 16) | \
+ _SHIFTL(((t) - \
+ (((yl) < 0) ? \
+ (((s16)(dtdy) < 0) ? \
+ (MAX((((s16)(yl)*(s16)(dtdy))>>7),0)) : \
+ (MIN((((s16)(yl)*(s16)(dtdy))>>7),0))) : 0)), \
+ 0, 16))); \
+ gImmp1(pkt, G_RDPHALF_2, (_SHIFTL((dsdx), 16, 16) | \
+ _SHIFTL((dtdy), 0, 16))); \
+}
+
+# define gsSPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+ {{(_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \
+ _SHIFTL(yh, 0, 12)), \
+ (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12))}}, \
+ gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \
+ gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))
+
+# define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |\
+ _SHIFTL(yh, 0, 12)); \
+ _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \
+ _SHIFTL(yl, 0, 12)); \
+ gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \
+ gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \
+}
+#endif
+
+#define gsDPWord(wordhi, wordlo) \
+ gsImmp1(G_RDPHALF_1, (uintptr_t)(wordhi)), \
+ gsImmp1(G_RDPHALF_2, (uintptr_t)(wordlo))
+
+#define gDPWord(pkt, wordhi, wordlo) \
+{ \
+ Gfx *_g = (Gfx *)(pkt); \
+ \
+ gImmp1(pkt, G_RDPHALF_1, (uintptr_t)(wordhi)); \
+ gImmp1(pkt, G_RDPHALF_2, (uintptr_t)(wordlo)); \
+}
+
+#define gDPFullSync(pkt) gDPNoParam(pkt, G_RDPFULLSYNC)
+#define gsDPFullSync() gsDPNoParam(G_RDPFULLSYNC)
+#define gDPTileSync(pkt) gDPNoParam(pkt, G_RDPTILESYNC)
+#define gsDPTileSync() gsDPNoParam(G_RDPTILESYNC)
+#define gDPPipeSync(pkt) gDPNoParam(pkt, G_RDPPIPESYNC)
+#define gsDPPipeSync() gsDPNoParam(G_RDPPIPESYNC)
+#define gDPLoadSync(pkt) gDPNoParam(pkt, G_RDPLOADSYNC)
+#define gsDPLoadSync() gsDPNoParam(G_RDPLOADSYNC)
+#define gDPNoOp(pkt) gDPNoParam(pkt, G_NOOP)
+#define gsDPNoOp() gsDPNoParam(G_NOOP)
+#define gDPNoOpTag(pkt, tag) gDPParam(pkt, G_NOOP, tag)
+#define gsDPNoOpTag(tag) gsDPParam(G_NOOP, tag)
+
+#endif /* _LANGUAGE_C */
+
+
+#endif /* _GBI_H_ */ \ No newline at end of file
diff --git a/src/n64/types.h b/src/n64/types.h
new file mode 100644
index 0000000..52ce306
--- /dev/null
+++ b/src/n64/types.h
@@ -0,0 +1,59 @@
+#ifndef ULTRA64_TYPES_H
+#define ULTRA64_TYPES_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+typedef signed char s8;
+typedef unsigned char u8;
+typedef signed short int s16;
+typedef unsigned short int u16;
+typedef signed int s32;
+typedef unsigned int u32;
+typedef signed long long int s64;
+typedef unsigned long long int u64;
+
+typedef volatile u8 vu8;
+typedef volatile u16 vu16;
+typedef volatile u32 vu32;
+typedef volatile u64 vu64;
+typedef volatile s8 vs8;
+typedef volatile s16 vs16;
+typedef volatile s32 vs32;
+typedef volatile s64 vs64;
+
+typedef float f32;
+typedef double f64;
+#if 0
+
+typedef s32 ptrdiff_t;
+typedef s32 intptr_t;
+typedef u32 uintptr_t;
+#endif
+
+#ifndef GBI_FLOATS
+typedef int Mtx_t[4][4];
+typedef union {
+ Mtx_t m;
+ struct {
+ u16 intPart[4][4];
+ u16 fracPart[4][4];
+ };
+ long long int forc_structure_alignment;
+} Mtx;
+#else
+typedef struct {
+ float m[4][4];
+} Mtx;
+#endif
+
+typedef float MtxF_t[4][4];
+typedef union {
+ MtxF_t mf;
+ struct {
+ float xx, yx, zx, wx, xy, yy, zy, wy, xz, yz, zz, wz, xw, yw, zw, ww;
+ };
+} MtxF;
+
+#endif
diff --git a/src/storm/SWrapper.cpp b/src/storm/SWrapper.cpp
index d17042f..fbb2329 100644
--- a/src/storm/SWrapper.cpp
+++ b/src/storm/SWrapper.cpp
@@ -1,8 +1,12 @@
#include "SWrapper.h"
#include <filesystem>
#include <iostream>
+#include <fstream>
+
+#include "spdlog/spdlog.h"
namespace fs = std::filesystem;
+bool debugMode = true;
SWrapper::SWrapper(const std::string& path) {
if(fs::exists(path)) {
@@ -17,6 +21,17 @@ SWrapper::SWrapper(const std::string& path) {
}
bool SWrapper::CreateFile(const std::string& path, std::vector<char> data) {
+ if(debugMode){
+ SPDLOG_INFO("Creating debug file: debug/{}", path);
+ std::string dpath = "debug/" + path;
+ if(!fs::exists(fs::path(dpath).parent_path())){
+ fs::create_directories(fs::path(dpath).parent_path());
+ }
+ std::ofstream stream(dpath, std::ios::binary);
+ stream.write((char*)data.data(), data.size());
+ stream.close();
+ }
+
HANDLE hFile;
#ifdef _WIN32
SYSTEMTIME sysTime;
@@ -32,6 +47,11 @@ bool SWrapper::CreateFile(const std::string& path, std::vector<char> data) {
char* raw = (char*) data.data();
size_t size = data.size();
+ if(size == 0){
+ std::cout << "File empty: " << path << std::endl;
+ return false;
+ }
+
if(size >> 32){
std::cout << "File too large: " << path << std::endl;
return false;
diff --git a/src/types/RawBuffer.h b/src/types/RawBuffer.h
new file mode 100644
index 0000000..b3ac390
--- /dev/null
+++ b/src/types/RawBuffer.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "../factories/BaseFactory.h"
+
+class RawBuffer : public IParsedData {
+public:
+ std::vector<uint8_t> mBuffer;
+
+ RawBuffer(uint8_t* data, size_t size) : mBuffer(data, data + size) {}
+ explicit RawBuffer(std::vector<uint8_t>& buffer) : mBuffer(std::move(buffer)) {}
+ RawBuffer(std::vector<uint8_t>::iterator begin, std::vector<uint8_t>::iterator end) : mBuffer(begin, end) {}
+}; \ No newline at end of file
diff --git a/src/types/SegmentedAddr.h b/src/types/SegmentedAddr.h
new file mode 100644
index 0000000..8aa868e
--- /dev/null
+++ b/src/types/SegmentedAddr.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <cstdint>
+
+struct SegmentedAddr {
+ uint32_t offset;
+}; \ No newline at end of file
diff --git a/src/utils/MIODecoder.cpp b/src/utils/MIODecoder.cpp
index 0a1698e..7574e55 100644
--- a/src/utils/MIODecoder.cpp
+++ b/src/utils/MIODecoder.cpp
@@ -1,14 +1,13 @@
#include "MIODecoder.h"
+#include <stdexcept>
extern "C" {
#include <libmio0/mio0.h>
}
-#include <stdexcept>
-#include <cstdint>
-std::unordered_map<uint32_t, std::vector<char>> MIO0Decoder::gCachedChunks;
+std::unordered_map<uint32_t, std::vector<uint8_t>> MIO0Decoder::gCachedChunks;
-std::vector<char>& MIO0Decoder::Decode(std::vector<uint8_t>& buffer, uint32_t offset) {
+std::vector<uint8_t>& MIO0Decoder::Decode(std::vector<uint8_t>& buffer, uint32_t offset) {
const unsigned char* in_buf = buffer.data() + offset;
mio0_header_t head;
@@ -16,9 +15,9 @@ std::vector<char>& MIO0Decoder::Decode(std::vector<uint8_t>& buffer, uint32_t of
throw std::runtime_error("Failed to decode MIO0 header");
}
- uint8_t* decompressed = new uint8_t[head.dest_size];
+ auto decompressed = new uint8_t[head.dest_size];
mio0_decode(in_buf, decompressed, nullptr);
- gCachedChunks[offset] = std::vector<char>(decompressed, decompressed + head.dest_size);
+ gCachedChunks[offset] = std::vector<uint8_t>(decompressed, decompressed + head.dest_size);
delete[] decompressed;
return gCachedChunks[offset];
diff --git a/src/utils/MIODecoder.h b/src/utils/MIODecoder.h
index 0d60ef9..ecf2ca4 100644
--- a/src/utils/MIODecoder.h
+++ b/src/utils/MIODecoder.h
@@ -6,7 +6,7 @@
class MIO0Decoder {
public:
- static std::unordered_map<uint32_t, std::vector<char>> gCachedChunks;
- static std::vector<char>& Decode(std::vector<uint8_t>& buffer, uint32_t offset);
+ static std::unordered_map<uint32_t, std::vector<uint8_t>> gCachedChunks;
+ static std::vector<uint8_t>& Decode(std::vector<uint8_t>& buffer, uint32_t offset);
static void ClearCache();
};