mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
Swapped mio with offset and fixed samples and animations
This commit is contained in:
+2
-1
@@ -11,4 +11,5 @@ debug/
|
||||
headers/
|
||||
build/
|
||||
code/
|
||||
.vscode/
|
||||
.vscode/
|
||||
tools/
|
||||
+105
-62
@@ -34,7 +34,7 @@ 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->gExporterType = type;
|
||||
this->gConfig.exporterType = type;
|
||||
this->RegisterFactory("BLOB", std::make_shared<BlobFactory>());
|
||||
this->RegisterFactory("TEXTURE", std::make_shared<TextureFactory>());
|
||||
this->RegisterFactory("VTX", std::make_shared<VtxFactory>());
|
||||
@@ -77,37 +77,34 @@ void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binar
|
||||
return;
|
||||
}
|
||||
|
||||
if(node["segments"]) {
|
||||
for(auto segment = node["segments"].begin(); segment != node["segments"].end(); ++segment) {
|
||||
auto id = std::stoi(segment->first.as<std::string>().substr(3));
|
||||
auto replacement = segment->second.as<uint32_t>();
|
||||
this->gTemporalSegments[id] = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
auto exporter = factory->get()->GetExporter(this->gConfig.exporterType);
|
||||
if(!exporter.has_value()){
|
||||
SPDLOG_ERROR("No exporter found for {}", name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto [fst, snd] : this->gAssetDependencies[this->gCurrentFile]) {
|
||||
if(snd.second) continue;
|
||||
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) {
|
||||
switch (this->gConfig.exporterType) {
|
||||
case ExportType::Binary: {
|
||||
if(binary == nullptr) break;
|
||||
if(binary == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
stream.str("");
|
||||
stream.clear();
|
||||
exporter->get()->Export(stream, result.value(), name, node, &name);
|
||||
@@ -127,6 +124,17 @@ void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binar
|
||||
}
|
||||
}
|
||||
|
||||
void Companion::ParseCurrentFileConfig(YAML::Node node) {
|
||||
if(node["segments"]) {
|
||||
for(auto segment = node["segments"].begin(); segment != node["segments"].end(); ++segment) {
|
||||
const auto id = std::stoi(segment->first.as<std::string>().substr(3));
|
||||
const auto replacement = segment->second.as<uint32_t>();
|
||||
this->gConfig.segment.local[id] = replacement;
|
||||
SPDLOG_DEBUG("Segment {} replaced with 0x{:X}", id, replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Companion::Process() {
|
||||
|
||||
if(!fs::exists("config.yml")) {
|
||||
@@ -140,42 +148,45 @@ void Companion::Process() {
|
||||
this->gRomData = std::vector<uint8_t>( std::istreambuf_iterator( input ), {} );
|
||||
input.close();
|
||||
|
||||
this->gCartridge = new N64::Cartridge(this->gRomData);
|
||||
gCartridge->Initialize();
|
||||
this->gCartridge = std::make_shared<N64::Cartridge>(this->gRomData);
|
||||
this->gCartridge->Initialize();
|
||||
|
||||
YAML::Node config = YAML::LoadFile("config.yml");
|
||||
|
||||
if(!config[gCartridge->GetHash()]){
|
||||
SPDLOG_ERROR("No config found for {}", gCartridge->GetHash());
|
||||
if(!config[this->gCartridge->GetHash()]){
|
||||
SPDLOG_ERROR("No config found for {}", this->gCartridge->GetHash());
|
||||
return;
|
||||
}
|
||||
|
||||
auto rom = config[gCartridge->GetHash()];
|
||||
auto rom = config[this->gCartridge->GetHash()];
|
||||
auto cfg = rom["config"];
|
||||
|
||||
if(!cfg) {
|
||||
SPDLOG_ERROR("No config found for {}", gCartridge->GetHash());
|
||||
SPDLOG_ERROR("No config found for {}", this->gCartridge->GetHash());
|
||||
return;
|
||||
}
|
||||
|
||||
if(rom["segments"]) {
|
||||
this->gSegments = rom["segments"].as<std::vector<uint32_t>>();
|
||||
auto segments = rom["segments"].as<std::vector<uint32_t>>();
|
||||
for (int i = 0; i < segments.size(); i++) {
|
||||
this->gConfig.segment.global[i + 1] = segments[i];
|
||||
}
|
||||
}
|
||||
auto path = rom["path"].as<std::string>();
|
||||
auto opath = cfg["output"];
|
||||
auto gbi = cfg["gbi"];
|
||||
|
||||
switch (gExporterType) {
|
||||
switch (this->gConfig.exporterType) {
|
||||
case ExportType::Binary: {
|
||||
this->gOutputPath = opath && opath["binary"] ? opath["binary"].as<std::string>() : "generic.otr";
|
||||
this->gConfig.outputPath = 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";
|
||||
this->gConfig.outputPath = opath && opath["headers"] ? opath["headers"].as<std::string>() : "headers";
|
||||
break;
|
||||
}
|
||||
case ExportType::Code: {
|
||||
this->gOutputPath = opath && opath["code"] ? opath["code"].as<std::string>() : "code";
|
||||
this->gConfig.outputPath = opath && opath["code"] ? opath["code"].as<std::string>() : "code";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -184,18 +195,18 @@ void Companion::Process() {
|
||||
auto key = gbi.as<std::string>();
|
||||
|
||||
if(key == "F3D") {
|
||||
this->gGBIVersion = GBIVersion::f3d;
|
||||
this->gConfig.gbi.version = GBIVersion::f3d;
|
||||
} else if(key == "F3DEX") {
|
||||
this->gGBIVersion = GBIVersion::f3dex;
|
||||
this->gConfig.gbi.version = GBIVersion::f3dex;
|
||||
} else if(key == "F3DB") {
|
||||
this->gGBIVersion = GBIVersion::f3db;
|
||||
this->gConfig.gbi.version = GBIVersion::f3db;
|
||||
} else if(key == "F3DEX2") {
|
||||
this->gGBIVersion = GBIVersion::f3dex2;
|
||||
this->gConfig.gbi.version = GBIVersion::f3dex2;
|
||||
} else if(key == "F3DEXB") {
|
||||
this->gGBIVersion = GBIVersion::f3dexb;
|
||||
this->gConfig.gbi.version = GBIVersion::f3dexb;
|
||||
} else if (key == "F3DEX_MK64") {
|
||||
this->gGBIVersion = GBIVersion::f3dex;
|
||||
this->gGBIMinorVersion = GBIMinorVersion::Mk64;
|
||||
this->gConfig.gbi.version = GBIVersion::f3dex;
|
||||
this->gConfig.gbi.subversion = GBIMinorVersion::Mk64;
|
||||
} else {
|
||||
SPDLOG_ERROR("Invalid GBI version");
|
||||
return;
|
||||
@@ -230,29 +241,41 @@ void Companion::Process() {
|
||||
spdlog::set_pattern(line);
|
||||
|
||||
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("Game: {}", this->gCartridge->GetGameTitle());
|
||||
SPDLOG_INFO("CRC: {}", this->gCartridge->GetCRC());
|
||||
SPDLOG_INFO("Version: {}", this->gCartridge->GetVersion());
|
||||
SPDLOG_INFO("Country: [{}]", this->gCartridge->GetCountryCode());
|
||||
SPDLOG_INFO("Hash: {}", this->gCartridge->GetHash());
|
||||
SPDLOG_INFO("Assets: {}", path);
|
||||
|
||||
auto wrapper = this->gExporterType == ExportType::Binary ? new SWrapper(this->gOutputPath) : nullptr;
|
||||
auto wrapper = this->gConfig.exporterType == ExportType::Binary ? new SWrapper(this->gConfig.outputPath) : nullptr;
|
||||
|
||||
auto vWriter = LUS::BinaryWriter();
|
||||
vWriter.SetEndianness(LUS::Endianness::Big);
|
||||
vWriter.Write(static_cast<uint8_t>(LUS::Endianness::Big));
|
||||
vWriter.Write(gCartridge->GetCRC());
|
||||
vWriter.Write(this->gCartridge->GetCRC());
|
||||
|
||||
for (const auto & entry : fs::recursive_directory_iterator(path)){
|
||||
if(entry.is_directory()) continue;
|
||||
YAML::Node root = YAML::LoadFile(entry.path().string());
|
||||
if(entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto yamlPath = entry.path().string();
|
||||
|
||||
if(yamlPath.find(".yaml") == std::string::npos && yamlPath.find(".yml") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
YAML::Node root = YAML::LoadFile(yamlPath);
|
||||
this->gCurrentDirectory = relative(entry.path(), path).replace_extension("");
|
||||
this->gCurrentFile = entry.path().string();
|
||||
this->gCurrentFile = yamlPath;
|
||||
|
||||
for(auto asset = root.begin(); asset != root.end(); ++asset){
|
||||
auto node = asset->second;
|
||||
if(!asset->second["offset"]) continue;
|
||||
|
||||
if(!asset->second["offset"]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto output = (this->gCurrentDirectory / asset->first.as<std::string>()).string();
|
||||
std::replace(output.begin(), output.end(), '\\', '/');
|
||||
@@ -261,26 +284,40 @@ void Companion::Process() {
|
||||
}
|
||||
|
||||
// Stupid hack because the iteration broke the assets
|
||||
root = YAML::LoadFile(entry.path().string());
|
||||
root = YAML::LoadFile(yamlPath);
|
||||
this->gConfig.segment.local.clear();
|
||||
|
||||
if(root[":config"]) {
|
||||
this->ParseCurrentFileConfig(root[":config"]);
|
||||
}
|
||||
|
||||
spdlog::set_pattern(regular);
|
||||
SPDLOG_INFO("------------------------------------------------");
|
||||
spdlog::set_pattern(line);
|
||||
|
||||
for(auto asset = root.begin(); asset != root.end(); ++asset){
|
||||
|
||||
spdlog::set_pattern(regular);
|
||||
SPDLOG_INFO("------------------------------------------------");
|
||||
spdlog::set_pattern(line);
|
||||
|
||||
auto entryName = asset->first.as<std::string>();
|
||||
std::string output = (this->gCurrentDirectory / entryName).string();
|
||||
std::replace(output.begin(), output.end(), '\\', '/');
|
||||
|
||||
this->gTemporalSegments.clear();
|
||||
if(entryName.find(":config") != std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this->gConfig.segment.temporal.clear();
|
||||
|
||||
this->ExtractNode(asset->second, output, wrapper);
|
||||
|
||||
spdlog::set_pattern(regular);
|
||||
SPDLOG_INFO("------------------------------------------------");
|
||||
spdlog::set_pattern(line);
|
||||
}
|
||||
|
||||
if(gExporterType != ExportType::Binary){
|
||||
std::string output = (this->gOutputPath / this->gCurrentDirectory).string();
|
||||
if(this->gConfig.exporterType != ExportType::Binary){
|
||||
std::string output = (this->gConfig.outputPath / this->gCurrentDirectory).string();
|
||||
|
||||
switch (gExporterType) {
|
||||
switch (this->gConfig.exporterType) {
|
||||
case ExportType::Header: {
|
||||
output += "/definition.h";
|
||||
break;
|
||||
@@ -345,7 +382,7 @@ void Companion::Process() {
|
||||
|
||||
std::ofstream file(output, std::ios::binary);
|
||||
|
||||
if(gExporterType == ExportType::Header) {
|
||||
if(this->gConfig.exporterType == ExportType::Header) {
|
||||
std::string symbol = entry.path().stem().string();
|
||||
std::transform(symbol.begin(), symbol.end(), symbol.begin(), toupper);
|
||||
file << "#ifndef " << symbol << "_H" << std::endl;
|
||||
@@ -360,9 +397,6 @@ void Companion::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
spdlog::set_pattern(regular);
|
||||
SPDLOG_INFO("------------------------------------------------");
|
||||
spdlog::set_pattern(line);
|
||||
if(wrapper != nullptr) {
|
||||
SPDLOG_INFO("Writing version file");
|
||||
wrapper->CreateFile("version", vWriter.ToVector());
|
||||
@@ -393,7 +427,10 @@ void Companion::Pack(const std::string& folder, const std::string& output) {
|
||||
std::unordered_map<std::string, std::vector<char>> files;
|
||||
|
||||
for (const auto & entry : fs::recursive_directory_iterator(folder)){
|
||||
if(entry.is_directory()) continue;
|
||||
if(entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ifstream input( entry.path(), std::ios::binary );
|
||||
auto data = std::vector( std::istreambuf_iterator( input ), {} );
|
||||
input.close();
|
||||
@@ -447,17 +484,23 @@ std::optional<std::shared_ptr<BaseFactory>> Companion::GetFactory(const std::str
|
||||
return this->gFactories[type];
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t> Companion::GetSegmentedAddr(const uint8_t segment) {
|
||||
std::optional<std::uint32_t> Companion::GetSegmentedAddr(const uint8_t segment) const {
|
||||
|
||||
if(this->gTemporalSegments.contains(segment)) {
|
||||
return this->gTemporalSegments[segment];
|
||||
auto segments = this->gConfig.segment;
|
||||
|
||||
if(segments.temporal.contains(segment)) {
|
||||
return segments.temporal[segment];
|
||||
}
|
||||
|
||||
if(segment >= this->gSegments.size()) {
|
||||
return std::nullopt;
|
||||
if(segments.local.contains(segment)) {
|
||||
return segments.local[segment];
|
||||
}
|
||||
|
||||
return this->gSegments[segment];
|
||||
if(segments.global.contains(segment)) {
|
||||
return segments.global[segment];
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::tuple<std::string, YAML::Node>> Companion::GetNodeByAddr(const uint32_t addr){
|
||||
|
||||
+45
-18
@@ -27,47 +27,74 @@ enum class GBIMinorVersion {
|
||||
SM64
|
||||
};
|
||||
|
||||
struct SegmentConfig {
|
||||
std::unordered_map<uint32_t, uint32_t> global;
|
||||
std::unordered_map<uint32_t, uint32_t> local;
|
||||
std::unordered_map<uint32_t, uint32_t> temporal;
|
||||
};
|
||||
|
||||
struct GBIConfig {
|
||||
GBIVersion version = GBIVersion::f3d;
|
||||
GBIMinorVersion subversion = GBIMinorVersion::None;
|
||||
};
|
||||
|
||||
struct TorchConfig {
|
||||
GBIConfig gbi;
|
||||
SegmentConfig segment;
|
||||
std::string outputPath;
|
||||
ExportType exporterType;
|
||||
bool otrMode;
|
||||
bool debug;
|
||||
};
|
||||
|
||||
class Companion {
|
||||
public:
|
||||
static Companion* Instance;
|
||||
explicit Companion(std::filesystem::path rom, bool otr, bool debug) : gRomPath(std::move(rom)), gOTRMode(otr), gIsDebug(debug) {}
|
||||
|
||||
explicit Companion(std::filesystem::path rom, const bool otr, const bool debug) : gRomPath(std::move(rom)), gCartridge(nullptr) {
|
||||
this->gConfig.otrMode = otr;
|
||||
this->gConfig.debug = debug;
|
||||
}
|
||||
|
||||
void Init(ExportType type);
|
||||
void Process();
|
||||
bool IsOTRMode() { return this->gOTRMode; }
|
||||
bool IsDebug() { return this->gIsDebug; }
|
||||
N64::Cartridge* GetCartridge() { return this->gCartridge; }
|
||||
|
||||
bool IsOTRMode() const { return this->gConfig.otrMode; }
|
||||
bool IsDebug() const { return this->gConfig.debug; }
|
||||
|
||||
N64::Cartridge* GetCartridge() const { return this->gCartridge.get(); }
|
||||
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::string GetOutputPath() { return this->gConfig.outputPath; }
|
||||
|
||||
GBIVersion GetGBIVersion() const { return this->gConfig.gbi.version; }
|
||||
GBIMinorVersion GetGBIMinorVersion() const { return this->gConfig.gbi.subversion; }
|
||||
|
||||
std::optional<std::uint32_t> GetSegmentedAddr(uint8_t segment) const;
|
||||
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;
|
||||
|
||||
TorchConfig& GetConfig() { return this->gConfig; }
|
||||
|
||||
std::optional<std::tuple<std::string, YAML::Node>> RegisterAsset(const std::string& name, YAML::Node& node);
|
||||
private:
|
||||
bool gOTRMode = false;
|
||||
bool gIsDebug = false;
|
||||
GBIVersion gGBIVersion = GBIVersion::f3d;
|
||||
GBIMinorVersion gGBIMinorVersion = GBIMinorVersion::None;
|
||||
std::string gOutputPath;
|
||||
std::string gCurrentFile;
|
||||
ExportType gExporterType;
|
||||
TorchConfig gConfig;
|
||||
fs::path gCurrentDirectory;
|
||||
N64::Cartridge* gCartridge;
|
||||
std::vector<uint8_t> gRomData;
|
||||
std::filesystem::path gRomPath;
|
||||
std::vector<uint32_t> gSegments;
|
||||
std::unordered_map<uint32_t, uint32_t> gTemporalSegments;
|
||||
std::shared_ptr<N64::Cartridge> gCartridge;
|
||||
|
||||
// Temporal Variables
|
||||
std::string gCurrentFile;
|
||||
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 ParseCurrentFileConfig(YAML::Node node);
|
||||
void RegisterFactory(const std::string& type, const std::shared_ptr<BaseFactory>& factory);
|
||||
void ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary);
|
||||
};
|
||||
|
||||
@@ -92,6 +92,10 @@ std::optional<std::shared_ptr<IParsedData>> BankFactory::parse(std::vector<uint8
|
||||
auto banks = AudioManager::Instance->get_banks();
|
||||
auto bankId = data["id"].as<uint32_t>();
|
||||
|
||||
if(AudioManager::Instance == nullptr){
|
||||
throw std::runtime_error("AudioManager not initialized");
|
||||
}
|
||||
|
||||
auto gSampleTable = Companion::Instance->GetCartridge()->GetCountry() == N64::CountryCode::Japan ? gJPSampleTable : gUSSampleTable;
|
||||
return std::make_shared<BankData>(banks[bankId], bankId, gSampleTable);
|
||||
}
|
||||
@@ -15,8 +15,9 @@
|
||||
|
||||
#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 SEGMENT_OFFSET(a) ((uint32_t)(a) & 0x00FFFFFF)
|
||||
#define SEGMENT_NUMBER(x) (((uint32_t)(x) >> 24) & 0xFF)
|
||||
#define IS_SEGMENTED(x) (((x) & 0x01000000 > 0) && (SEGMENT_NUMBER(x) < 0x20))
|
||||
|
||||
#define tab "\t"
|
||||
#define fourSpaceTab " "
|
||||
|
||||
@@ -37,7 +37,8 @@ std::unordered_map<std::string, uint8_t> gF3DExTable = {
|
||||
};
|
||||
|
||||
std::unordered_map<GBIVersion, std::unordered_map<std::string, uint8_t>> gGBITable = {
|
||||
{ GBIVersion::f3d, gF3DTable }
|
||||
{ GBIVersion::f3d, gF3DTable },
|
||||
{ GBIVersion::f3dex, gF3DExTable },
|
||||
};
|
||||
|
||||
#define GBI(cmd) gGBITable[Companion::Instance->GetGBIVersion()][#cmd]
|
||||
@@ -257,14 +258,33 @@ void DListBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedDat
|
||||
writer.Finish(write);
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
|
||||
std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint8_t>& raw_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);
|
||||
auto offset = node["offset"].as<uint32_t>();
|
||||
const bool isCompressed = node["mio0"] ? true : false;
|
||||
|
||||
LUS::BinaryReader reader(decoded.data(), decoded.size());
|
||||
std::vector<uint8_t> buffer;
|
||||
|
||||
if(IS_SEGMENTED(offset)){
|
||||
const auto segment = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(offset));
|
||||
|
||||
if(!segment.has_value()) {
|
||||
SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(offset));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
offset = segment.value() + SEGMENT_OFFSET(offset);
|
||||
}
|
||||
|
||||
if(isCompressed){
|
||||
const auto mio0 = node["mio0"].as<uint32_t>();
|
||||
buffer = MIO0Decoder::Decode(raw_buffer, mio0);
|
||||
} else {
|
||||
buffer = raw_buffer;
|
||||
}
|
||||
|
||||
LUS::BinaryReader reader(buffer.data(), buffer.size());
|
||||
reader.SetEndianness(LUS::Endianness::Big);
|
||||
reader.Seek(offset, LUS::SeekOffsetType::Start);
|
||||
|
||||
@@ -282,25 +302,53 @@ std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint
|
||||
}
|
||||
|
||||
if(opcode == GBI(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()) {
|
||||
std::optional<uint32_t> segment;
|
||||
uint32_t ptr;
|
||||
|
||||
if(IS_SEGMENTED(w1)){
|
||||
segment = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1));
|
||||
|
||||
if(!segment.has_value()) {
|
||||
SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1));
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr = SEGMENT_OFFSET(w1);
|
||||
} else {
|
||||
ptr = w1;
|
||||
}
|
||||
|
||||
auto dec = Companion::Instance->GetNodeByAddr(w1);
|
||||
|
||||
if(!dec.has_value()){
|
||||
SPDLOG_INFO("Addr to Display list command at 0x{:X} not in yaml, autogenerating it", w1);
|
||||
|
||||
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_" + Torch::to_hex(addr.value() + w1, false));
|
||||
|
||||
std::string output;
|
||||
YAML::Node dl;
|
||||
|
||||
if(isCompressed){
|
||||
dl["mio0"] = segment.has_value() ? segment.value() : ptr;
|
||||
if(segment.has_value()) {
|
||||
SPDLOG_INFO("Found compressed and segmented display list at 0x{:X}", ptr);
|
||||
output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_dl_" + Torch::to_hex(segment.value() + w1, false));
|
||||
} else {
|
||||
SPDLOG_INFO("Found compressed display list at 0x{:X}", ptr);
|
||||
output = Companion::Instance->NormalizeAsset("dl_" + Torch::to_hex(w1, false));
|
||||
}
|
||||
} else {
|
||||
SPDLOG_INFO("Found display list at 0x{:X}", ptr);
|
||||
output = Companion::Instance->NormalizeAsset("dl_" + Torch::to_hex(w1, false));
|
||||
}
|
||||
|
||||
|
||||
dl["type"] = "GFX";
|
||||
dl["mio0"] = addr.value();
|
||||
dl["offset"] = ptr;
|
||||
dl["symbol"] = output;
|
||||
|
||||
auto result = factory->parse(rom, dl);
|
||||
|
||||
if(!result.has_value()){
|
||||
@@ -376,7 +424,21 @@ std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t ptr = SEGMENT_OFFSET(w1);
|
||||
std::optional<uint32_t> segment;
|
||||
uint32_t ptr;
|
||||
|
||||
if(IS_SEGMENTED(w1)){
|
||||
segment = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1));
|
||||
|
||||
if(!segment.has_value()) {
|
||||
SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1));
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr = SEGMENT_OFFSET(w1);
|
||||
} else {
|
||||
ptr = 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);
|
||||
@@ -388,10 +450,25 @@ std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint
|
||||
|
||||
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_" + Torch::to_hex(addr.value() + w1, false));
|
||||
|
||||
std::string output;
|
||||
YAML::Node vtx;
|
||||
|
||||
if(isCompressed){
|
||||
vtx["mio0"] = segment.has_value() ? segment.value() : ptr;
|
||||
if(segment.has_value()) {
|
||||
SPDLOG_INFO("Found compressed and segmented display list at 0x{:X}", ptr);
|
||||
output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_vtx_" + Torch::to_hex(segment.value() + w1, false));
|
||||
} else {
|
||||
SPDLOG_INFO("Found compressed display list at 0x{:X}", ptr);
|
||||
output = Companion::Instance->NormalizeAsset("vtx_" + Torch::to_hex(w1, false));
|
||||
}
|
||||
} else {
|
||||
SPDLOG_INFO("Found display list at 0x{:X}", ptr);
|
||||
output = Companion::Instance->NormalizeAsset("dl_" + Torch::to_hex(w1, false));
|
||||
}
|
||||
|
||||
vtx["type"] = "VTX";
|
||||
vtx["mio0"] = addr.value();
|
||||
vtx["offset"] = ptr;
|
||||
vtx["count"] = nvtx;
|
||||
vtx["symbol"] = output;
|
||||
|
||||
@@ -71,8 +71,8 @@ std::optional<std::shared_ptr<IParsedData>> LightsFactory::parse(std::vector<uin
|
||||
auto mio0 = node["mio0"].as<size_t>();
|
||||
auto offset = node["offset"].as<uint32_t>();
|
||||
|
||||
auto decoded = MIO0Decoder::Decode(buffer, mio0);
|
||||
LUS::BinaryReader reader(decoded.data() + offset, sizeof(Lights1Raw));
|
||||
auto decoded = MIO0Decoder::Decode(buffer, offset);
|
||||
LUS::BinaryReader reader(decoded.data() + mio0, sizeof(Lights1Raw));
|
||||
|
||||
reader.SetEndianness(LUS::Endianness::Big);
|
||||
Lights1Raw lights;
|
||||
|
||||
@@ -6,31 +6,38 @@ void SampleBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedDa
|
||||
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);
|
||||
writer.Write(sample.loop.start);
|
||||
writer.Write(sample.loop.end);
|
||||
writer.Write(sample.loop.count);
|
||||
writer.Write(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));
|
||||
writer.Write(static_cast<uint32_t>(state.size()));
|
||||
writer.Write(reinterpret_cast<char*>(state.data()), state.size() * sizeof(int16_t));
|
||||
} else {
|
||||
writer.Write((uint32_t) 0);
|
||||
writer.Write(static_cast<uint32_t>(0));
|
||||
}
|
||||
|
||||
writer.Write((uint32_t) sample.book.order);
|
||||
writer.Write((uint32_t) sample.book.npredictors);
|
||||
writer.Write(sample.book.order);
|
||||
writer.Write(sample.book.npredictors);
|
||||
|
||||
writer.Write(static_cast<uint32_t>(sample.book.table.size()));
|
||||
writer.Write(reinterpret_cast<char*>(sample.book.table.data()), sample.book.table.size() * sizeof(int16_t));
|
||||
|
||||
writer.Write(static_cast<int32_t>(sample.data.size()));
|
||||
writer.Write(reinterpret_cast<char*>(sample.data.data()), sample.data.size());
|
||||
|
||||
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.Finish(write);
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<IParsedData>> SampleFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
|
||||
auto id = data["id"].as<int32_t>();
|
||||
const auto id = data["id"].as<int32_t>();
|
||||
if(AudioManager::Instance == nullptr){
|
||||
throw std::runtime_error("AudioManager not initialized");
|
||||
}
|
||||
AudioBankSample entry = AudioManager::Instance->get_aifc(id);
|
||||
return std::make_shared<SampleData>(entry);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "BaseFactory.h"
|
||||
#include "audio/AudioManager.h"
|
||||
|
||||
@@ -7,7 +9,7 @@ class SampleData : public IParsedData {
|
||||
public:
|
||||
AudioBankSample mSample;
|
||||
|
||||
SampleData(AudioBankSample sample) : mSample(sample) {}
|
||||
explicit SampleData(AudioBankSample sample) : mSample(std::move(sample)) {}
|
||||
};
|
||||
|
||||
class SampleBinaryExporter : public BaseExporter {
|
||||
@@ -17,7 +19,8 @@ class SampleBinaryExporter : public BaseExporter {
|
||||
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 {
|
||||
|
||||
std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
|
||||
return {
|
||||
REGISTER(Binary, SampleBinaryExporter)
|
||||
};
|
||||
|
||||
@@ -17,14 +17,14 @@ static const std::unordered_map <std::string, TextureType> gTextureTypes = {
|
||||
{ "IA16", TextureType::GrayscaleAlpha16bpp },
|
||||
};
|
||||
|
||||
uint8_t* alloc_ia8_text_from_i1(uint16_t *in, int16_t width, int16_t height) {
|
||||
std::vector<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;
|
||||
auto out = new uint8_t[width * height];
|
||||
const auto out = new uint8_t[width * height];
|
||||
|
||||
for (inPos = 0; inPos < (width * height) / 16; inPos++) {
|
||||
bitMask = 0x8000;
|
||||
for (int32_t inPos = 0; inPos < (width * height) / 16; inPos++) {
|
||||
uint16_t bitMask = 0x8000;
|
||||
|
||||
while (bitMask != 0) {
|
||||
if (BSWAP16(in[inPos]) & bitMask) {
|
||||
@@ -38,7 +38,10 @@ uint8_t* alloc_ia8_text_from_i1(uint16_t *in, int16_t width, int16_t height) {
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
auto result = std::vector(out, out + width * height);
|
||||
delete[] out;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextureHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
|
||||
@@ -126,16 +129,16 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
|
||||
std::vector<uint8_t> result;
|
||||
|
||||
if(node["mio0"]){
|
||||
auto decoded = MIO0Decoder::Decode(buffer, offset);
|
||||
auto mio0 = node["mio0"].as<size_t>();
|
||||
auto decoded = MIO0Decoder::Decode(buffer, mio0);
|
||||
auto data = decoded.data() + offset;
|
||||
auto data = decoded.data() + mio0;
|
||||
|
||||
if(type == TextureType::GrayscaleAlpha1bpp){
|
||||
auto ia8 = alloc_ia8_text_from_i1((uint16_t*) data, 8, 16);
|
||||
result = std::vector(ia8, ia8 + 8 * 16);
|
||||
delete[] ia8;
|
||||
result = alloc_ia8_text_from_i1((uint16_t*) data, 8, 16);
|
||||
} else {
|
||||
result = std::vector(data, data + size);
|
||||
}
|
||||
|
||||
result = std::vector(data, data + size);
|
||||
} else {
|
||||
result = std::vector(buffer.data() + offset, buffer.data() + offset + size);
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ std::optional<std::shared_ptr<IParsedData>> VtxFactory::parse(std::vector<uint8_
|
||||
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) );
|
||||
auto decoded = MIO0Decoder::Decode(buffer, offset);
|
||||
LUS::BinaryReader reader(decoded.data() + mio0, count * sizeof(VtxRaw) );
|
||||
|
||||
reader.SetEndianness(LUS::Endianness::Big);
|
||||
std::vector<VtxRaw> vertices;
|
||||
|
||||
@@ -62,8 +62,8 @@ std::optional<std::shared_ptr<IParsedData>> MK64::WaypointFactory::parse(std::ve
|
||||
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) );
|
||||
auto decoded = MIO0Decoder::Decode(buffer, offset);
|
||||
LUS::BinaryReader reader(decoded.data() + mio0, count * sizeof(MK64::TrackWaypoint) );
|
||||
|
||||
reader.SetEndianness(LUS::Endianness::Big);
|
||||
std::vector<MK64::TrackWaypoint> waypoints;
|
||||
|
||||
@@ -7,22 +7,22 @@ void SM64::AnimationBinaryExporter::Export(std::ostream &write, std::shared_ptr<
|
||||
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(anim->mFlags);
|
||||
writer.Write(anim->mAnimYTransDivisor);
|
||||
writer.Write(anim->mStartFrame);
|
||||
writer.Write(anim->mLoopStart);
|
||||
writer.Write(anim->mLoopEnd);
|
||||
writer.Write(anim->mUnusedBoneCount);
|
||||
writer.Write(static_cast<uint64_t>(anim->mLength));
|
||||
|
||||
writer.Write((uint32_t) anim->mIndices.size());
|
||||
for (auto& index : anim->mIndices) {
|
||||
writer.Write((int16_t) index);
|
||||
writer.Write(static_cast<uint32_t>(anim->mIndices.size()));
|
||||
for (const auto& index : anim->mIndices) {
|
||||
writer.Write(index);
|
||||
}
|
||||
|
||||
writer.Write((uint32_t) anim->mEntries.size());
|
||||
for (auto& entry : anim->mEntries) {
|
||||
writer.Write((uint16_t) entry);
|
||||
writer.Write(static_cast<uint32_t>(anim->mEntries.size()));
|
||||
for (const auto& entry : anim->mEntries) {
|
||||
writer.Write(entry);
|
||||
}
|
||||
|
||||
writer.Finish(write);
|
||||
@@ -33,7 +33,7 @@ std::optional<std::shared_ptr<IParsedData>> SM64::AnimationFactory::parse(std::v
|
||||
auto valuesNode = node["values"];
|
||||
auto indexNode = node["indices"];
|
||||
|
||||
LUS::BinaryReader header((char*) buffer.data() + headerNode["offset"].as<uint32_t>(), headerNode["size"].as<uint32_t>());
|
||||
LUS::BinaryReader header(reinterpret_cast<char *>(buffer.data()) + headerNode["offset"].as<uint32_t>(), headerNode["size"].as<uint32_t>());
|
||||
header.SetEndianness(LUS::Endianness::Big);
|
||||
|
||||
auto flags = header.ReadInt16();
|
||||
@@ -46,10 +46,10 @@ std::optional<std::shared_ptr<IParsedData>> SM64::AnimationFactory::parse(std::v
|
||||
header.ReadUInt32();
|
||||
auto length = header.ReadUInt32();
|
||||
|
||||
LUS::BinaryReader indices((char*) buffer.data() + indexNode["offset"].as<uint32_t>(), indexNode["size"].as<uint32_t>());
|
||||
LUS::BinaryReader indices(reinterpret_cast<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;
|
||||
size_t indexLength = indexNode["size"].as<uint32_t>() / sizeof(int16_t);
|
||||
std::vector<int16_t> indicesData;
|
||||
for (size_t i = 0; i < indexLength; i++) {
|
||||
indicesData.push_back(indices.ReadInt16());
|
||||
}
|
||||
@@ -70,5 +70,5 @@ std::optional<std::shared_ptr<IParsedData>> SM64::AnimationFactory::parse(std::v
|
||||
SPDLOG_INFO("Unused Bone Count: {}", unusedBoneCount);
|
||||
SPDLOG_INFO("Length: {}", length);
|
||||
|
||||
return std::make_shared<AnimationData>(flags, animYTransDivisor, startFrame, loopStart, loopEnd, unusedBoneCount, length, valuesData, indicesData);
|
||||
return std::make_shared<AnimationData>(flags, animYTransDivisor, startFrame, loopStart, loopEnd, unusedBoneCount, length, indicesData, valuesData);
|
||||
}
|
||||
@@ -12,10 +12,10 @@ public:
|
||||
int16_t mLoopEnd;
|
||||
int16_t mUnusedBoneCount;
|
||||
int16_t mLength;
|
||||
std::vector<uint16_t> mIndices;
|
||||
std::vector<int16_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) {}
|
||||
AnimationData(int16_t flags, int16_t animYTransDivisor, int16_t startFrame, int16_t loopStart, int16_t loopEnd, int16_t unusedBoneCount, int16_t length, std::vector<int16_t> indices, std::vector<uint16_t> entries) : mFlags(flags), mAnimYTransDivisor(animYTransDivisor), mStartFrame(startFrame), mLoopStart(loopStart), mLoopEnd(loopEnd), mUnusedBoneCount(unusedBoneCount), mLength(length), mIndices(std::move(indices)), mEntries(std::move(entries)) {}
|
||||
};
|
||||
|
||||
class AnimationBinaryExporter : public BaseExporter {
|
||||
|
||||
@@ -21,11 +21,11 @@ std::optional<std::shared_ptr<IParsedData>> SM64::DialogFactory::parse(std::vect
|
||||
auto offset = node["offset"].as<int32_t>();
|
||||
auto mio0 = node["mio0"].as<size_t>();
|
||||
|
||||
auto decoded = MIO0Decoder::Decode(buffer, mio0);
|
||||
auto decoded = MIO0Decoder::Decode(buffer, offset);
|
||||
auto bytes = (uint8_t*) decoded.data();
|
||||
LUS::BinaryReader reader(bytes, decoded.size());
|
||||
reader.SetEndianness(LUS::Endianness::Big);
|
||||
reader.Seek(offset, LUS::SeekOffsetType::Start);
|
||||
reader.Seek(mio0, LUS::SeekOffsetType::Start);
|
||||
|
||||
auto unused = reader.ReadUInt32();
|
||||
auto linesPerBox = reader.ReadUByte();
|
||||
|
||||
@@ -16,11 +16,11 @@ std::optional<std::shared_ptr<IParsedData>> SM64::TextFactory::parse(std::vector
|
||||
auto mio0 = data["mio0"].as<size_t>();
|
||||
|
||||
std::vector<uint8_t> text;
|
||||
auto decoded = MIO0Decoder::Decode(buffer, mio0);
|
||||
auto decoded = MIO0Decoder::Decode(buffer, offset);
|
||||
auto bytes = (uint8_t*) decoded.data();
|
||||
|
||||
while(bytes[offset] != 0xFF){
|
||||
auto c = bytes[offset++];
|
||||
while(bytes[mio0] != 0xFF){
|
||||
auto c = bytes[mio0++];
|
||||
text.push_back(c);
|
||||
}
|
||||
text.push_back(0xFF);
|
||||
|
||||
Reference in New Issue
Block a user