diff options
| author | Lywx <kiritodev01@gmail.com> | 2023-11-15 15:11:15 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-15 15:11:15 -0600 |
| commit | eaddecd0b402c12a780831e3139d7a35e78322e6 (patch) | |
| tree | 0c961e1ba2339f52892b54f44b8ff0018b77c382 /src | |
| parent | a66b259d7c10c3367a04819c6b55d47fb9a99f5e (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')
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(); }; |
