From 22e3cdfbd09e61b0f35aa620db356ad2e79fe34b Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Tue, 21 Oct 2025 23:14:32 -0600 Subject: [PATCH] Implemented EDL decompression and duke nukem map factories --- CMakeLists.txt | 9 +- lib/libedl/edl.c | 503 +++++++++++++++++++++ lib/libedl/edl.h | 49 ++ src/Companion.cpp | 31 +- src/Companion.h | 1 + src/factories/BaseFactory.h | 1 + src/factories/CompressedTextureFactory.cpp | 5 +- src/factories/ResourceType.h | 9 +- src/factories/dkzh/MapInfoFactory.cpp | 189 ++++++++ src/factories/dkzh/MapInfoFactory.h | 56 +++ src/factories/dkzh/SectorTypeFactory.cpp | 155 +++++++ src/factories/dkzh/SectorTypeFactory.h | 62 +++ src/factories/dkzh/SpriteTypeFactory.cpp | 145 ++++++ src/factories/dkzh/SpriteTypeFactory.h | 60 +++ src/factories/dkzh/VertexFactory.cpp | 174 +++++++ src/factories/dkzh/VertexFactory.h | 43 ++ src/factories/dkzh/WallTypeFactory.cpp | 146 ++++++ src/factories/dkzh/WallTypeFactory.h | 60 +++ src/utils/Decompressor.cpp | 82 ++-- src/utils/Decompressor.h | 9 +- src/utils/TorchUtils.h | 25 +- 21 files changed, 1765 insertions(+), 49 deletions(-) create mode 100644 lib/libedl/edl.c create mode 100644 lib/libedl/edl.h create mode 100644 src/factories/dkzh/MapInfoFactory.cpp create mode 100644 src/factories/dkzh/MapInfoFactory.h create mode 100644 src/factories/dkzh/SectorTypeFactory.cpp create mode 100644 src/factories/dkzh/SectorTypeFactory.h create mode 100644 src/factories/dkzh/SpriteTypeFactory.cpp create mode 100644 src/factories/dkzh/SpriteTypeFactory.h create mode 100644 src/factories/dkzh/VertexFactory.cpp create mode 100644 src/factories/dkzh/VertexFactory.h create mode 100644 src/factories/dkzh/WallTypeFactory.cpp create mode 100644 src/factories/dkzh/WallTypeFactory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 05ebc206..9197fafd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ option(BUILD_SF64 "Build with Star Fox 64 support" ON) option(BUILD_FZERO "Build with F-Zero X support" ON) option(BUILD_MARIO_ARTIST "Build with Mario Artist support" ON) option(BUILD_NAUDIO "Build with NAudio support" ON) +option(BUILD_DKZH "Build with Duke Nukem Zero Hour support" ON) if(EMSCRIPTEN) set(BUILD_SM64 OFF) # TODO: This is broken for some reason @@ -67,7 +68,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) file(GLOB_RECURSE CXX_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/**/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/lib/strhash64/*.cpp) -file(GLOB C_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/**/*.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/libmio0/*.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/libyay0/*.c) +file(GLOB C_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/**/*.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/libmio0/*.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/libedl/*.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/libyay0/*.c) set(SRC_DIR ${CXX_FILES} ${C_FILES} ${LGFXD_FILES}) if(BUILD_SM64) @@ -106,6 +107,12 @@ else() list(FILTER SRC_DIR EXCLUDE REGEX "${CMAKE_CURRENT_SOURCE_DIR}/src/factories/naudio/*") endif() +if(BUILD_DKZH) + add_definitions(-DDKZH_SUPPORT) +else() + list(FILTER SRC_DIR EXCLUDE REGEX "${CMAKE_CURRENT_SOURCE_DIR}/src/factories/dkzh/*") +endif() + if(ENABLE_ASAN) add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) diff --git a/lib/libedl/edl.c b/lib/libedl/edl.c new file mode 100644 index 00000000..a32f2759 --- /dev/null +++ b/lib/libedl/edl.c @@ -0,0 +1,503 @@ +#include "edl.h" +#include + +/*data*/ + +/*800E0B40*/ +static uint8_t _table1[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x14, 0x18, 0x1C, + 0x20, 0x28, 0x30, 0x38, 0x40, 0x50, 0x60, 0x70, 0x80, 0xA0, 0xC0, 0xE0, 0xFF, 0x00, 0x00, 0x00, +}; + +/*800E0B60*/ +static uint8_t _table2[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0, +}; + +/*800E0B80*/ +static uint16_t _table3[30] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0006, 0x0008, 0x000C, 0x0010, 0x0018, 0x0020, 0x0030, 0x0040, 0x0060, 0x0080, + 0x00C0, 0x0100, 0x0180, 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0C00, 0x1000, 0x1800, 0x2000, 0x3000, 0x4000, 0x6000, +}; + +/*800E0BBC*/ +static int8_t _table4[36] = { + 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, 0x6, 0x6, 0x7, 0x7, + 0x8, 0x8, 0x9, 0x9, 0xA, 0xA, 0xB, 0xB, 0xC, 0xC, 0xD, 0xD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +/*comm*/ +/*8012CD90*/ uint32_t _what[288] ALIGNED(16); +/*80168820*/ uint32_t _samp[287] ALIGNED(16); +/*801978A0*/ uint32_t _when[288] ALIGNED(16); + +/*.text*/ +static void _parseEDLheader(EDLInfo *info); +static int32_t _swap(EDLInfo *info, uint32_t value); + +/*800808D0*/ +static void _decodeEDL0(EDLInfo *info) +{ + uint8_t *src; + uint8_t *dst; + int32_t i; + int32_t size; + + dst = info->dst; + i = size = info->dsize; + src = &info->src[12]; + + if ((src >= dst) || (dst >= &src[size])) + { + for (i = (size-1); i != -1; i--) + *dst++ = *src++; + } + else + { + dst = &dst[size-1]; + src = &src[size-1]; + + for (i = (size-1); i != -1; i--) + *dst-- = *src--; + } +} + +#if SYS_ENDIAN == SYS_BIG_ENDIAN +#define SWAP32(A) A +#else +#define SWAP32(A) _swap(info, A) +#endif + +#define GET_BITS_(OUTVAR,BITCOUNT,M) \ + { \ + count -= BITCOUNT; \ + if (count < 0) \ + { \ + OUTVAR = data; \ + data = next; \ + next = SWAP32(*in++); \ + OUTVAR = (OUTVAR + (data << (count + BITCOUNT))) & ((M<>= -count; \ + count += 0x20; \ + } \ + else \ + { \ + OUTVAR = data & ((M<>= BITCOUNT; \ + } \ + } + +/*TODO*/ +#define GET_BITS1(OUTVAR,BITCOUNT) GET_BITS_(OUTVAR,BITCOUNT,1) +#define GET_BITS2(OUTVAR,BITCOUNT) GET_BITS_(OUTVAR,BITCOUNT,one) + +/*80080968*/ +static void _decodeEDL1(EDLInfo *info) +{ + uint32_t number[0x21]; + uint8_t sp88[0x400]; + uint16_t large[0x600]; + uint16_t small[0x300]; + uint16_t *sp1694; + int32_t sp169C; + uint32_t sp16A4; + uint32_t sp16BC; + + uint32_t i, j, k, l, m, n, o, p, q, r, s; + int32_t count; + int32_t *in; + uint8_t *out; + uint32_t data, next; + uint8_t one; + + uint8_t *src; + uint8_t *ptr1; + uint8_t *dst; + uint8_t *ptr2; + + src = &info->src[12]; + ptr1 = &src[info->csize] - 1; + dst = info->dst; + if ((uintptr_t)ptr1 >= (uintptr_t)dst) + { + ptr2 = &info->dst[info->dsize]; + if ((uintptr_t)(ptr2 - 1) >= (uintptr_t)ptr1) + { + i = 0; + ptr1 = ptr2 - info->csize; + ptr2 = src; + do + { + *ptr1++ = *ptr2++; + i++; + } while (i < (uint32_t)info->csize); + src = &dst[info->dsize] - info->csize; + } + } + + in = (int32_t *)src; + data = SWAP32(*in++); + next = SWAP32(*in++); + out = info->dst; + + count = 32; + sp16A4 = 0; + one = 1; /*FAKEMATCH*/ + do + { + GET_BITS1(j, 1); + + /*mode 0 - */ + if (j == 0) + { + GET_BITS1(i, 15); + + for (i = i - 1; (int32_t)i != -1; i--) + { + GET_BITS1(j, 8); + *out++ = j; + } + } + else + { + /*mode 1 - tables*/ + sp169C = 1; + do + { + sp1694 = &small[0]; + r = 8; + if (sp169C-- != 0) + { + sp1694 = &large[0]; + r = 10; + } + + GET_BITS1(j, 9); + + /*construct tables*/ + s = j; + if (j != 0) + { + for (k = 1; k < ARRAY_COUNT(number); k++) + number[k] = 0; + + /*iterate to grab entries*/ + k = 0; + do + { + GET_BITS1(j, 1); + + if (j == one) + GET_BITS1(sp16A4, 4); + + _what[k] = sp16A4; + number[sp16A4]++; + k++; + } while (k < s); + + /*build occurance table*/ + number[0] = 0; + m = 0; + for (k = 1; k < 16; k++) + { + for (l = 0; l < s; l++) + { + if (_what[l] == k) + { + _when[m] = l; + m++; + } + } + } + + /*sort nibbles*/ + m = 0; + for (i = 1; i < 16; i++) + { + for (k = 1; number[i] >= k; k++) + { + _what[m] = i; + m++; + } + } + + /*generate bitsample table*/ + _what[m] = 0; + k = 0; + m = 0; + for (i = _what[0]; _what[m] != 0; i++) + { + for (p = 0; _what[m] == i; p++, m++) + { + l = k | (one << i); + k++; + _samp[m] = 0; + + do + { + _samp[m] <<= 1; + _samp[m] += (l & 1); + l >>= 1; + } while (l != one); + } + k <<= 1; + } + + k = 0; + do + { + sp88[k] = 0; + k++; + } while (k < (uint32_t)(one << r)); + + m = 0; + for (i = 1; i < r; i++) + { + for (k = 1; number[i] >= k; k++, m++) + { + j = _samp[m]; + + do + { + sp1694[j] = (_when[m] << 7) + i; + j += (one << i); + } while (j < (uint32_t)(one << r)); + } + } + + n = m; + for (; i < 16; i++) + { + for (k = 1; number[i] >= k; k++, m++) + { + j = _samp[m]; + l = _what[m]; + + if (sp88[j & ((one << r) - 1)] < l) + sp88[j & ((one << r) - 1)] = l; + } + } + + j = 0; + k = 0; + do + { + if ((sp88[k] & 0xFF) != 0) + { + if (((sp88[k] & 0xFF) - r) >= 8) + { + info->result = -8; + return; + } + sp1694[k] = (j << 7) + ((sp88[k] - r) << 4); + j += one << (sp88[k] - r); + } + k++; + } while (k < (uint32_t)(one << r)); + + if (j >= 0x200) + { + info->result = -9; + return; + } + + m = n; + i = r; + if (i < 16) + { + uint16_t *ptr; + o = one << i; + sp16BC = o - 1; + do + { + for (k = 1; number[i] >= k; k++, m++) + { + j = _samp[m]; + l = j >> r; + ptr = &sp1694[(sp1694[j & sp16BC] >> 7) + o]; + j = (sp1694[j & sp16BC] >> 4) & 7; + do + { + ptr[l] = (_when[m] << 7) + _what[m]; + l += one << (_what[m] - r); + } while (l < (uint32_t)(one << j)); + } + i++; + } while (i < 16); + } + } + } while (sp169C >= 0); + + /*write data*/ + do + { + if (count < 0xF) + q = data + (next << count); + else + q = data; + + i = large[(q & 0x3FF)]; + if ((i & 0xF) == 0) + { + uint16_t *a, *b; + j = i >> 7; + a = &large[0x400]; + b = &a[((q >> 10) & ((one << ((i >> 4) & 7)) - 1)) + j]; + i = b[0]; + } + + GET_BITS1(j, (i & 0xF)); + + i >>= 7; + if (i < 0x100) + { + *out = i; + out += 1; + } + else if (i != 0x100) + { + j = 0; + if (_table2[i-0x101] != 0) + GET_BITS2(j, _table2[i-0x101]); + + dst = _table1; /*FAKEMATCH?*/ + i = (dst[i-0x101] + j) + 3; + if (count < 0xF) + q = data + (next << count); + else + q = data; + + l = small[q & 0xFF]; + if ((l & 0xF) == 0) + { + uint16_t *a, *b; + j = l >> 7; + a = &small[0x100]; + b = &a[((q >> 8) & ((one << ((l >> 4) & 7)) - 1)) + j]; + l = b[0]; + } + + GET_BITS1(j, (l & 0xF)); + + /*pull number of bits*/ + l >>= 7; + j = 0; + if (_table4[l] != 0) + GET_BITS2(j, _table4[l]); + + l = _table3[l] + j; + ptr2 = (out - l) - 1; + if (l == 0) + { + do + { + *out++ = *ptr2; + i--; + } while (i != 0); + } + else + { + do + { + *out++ = *ptr2++; + i--; + } while (i != 0); + } + } + else + break; + } while (1); + } + + /*test EOF*/ + GET_BITS1(j, 1); + } while (j == 0); +} + +/*800813F8*/ +static void _decodeEDL(EDLInfo *info) { + _parseEDLheader(info); + if (info->result == 0) + { + switch (info->type) + { + case 0: + _decodeEDL0(info); + break; + case 1: + _decodeEDL1(info); + break; + } + } +} + +/*80081460*/ +static void _parseEDLheader(EDLInfo *info) +{ + if ((info->src[0] == 'E') && (info->src[1] == 'D') && (info->src[2] == 'L')) + { + info->file_endian = info->src[3] >> 7; + info->type = info->src[3] & 0x7F; + if (info->type < 2) + { + if (info->type >= 0) + { + info->result = 0; + info->csize = _swap(info, *(uint32_t *)&info->src[4]); + info->dsize = _swap(info, *(uint32_t *)&info->src[8]); + } + else + info->result = -4; + } + else + info->result = -4; + } + else + info->result = -3; +} + +/*8008151C*/ +static int32_t _swap(EDLInfo *info, uint32_t value) +{ + if (info->file_endian == info->sys_endian) + return value; + else + return (value >> 24) + ((value >> 8) & 0xFF00) + ((value & 0xFF00) << 8) + (value << 24); +} + +/*8008155C*/ +int32_t getEDLDecompressedSize(uint8_t *src) +{ + EDLInfo info; + + info.src = src; + info.sys_endian = SYS_ENDIAN; + _parseEDLheader(&info); + if (info.result == 0) + return info.dsize; + else + return 0; +} + +/*80081598*/ +int32_t decompressEDL(EDLInfo* info, void *src, void *dst) +{ + info->src = src; + info->sys_endian = SYS_ENDIAN; + info->dst = dst; + _decodeEDL(info); + return info->result; +} + +/*800815CC*/ +static int32_t _isEDL(uint8_t *src) +{ + EDLInfo info; + + info.sys_endian = SYS_ENDIAN; + info.src = src; + info.dst = 0; + _parseEDLheader(&info); + return info.result != -3; +} \ No newline at end of file diff --git a/lib/libedl/edl.h b/lib/libedl/edl.h new file mode 100644 index 00000000..6ab0db53 --- /dev/null +++ b/lib/libedl/edl.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +#define ALIGNED(x) __attribute__((aligned(x))) + +#define ARRAY_COUNT(arr) \ + (int32_t)(sizeof(arr) / sizeof(arr[0])) + +#define SYS_LITTLE_ENDIAN 0 +#define SYS_BIG_ENDIAN 1 + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define SYS_ENDIAN SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define SYS_ENDIAN SYS_BIG_ENDIAN +#else +#error Platform not supported +#endif + +typedef struct { + uint8_t *dst; + uint8_t *src; + int32_t csize; + int32_t dsize; + int32_t type; + int32_t sys_endian; + int32_t file_endian; + int32_t result; +} EDLInfo; + +typedef struct +{ + uint8_t *romstart; + uint8_t *romend; + uint8_t **handle; + int32_t *offset; +} edlUnkStruct1; + +#define EDL_FILE_MAX_SIZE 0x5B108 + +int32_t decompressEDL(EDLInfo* info, void *src, void *dst); +int32_t getEDLDecompressedSize(uint8_t *src); +void allocacheEDL(void *handle, int32_t size); +void edl_80081688(void *handle, int32_t id); +void edl_80081760(void *handle, int32_t id, void *dst); +uint8_t *edl_80081840(int16_t id, int16_t off); + +extern edlUnkStruct1 D_800E0D18[32]; \ No newline at end of file diff --git a/src/Companion.cpp b/src/Companion.cpp index 231b24c2..7a3625a5 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -101,6 +101,14 @@ #include "factories/naudio/v1/SequenceFactory.h" #endif +#ifdef DKZH_SUPPORT +#include "factories/dkzh/VertexFactory.h" +#include "factories/dkzh/MapInfoFactory.h" +#include "factories/dkzh/WallTypeFactory.h" +#include "factories/dkzh/SectorTypeFactory.h" +#include "factories/dkzh/SpriteTypeFactory.h" +#endif + #include "preprocess/CompTool.h" using namespace std::chrono; @@ -218,6 +226,15 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("NAUDIO:V1:ADPCM_BOOK", std::make_shared()); this->RegisterFactory("NAUDIO:V1:SEQUENCE", std::make_shared()); #endif + +#ifdef DKZH_SUPPORT + this->RegisterFactory("DKZH:VERTEX", std::make_shared()); + this->RegisterFactory("DKZH:MAP_INFO_TABLE", std::make_shared()); + this->RegisterFactory("DKZH:WALL_TYPE_TABLE", std::make_shared()); + this->RegisterFactory("DKZH:SECTOR_TYPE_TABLE", std::make_shared()); + this->RegisterFactory("DKZH:SPRITE_TYPE_TABLE", std::make_shared()); +#endif + #ifndef __EMSCRIPTEN__ // We call this manually this->Process(); #endif @@ -333,7 +350,7 @@ std::optional Companion::ParseNode(YAML::Node& node, std::strin SPDLOG_INFO("Processed {}", name); return ParseResultData { - name, type, node, result + name, type, YAML::Clone(node), result }; } @@ -774,6 +791,7 @@ void Companion::ProcessFile(YAML::Node root) { result.name, result.node["offset"].as(), alignment, + GetNode(result.node, "out"), stream.str(), GetNode(result.node, "comment"), std::nullopt @@ -785,6 +803,7 @@ void Companion::ProcessFile(YAML::Node root) { result.name, result.node["offset"].as(), alignment, + GetNode(result.node, "out"), stream.str(), GetNode(result.node, "comment"), std::get(endptr.value()) @@ -796,6 +815,7 @@ void Companion::ProcessFile(YAML::Node root) { result.name, oentry.start, alignment, + GetNode(result.node, "out"), stream.str(), GetNode(result.node, "comment"), oentry.end @@ -890,7 +910,7 @@ void Companion::ProcessFile(YAML::Node root) { stream << "// 0x" << std::hex << std::uppercase << ASSET_PTR(result.endptr.value()) << "\n\n"; } - if(hasSize && i < entries.size() - 1 && this->gConfig.exporterType == ExportType::Code && !this->gIndividualIncludes){ + if(hasSize && i < entries.size() - 1 && this->gConfig.exporterType == ExportType::Code && !this->gIndividualIncludes) { int32_t startptr = ASSET_PTR(result.endptr.value()); int32_t end = ASSET_PTR(entries[i + 1].addr); @@ -925,7 +945,7 @@ void Companion::ProcessFile(YAML::Node root) { if (this->gConfig.exporterType == ExportType::Code && this->gIndividualIncludes) { fs::path outinc = fs::path(this->gConfig.outputPath) / this->gCurrentDirectory.parent_path() / - fs::relative(fs::path(result.name + ".inc.c"), this->gCurrentDirectory.parent_path()); + fs::relative(fs::path(result.out.value_or(result.name + ".inc.c")), this->gCurrentDirectory.parent_path()); if(!exists(outinc.parent_path())){ create_directories(outinc.parent_path()); @@ -933,9 +953,10 @@ void Companion::ProcessFile(YAML::Node root) { std::ofstream file(outinc, std::ios::binary); - if(!this->gFileHeader.empty()) { + if(!this->gFileHeader.empty() && file.tellp() == 0) { file << this->gFileHeader << std::endl; } + file << stream.str(); stream.str(""); stream.seekp(0); @@ -1393,7 +1414,7 @@ std::optional> Companion::RegisterAsset(cons void Companion::RegisterFactory(const std::string& type, const std::shared_ptr& factory) { this->gFactories[type] = factory; - SPDLOG_INFO("Registered factory for {}", type); + SPDLOG_DEBUG("Registered factory for {}", type); } std::optional> Companion::GetFactory(const std::string &type) { diff --git a/src/Companion.h b/src/Companion.h index 95da2a48..5acc161e 100644 --- a/src/Companion.h +++ b/src/Companion.h @@ -69,6 +69,7 @@ struct WriteEntry { std::string name; uint32_t addr; uint32_t alignment; + std::optional out; std::string buffer; std::optional comment; std::optional endptr; diff --git a/src/factories/BaseFactory.h b/src/factories/BaseFactory.h index 3fdb1cf5..3481fbfa 100644 --- a/src/factories/BaseFactory.h +++ b/src/factories/BaseFactory.h @@ -27,6 +27,7 @@ namespace fs = std::filesystem; #define ASSET_PTR(x) (IS_SEGMENTED(x) ? SEGMENT_OFFSET(x) : (x)) #define tab_t "\t" +#define dtab_t "\t\t" #define fourSpaceTab " " struct OffsetEntry { diff --git a/src/factories/CompressedTextureFactory.cpp b/src/factories/CompressedTextureFactory.cpp index 34ccc61a..175ac33c 100644 --- a/src/factories/CompressedTextureFactory.cpp +++ b/src/factories/CompressedTextureFactory.cpp @@ -35,6 +35,7 @@ static const std::unordered_map sCompressionTypes { "YAY0", CompressionType::YAY0 }, { "YAY1", CompressionType::YAY1 }, { "YAZ0", CompressionType::YAZ0 }, + { "EDL" , CompressionType::EDL }, }; ExportResult CompressedTextureHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { @@ -356,6 +357,8 @@ std::string getcomptype(CompressionType type) { return "YAY1"; case CompressionType::YAZ0: return "YAZ0"; + case CompressionType::EDL: + return "EDL"; default: break; } @@ -472,7 +475,7 @@ std::optional> CompressedTextureFactory::parse_modd if (!sCompressionTypes.contains(compression)) { SPDLOG_ERROR("Compresed Texture entry at {:X} in yaml missing compression type\n\ Please add one of the following compression types\n\ - MIO0, YAY0, YAY1, YAZ0 (Unsupported)", offset); + MIO0, YAY0, YAY1, YAZ0 (Unsupported), EDL (Unsupported)", offset); return std::nullopt; } compressionType = sCompressionTypes.at(compression); diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h index ae481386..febbba0f 100644 --- a/src/factories/ResourceType.h +++ b/src/factories/ResourceType.h @@ -77,6 +77,13 @@ enum class ResourceType { AdpcmLoop = 0x4150434C, // APCL AdpcmBook = 0x41504342, // APCB Envelope = 0x45564C50, // EVLP - AudioTable = 0x4154424C // ATBL + AudioTable = 0x4154424C, // ATBL + + // DKZH + CVertex = 0x43565254, // CVRT + MapInfo = 0x4D415049, // MAPI + SectorType = 0x53454354, // SECT + SpriteType = 0x53505254, // SPRT + WallType = 0x57414C4C, // WALL }; } // namespace Torch diff --git a/src/factories/dkzh/MapInfoFactory.cpp b/src/factories/dkzh/MapInfoFactory.cpp new file mode 100644 index 00000000..60c5ba94 --- /dev/null +++ b/src/factories/dkzh/MapInfoFactory.cpp @@ -0,0 +1,189 @@ +#include "MapInfoFactory.h" +#include "Companion.h" +#include "utils/Decompressor.h" +#include "libedl/edl.h" +#include +#include + +#define HEX(c) (c < 0 ? "-0x" : "0x") << std::hex << std::setfill('0') << std::abs(c) << std::dec +#define U_HEX(c) "0x" << std::hex << std::setfill('0') << c << std::dec + +ExportResult MapInfoHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern MapInfo " << symbol << "[];\n"; + + return std::nullopt; +} + +ExportResult MapInfoCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto symbol = GetSafeNode(node, "symbol", entryName); + auto offset = GetSafeNode(node, "offset"); + auto data = std::static_pointer_cast(raw)->list; + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "MapInfo " << symbol << "[] = {\n"; + + for (int i = 0; i < data.size(); i++) { + int id = i + 1; + write << tab_t << "{" << "\n"; + write << dtab_t << "maps_map" << id << "_ROM_START, // "<< U_HEX(data[i].rom_start) << "\n"; + write << dtab_t << "maps_map" << id << "_ROM_END, // "<< U_HEX(data[i].rom_end) << "\n"; + write << dtab_t << "(s32)maps_map" << id << "_sectors_bin, // "<< U_HEX(data[i].sector_offset) << "\n"; + write << dtab_t << "(s32)maps_map" << id << "_walls_bin, // "<< U_HEX(data[i].wall_offset) << "\n"; + write << dtab_t << "(s32)maps_map" << id << "_sprites_bin, // "<< U_HEX(data[i].sprite_offset) << "\n"; + write << dtab_t << HEX(data[i].sectors) << ",\n"; + write << dtab_t << HEX(data[i].sprites) << ",\n"; + write << dtab_t << HEX(data[i].walls) << ",\n"; + write << dtab_t << HEX(data[i].xpos) << ",\n"; + write << dtab_t << HEX(data[i].ypos) << ",\n"; + write << dtab_t << HEX(data[i].zpos) << ",\n"; + write << dtab_t << HEX(data[i].ang) << ",\n"; + write << dtab_t << data[i].skytop_r << ".0f,\n"; + write << dtab_t << data[i].skytop_g << ".0f,\n"; + write << dtab_t << data[i].skytop_b << ".0f,\n"; + write << dtab_t << data[i].skybottom_r << ".0f,\n"; + write << dtab_t << data[i].skybottom_g << ".0f,\n"; + write << dtab_t << data[i].skybottom_b << ".0f,\n"; + write << tab_t << "}," << "\n"; + } + write << "};\n"; + + if (Companion::Instance->IsDebug()) { + write << "// size: 0x" << std::hex << std::uppercase << (data.size() * sizeof(MapInfo)) << "\n"; + } + + return offset + data.size(); +} + +ExportResult MapInfoBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast(raw)->list; + + WriteHeader(writer, Torch::ResourceType::MapInfo, 0); + writer.Write((uint32_t) data.size()); + + for (const auto &item: data) { + writer.Write(item.rom_start); + writer.Write(item.rom_end); + writer.Write(item.sector_offset); + writer.Write(item.wall_offset); + writer.Write(item.sprite_offset); + writer.Write(item.sectors); + writer.Write(item.sprites); + writer.Write(item.walls); + writer.Write(item.xpos); + writer.Write(item.ypos); + writer.Write(item.zpos); + writer.Write(item.ang); + writer.Write(item.skytop_r); + writer.Write(item.skytop_g); + writer.Write(item.skytop_b); + writer.Write(item.skybottom_r); + writer.Write(item.skybottom_g); + writer.Write(item.skybottom_b); + } + + writer.Finish(write); + return std::nullopt; +} + +MapInfo readInfo(LUS::BinaryReader& reader) { + MapInfo map {}; + map.rom_start = reader.ReadUInt32(); + map.rom_end = reader.ReadUInt32(); + map.sector_offset = reader.ReadInt32(); + map.wall_offset = reader.ReadInt32(); + map.sprite_offset = reader.ReadInt32(); + map.sectors = reader.ReadInt32(); + map.sprites = reader.ReadInt32(); + map.walls = reader.ReadInt32(); + map.xpos = reader.ReadInt32(); + map.ypos = reader.ReadInt32(); + map.zpos = reader.ReadInt32(); + map.ang = reader.ReadInt32(); + map.skytop_r = reader.ReadFloat(); + map.skytop_g = reader.ReadFloat(); + map.skytop_b = reader.ReadFloat(); + map.skybottom_r = reader.ReadFloat(); + map.skybottom_g = reader.ReadFloat(); + map.skybottom_b = reader.ReadFloat(); + + return map; +} + +void readSectors(MapInfo& map, size_t id) { + size_t count = 0; + + auto offset = map.rom_start + map.sector_offset; + YAML::Node sector; + sector["type"] = "DKZH:SECTOR_TYPE_TABLE"; + sector["offset"] = offset; + sector["out"] = "map" + std::to_string(id + 1) + "/sectors.c"; + sector["symbol"] = "sectors"; + sector["count"] = map.sectors; + Companion::Instance->AddAsset(sector); + + auto result = std::static_pointer_cast(Companion::Instance->GetParseDataByAddr(offset).value().data.value()); + + for(size_t i = 0; i < map.sectors; i++){ + count += result->list[i].floorvtxnum; + count += result->list[i].ceilingvtxnum; + } + + YAML::Node vtx; + vtx["type"] = "DKZH:VERTEX"; + vtx["offset"] = map.rom_start; + vtx["count"] = count * 3; + vtx["out"] = "map" + std::to_string(id + 1) + "/vertex.c"; + vtx["symbol"] = "vectors"; + Companion::Instance->AddAsset(vtx); +} + +void readSprites(MapInfo& map, size_t id) { + auto offset = map.rom_start + map.sprite_offset; + YAML::Node sprite; + sprite["type"] = "DKZH:SPRITE_TYPE_TABLE"; + sprite["offset"] = offset; + sprite["out"] = "map" + std::to_string(id + 1) + "/sprites.c"; + sprite["symbol"] = "sprites"; + sprite["count"] = map.sprites; + Companion::Instance->AddAsset(sprite); +} + +void readWalls(MapInfo& map, size_t id) { + auto offset = map.rom_start + map.wall_offset; + YAML::Node sprite; + sprite["type"] = "DKZH:WALL_TYPE_TABLE"; + sprite["offset"] = offset; + sprite["out"] = "map" + std::to_string(id + 1) + "/walls.c"; + sprite["symbol"] = "walls"; + sprite["count"] = map.walls; + Companion::Instance->AddAsset(sprite); +} + +std::optional> MapInfoFactory::parse(std::vector& buffer, YAML::Node& node) { + auto reader = Decompressor::AutoDecode(node, buffer).GetReader(); + auto count = GetSafeNode(node, "count"); + reader.SetEndianness(Torch::Endianness::Big); + std::vector list; + + for(size_t i = 0; i < count; i++){ + MapInfo map = readInfo(reader); + readSectors(map, i); + readSprites(map, i); + readWalls(map, i); + list.push_back(map); + } + + return std::make_shared(list); +} diff --git a/src/factories/dkzh/MapInfoFactory.h b/src/factories/dkzh/MapInfoFactory.h new file mode 100644 index 00000000..124a2ffa --- /dev/null +++ b/src/factories/dkzh/MapInfoFactory.h @@ -0,0 +1,56 @@ +#pragma once + +#include "factories/BaseFactory.h" +#include "SectorTypeFactory.h" + +struct MapInfo { + uint32_t rom_start; + uint32_t rom_end; + int32_t sector_offset; + int32_t wall_offset; + int32_t sprite_offset; + int32_t sectors; + int32_t sprites; + int32_t walls; + int32_t xpos; + int32_t ypos; + int32_t zpos; + int32_t ang; + float skytop_r; + float skytop_g; + float skytop_b; + float skybottom_r; + float skybottom_g; + float skybottom_b; +}; + +class MapInfoData : public IParsedData { +public: + std::vector list; + + explicit MapInfoData(const std::vector &list) : list(list) {} +}; + +class MapInfoHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MapInfoBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MapInfoCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MapInfoFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Header, MapInfoHeaderExporter) + REGISTER(Binary, MapInfoBinaryExporter) + REGISTER(Code, MapInfoCodeExporter) + }; + } +}; diff --git a/src/factories/dkzh/SectorTypeFactory.cpp b/src/factories/dkzh/SectorTypeFactory.cpp new file mode 100644 index 00000000..c70fc95d --- /dev/null +++ b/src/factories/dkzh/SectorTypeFactory.cpp @@ -0,0 +1,155 @@ +#include "SectorTypeFactory.h" +#include "Companion.h" +#include "utils/Decompressor.h" +#include "libedl/edl.h" +#include + +#define HEX(c) (c < 0 ? "-0x" : "0x") << std::hex << std::setfill('0') << std::abs(((int)c)) << std::dec +#define U_HEX(c) "0x" << std::hex << std::setfill('0') << ((int)c) << std::dec + +ExportResult SectorTypeHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern SectorType " << symbol << "[];\n"; + + return std::nullopt; +} + +ExportResult SectorTypeCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto symbol = GetSafeNode(node, "symbol", entryName); + auto data = std::static_pointer_cast(raw)->list; + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "SectorType " << symbol << "[] = {\n"; + + for (int i = 0; i < data.size(); i++) { + int id = i + 1; + write << tab_t << "{" << "\n"; + write << dtab_t << HEX(data[i].ceilingz) << ",\n"; + write << dtab_t << HEX(data[i].floorz) << ",\n"; + write << dtab_t << HEX(data[i].wallptr) << ",\n"; + write << dtab_t << HEX(data[i].wallnum) << ",\n"; + write << dtab_t << HEX(data[i].ceilingstat) << ",\n"; + write << dtab_t << HEX(data[i].floorstat) << ",\n"; + write << dtab_t << HEX(data[i].ceilingpicnum) << ",\n"; + write << dtab_t << HEX(data[i].ceilingheinum) << ",\n"; + write << dtab_t << HEX(data[i].floorpicnum) << ",\n"; + write << dtab_t << HEX(data[i].floorheinum) << ",\n"; + write << dtab_t << HEX(data[i].unk18) << ",\n"; + write << dtab_t << HEX(data[i].unk1A) << ",\n"; + write << dtab_t << HEX(data[i].unk1C) << ",\n"; + write << dtab_t << U_HEX(data[i].floorvtxptr) << ",\n"; + write << dtab_t << U_HEX(data[i].ceilingvtxptr) << ",\n"; + write << dtab_t << U_HEX(data[i].ceilingshade) << ",\n"; + write << dtab_t << U_HEX(data[i].ceilingpal) << ",\n"; + write << dtab_t << "{ 0, 0 }" << ",\n"; + write << dtab_t << U_HEX(data[i].floorshade) << ",\n"; + write << dtab_t << U_HEX(data[i].floorpal) << ",\n"; + write << dtab_t << "{ 0, 0 }" << ",\n"; + write << dtab_t << U_HEX(data[i].unk2A) << ",\n"; + write << dtab_t << U_HEX(data[i].floorvtxnum) << ",\n"; + write << dtab_t << U_HEX(data[i].ceilingvtxnum) << ",\n"; + write << dtab_t << "{ 0, 0, 0 }" << ",\n"; + write << tab_t << "}," << "\n"; + } + + write << "};\n"; + + if (Companion::Instance->IsDebug()) { + write << "// size: 0x" << std::hex << std::uppercase << (data.size() * sizeof(SectorType)) << "\n"; + } + + return std::nullopt; +} + +ExportResult SectorTypeBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast(raw)->list; + + WriteHeader(writer, Torch::ResourceType::SectorType, 0); + writer.Write((uint32_t) data.size()); + + for (const auto &item: data) { + writer.Write(item.ceilingz); + writer.Write(item.floorz); + writer.Write(item.wallptr); + writer.Write(item.wallnum); + writer.Write(item.ceilingstat); + writer.Write(item.floorstat); + writer.Write(item.ceilingpicnum); + writer.Write(item.ceilingheinum); + writer.Write(item.floorpicnum); + writer.Write(item.floorheinum); + writer.Write(item.unk18); + writer.Write(item.unk1A); + writer.Write(item.unk1C); + writer.Write(item.floorvtxptr); + writer.Write(item.ceilingvtxptr); + writer.Write(item.ceilingshade); + writer.Write(item.ceilingpal); + writer.Write(item.pad[2]); + writer.Write(item.floorshade); + writer.Write(item.floorpal); + writer.Write(item.pad2[2]); + writer.Write(item.unk2A); + writer.Write(item.floorvtxnum); + writer.Write(item.ceilingvtxnum); + writer.Write(item.pad3[3]); + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional> SectorTypeFactory::parse(std::vector& buffer, YAML::Node& node) { + auto reader = Decompressor::AutoDecode(node, buffer).GetReader(); + auto count = GetSafeNode(node, "count"); + reader.SetEndianness(Torch::Endianness::Big); + std::vector list; + + for(size_t i = 0; i < count; i++) { + SectorType type {}; + type.ceilingz = reader.ReadInt32(); + type.floorz = reader.ReadInt32(); + type.wallptr = reader.ReadInt16(); + type.wallnum = reader.ReadInt16(); + type.ceilingstat = reader.ReadInt16(); + type.floorstat = reader.ReadInt16(); + type.ceilingpicnum = reader.ReadInt16(); + type.ceilingheinum = reader.ReadInt16(); + type.floorpicnum = reader.ReadInt16(); + type.floorheinum = reader.ReadInt16(); + type.unk18 = reader.ReadInt16(); + type.unk1A = reader.ReadInt16(); + type.unk1C = reader.ReadInt16(); + type.floorvtxptr = reader.ReadUInt16(); + type.ceilingvtxptr = reader.ReadUInt16(); + type.ceilingshade = reader.ReadUInt16(); + type.ceilingpal = reader.ReadUInt16(); + type.pad[0] = reader.ReadUByte(); + type.pad[1] = reader.ReadUByte(); + type.floorshade = reader.ReadUByte(); + type.floorpal = reader.ReadUByte(); + type.pad2[0] = reader.ReadUByte(); + type.pad2[1] = reader.ReadUByte(); + type.unk2A = reader.ReadUByte(); + type.floorvtxnum = reader.ReadUByte(); + type.ceilingvtxnum = reader.ReadUByte(); + type.pad3[0] = reader.ReadUByte(); + type.pad3[1] = reader.ReadUByte(); + type.pad3[2] = reader.ReadUByte(); + + list.push_back(type); + } + + return std::make_shared(list); +} diff --git a/src/factories/dkzh/SectorTypeFactory.h b/src/factories/dkzh/SectorTypeFactory.h new file mode 100644 index 00000000..8d2afd99 --- /dev/null +++ b/src/factories/dkzh/SectorTypeFactory.h @@ -0,0 +1,62 @@ +#pragma once + +#include "factories/BaseFactory.h" +#include + +struct SectorType { + int32_t ceilingz; + int32_t floorz; + int16_t wallptr; + int16_t wallnum; + int16_t ceilingstat; + int16_t floorstat; + int16_t ceilingpicnum; + int16_t ceilingheinum; + int16_t floorpicnum; + int16_t floorheinum; + int16_t unk18; /*lotag?*/ + int16_t unk1A; /*hitag?*/ + int16_t unk1C; /*extra?*/ + uint16_t floorvtxptr; + uint16_t ceilingvtxptr; + uint8_t ceilingshade; + uint8_t ceilingpal; + uint8_t pad[2]; + uint8_t floorshade; + uint8_t floorpal; + uint8_t pad2[2]; + uint8_t unk2A; + uint8_t floorvtxnum; + uint8_t ceilingvtxnum; + uint8_t pad3[3]; +}; + +class SectorTypeData : public IParsedData { +public: + std::vector list; + + explicit SectorTypeData(const std::vector &list) : list(list) {} +}; +class SectorTypeHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SectorTypeBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SectorTypeCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SectorTypeFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Header, SectorTypeHeaderExporter) + REGISTER(Binary, SectorTypeBinaryExporter) + REGISTER(Code, SectorTypeCodeExporter) + }; + } +}; diff --git a/src/factories/dkzh/SpriteTypeFactory.cpp b/src/factories/dkzh/SpriteTypeFactory.cpp new file mode 100644 index 00000000..387b08af --- /dev/null +++ b/src/factories/dkzh/SpriteTypeFactory.cpp @@ -0,0 +1,145 @@ +#include "SpriteTypeFactory.h" +#include "Companion.h" +#include "utils/Decompressor.h" +#include "libedl/edl.h" +#include + +#define HEX(c) (c < 0 ? "-0x" : "0x") << std::hex << std::setfill('0') << std::abs(((int)c)) << std::dec +#define U_HEX(c) "0x" << std::hex << std::setfill('0') << ((int)c) << std::dec + +ExportResult SpriteTypeHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern SpriteType " << symbol << "[];\n"; + + return std::nullopt; +} + +ExportResult SpriteTypeCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto symbol = GetSafeNode(node, "symbol", entryName); + auto data = std::static_pointer_cast(raw)->list; + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "SpriteType " << symbol << "[] = {\n"; + + for (int i = 0; i < data.size(); i++) { + int id = i + 1; + write << tab_t << "{" << "\n"; + write << dtab_t << HEX(data[i].x) << ",\n"; + write << dtab_t << HEX(data[i].y) << ",\n"; + write << dtab_t << HEX(data[i].z) << ",\n"; + write << dtab_t << HEX(data[i].cstat) << ",\n"; + write << dtab_t << HEX(data[i].picnum) << ",\n"; + write << dtab_t << HEX(data[i].sectnum) << ",\n"; + write << dtab_t << HEX(data[i].statnum) << ",\n"; + write << dtab_t << HEX(data[i].ang) << ",\n"; + write << dtab_t << HEX(data[i].unk16) << ",\n"; + write << dtab_t << HEX(data[i].unk18) << ",\n"; + write << dtab_t << HEX(data[i].unk1A) << ",\n"; + write << dtab_t << HEX(data[i].unk1C) << ",\n"; + write << dtab_t << HEX(data[i].lotag) << ",\n"; + write << dtab_t << HEX(data[i].hitag) << ",\n"; + write << dtab_t << HEX(data[i].unk22) << ",\n"; + write << dtab_t << U_HEX(data[i].unk24) << ",\n"; + write << dtab_t << U_HEX(data[i].unk25) << ",\n"; + write << dtab_t << U_HEX(data[i].clipdist) << ",\n"; + write << dtab_t << U_HEX(data[i].xrepeat) << ",\n"; + write << dtab_t << U_HEX(data[i].yrepeat) << ",\n"; + write << dtab_t << U_HEX(data[i].unk29) << ",\n"; + write << dtab_t << U_HEX(data[i].unk2A) << ",\n"; + write << dtab_t << U_HEX(data[i].unk2B) << ",\n"; + write << tab_t << "}," << "\n"; + } + + write << "};\n"; + + if (Companion::Instance->IsDebug()) { + write << "// size: 0x" << std::hex << std::uppercase << (data.size() * sizeof(SpriteType)) << "\n"; + } + + return std::nullopt; +} + +ExportResult SpriteTypeBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast(raw)->list; + + WriteHeader(writer, Torch::ResourceType::SpriteType, 0); + writer.Write((uint32_t) data.size()); + + for (const auto &item: data) { + writer.Write(item.x); + writer.Write(item.y); + writer.Write(item.z); + writer.Write(item.cstat); + writer.Write(item.picnum); + writer.Write(item.sectnum); + writer.Write(item.statnum); + writer.Write(item.ang); + writer.Write(item.unk16); + writer.Write(item.unk18); + writer.Write(item.unk1A); + writer.Write(item.unk1C); + writer.Write(item.lotag); + writer.Write(item.hitag); + writer.Write(item.unk22); + writer.Write(item.unk24); + writer.Write(item.unk25); + writer.Write(item.clipdist); + writer.Write(item.xrepeat); + writer.Write(item.yrepeat); + writer.Write(item.unk29); + writer.Write(item.unk2A); + writer.Write(item.unk2B); + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional> SpriteTypeFactory::parse(std::vector& buffer, YAML::Node& node) { + auto reader = Decompressor::AutoDecode(node, buffer).GetReader(); + auto count = GetSafeNode(node, "count"); + reader.SetEndianness(Torch::Endianness::Big); + std::vector list; + + for(size_t i = 0; i < count; i++) { + SpriteType type {}; + type.x = reader.ReadInt32(); + type.y = reader.ReadInt32(); + type.z = reader.ReadInt32(); + type.cstat = reader.ReadInt16(); + type.picnum = reader.ReadInt16(); + type.sectnum = reader.ReadInt16(); + type.statnum = reader.ReadInt16(); + type.ang = reader.ReadInt16(); + type.unk16 = reader.ReadInt16(); + type.unk18 = reader.ReadInt16(); + type.unk1A = reader.ReadInt16(); + type.unk1C = reader.ReadInt16(); + type.lotag = reader.ReadInt16(); + type.hitag = reader.ReadInt16(); + type.unk22 = reader.ReadInt16(); + type.unk24 = reader.ReadUByte(); + type.unk25 = reader.ReadUByte(); + type.clipdist = reader.ReadUByte(); + type.xrepeat = reader.ReadUByte(); + type.yrepeat = reader.ReadUByte(); + type.unk29 = reader.ReadUByte(); + type.unk2A = reader.ReadUByte(); + type.unk2B = reader.ReadUByte(); + + list.push_back(type); + } + + return std::make_shared(list); +} diff --git a/src/factories/dkzh/SpriteTypeFactory.h b/src/factories/dkzh/SpriteTypeFactory.h new file mode 100644 index 00000000..91b419b1 --- /dev/null +++ b/src/factories/dkzh/SpriteTypeFactory.h @@ -0,0 +1,60 @@ +#pragma once + +#include "factories/BaseFactory.h" +#include + +struct SpriteType { + int32_t x; + int32_t y; + int32_t z; + int16_t cstat; + int16_t picnum; + int16_t sectnum; + int16_t statnum; + int16_t ang; + int16_t unk16; + int16_t unk18; + int16_t unk1A; + int16_t unk1C; + int16_t lotag; + int16_t hitag; + int16_t unk22; + uint8_t unk24; + uint8_t unk25; + uint8_t clipdist; + uint8_t xrepeat; + uint8_t yrepeat; + uint8_t unk29; + uint8_t unk2A; + uint8_t unk2B; +}; + +class SpriteTypeData : public IParsedData { +public: + std::vector list; + + explicit SpriteTypeData(const std::vector &list) : list(list) {} +}; +class SpriteTypeHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SpriteTypeBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SpriteTypeCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SpriteTypeFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Header, SpriteTypeHeaderExporter) + REGISTER(Binary, SpriteTypeBinaryExporter) + REGISTER(Code, SpriteTypeCodeExporter) + }; + } +}; diff --git a/src/factories/dkzh/VertexFactory.cpp b/src/factories/dkzh/VertexFactory.cpp new file mode 100644 index 00000000..df49e71a --- /dev/null +++ b/src/factories/dkzh/VertexFactory.cpp @@ -0,0 +1,174 @@ +#include "VertexFactory.h" +#include "spdlog/spdlog.h" + +#include "Companion.h" +#include "utils/Decompressor.h" + +#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x +#define COL(c) std::dec << std::setfill(' ') << std::setw(3) << c + +ExportResult VertexHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + auto vtx = std::static_pointer_cast(raw)->mVtxs; + const auto offset = GetSafeNode(node, "offset"); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + const auto searchTable = Companion::Instance->SearchTable(offset); + + if(searchTable.has_value()){ + const auto [name, start, end, mode, index_size] = searchTable.value(); + // We will ignore the overriden index_size for now... + + if(start != offset){ + return std::nullopt; + } + + write << "extern Vertex " << name << "[][" << vtx.size() << "];\n"; + } else { + write << "extern Vertex " << symbol << "[];\n"; + } + + return std::nullopt; +} + +ExportResult VertexCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto vtx = std::static_pointer_cast(raw)->mVtxs; + const auto symbol = GetSafeNode(node, "symbol", entryName); + auto offset = GetSafeNode(node, "offset"); + const auto searchTable = Companion::Instance->SearchTable(offset); + + if(searchTable.has_value()){ + const auto [name, start, end, mode, index_size] = searchTable.value(); + + + if(start == offset){ + write << "Vertex " << name << "[][" << vtx.size() << "] = {\n"; + } + + write << fourSpaceTab << "{"; + + 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 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 << "\n" << fourSpaceTab; + } + + // {{{ x, y, z }, { tc1, tc2 }, { c1, c2, c3, c4 }}} + write << fourSpaceTab << "{{{" << NUM(x) << ", " << NUM(y) << ", " << NUM(z) << "}, {" << NUM(tc1) << ", " << NUM(tc2) << "}, {" << COL(c1) << ", " << COL(c2) << ", " << COL(c3) << ", " << COL(c4) << "}}},"; + } + write << "\n" << fourSpaceTab << "},\n"; + + if(end == offset){ + write << "};\n\n"; + } + } else { + + write << "Vertex " << 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 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 }, { tc1, tc2 }, { c1, c2, c3, c4 }}} + write << "{{{" << NUM(x) << ", " << NUM(y) << ", " << NUM(z) << "}, {" << NUM(tc1) << ", " << NUM(tc2) << "}, {" << COL(c1) << ", " << COL(c2) << ", " << COL(c3) << ", " << COL(c4) << "}}},\n"; + } + + write << "};\n"; + + if (Companion::Instance->IsDebug()) { + write << "// count: " << std::to_string(vtx.size()) << " Vertexs\n"; + } else { + write << "\n"; + } + } + + return offset + vtx.size() * sizeof(VertexRaw); +} + +ExportResult VertexBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto vtx = std::static_pointer_cast(raw); + auto writer = LUS::BinaryWriter(); + + WriteHeader(writer, Torch::ResourceType::CVertex, 0); + writer.Write((uint32_t) vtx->mVtxs.size()); + for(auto v : vtx->mVtxs) { + if(Companion::Instance->GetConfig().gbi.useFloats){ + writer.Write((float) v.ob[0]); + writer.Write((float) v.ob[1]); + writer.Write((float) v.ob[2]); + } else { + writer.Write((int16_t) v.ob[0]); + writer.Write((int16_t) v.ob[1]); + writer.Write((int16_t) v.ob[2]); + } + 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); + return std::nullopt; +} + +std::optional> VertexFactory::parse(std::vector& buffer, YAML::Node& node) { + auto count = GetSafeNode(node, "count"); + + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + LUS::BinaryReader reader(segment.data, count * sizeof(VertexRaw)); + + reader.SetEndianness(Torch::Endianness::Big); + std::vector vertices; + + for(size_t i = 0; i < count; i++) { + auto x = reader.ReadInt16(); + auto y = reader.ReadInt16(); + auto z = reader.ReadInt16(); + 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(VertexRaw({ + {x, y, z}, {tc1, tc2}, {cn1, cn2, cn3, cn4} + })); + } + + return std::make_shared(vertices); +} diff --git a/src/factories/dkzh/VertexFactory.h b/src/factories/dkzh/VertexFactory.h new file mode 100644 index 00000000..fed7f887 --- /dev/null +++ b/src/factories/dkzh/VertexFactory.h @@ -0,0 +1,43 @@ +#pragma once + +#include "factories/BaseFactory.h" + +struct VertexRaw { + int16_t ob[3]; /* x, y, z */ + int16_t tc[2]; /* texture coord */ + uint8_t cn[4]; /* color & alpha */ +}; + +class VertexData : public IParsedData { +public: + std::vector mVtxs; + + explicit VertexData(std::vector vtxs) : mVtxs(vtxs) {} +}; + +class VertexHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class VertexBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class VertexCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class VertexFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Code, VertexCodeExporter) + REGISTER(Header, VertexHeaderExporter) + REGISTER(Binary, VertexBinaryExporter) + }; + } + uint32_t GetAlignment() override { + return 8; + }; +}; \ No newline at end of file diff --git a/src/factories/dkzh/WallTypeFactory.cpp b/src/factories/dkzh/WallTypeFactory.cpp new file mode 100644 index 00000000..b6efe51f --- /dev/null +++ b/src/factories/dkzh/WallTypeFactory.cpp @@ -0,0 +1,146 @@ +#include "WallTypeFactory.h" +#include "Companion.h" +#include "utils/Decompressor.h" +#include "libedl/edl.h" +#include + +#define HEX(c) (c < 0 ? "-0x" : "0x") << std::hex << std::setfill('0') << std::abs(((int)c)) << std::dec +#define U_HEX(c) "0x" << std::hex << std::setfill('0') << ((int)c) << std::dec + +ExportResult WallTypeHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern WallType " << symbol << "[];\n"; + + return std::nullopt; +} + +ExportResult WallTypeCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto symbol = GetSafeNode(node, "symbol", entryName); + auto data = std::static_pointer_cast(raw)->list; + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "WallType " << symbol << "[] = {\n"; + + for (int i = 0; i < data.size(); i++) { + int id = i + 1; + write << tab_t << "{" << "\n"; + write << dtab_t << HEX(data[i].x) << ",\n"; + write << dtab_t << HEX(data[i].y) << ",\n"; + write << dtab_t << HEX(data[i].point2) << ",\n"; + write << dtab_t << HEX(data[i].nextwall) << ",\n"; + write << dtab_t << HEX(data[i].nextsector) << ",\n"; + write << dtab_t << HEX(data[i].cstat) << ",\n"; + write << dtab_t << HEX(data[i].picnum) << ",\n"; + write << dtab_t << HEX(data[i].overpicnum) << ",\n"; + write << dtab_t << HEX(data[i].unk14) << ",\n"; + write << dtab_t << HEX(data[i].unk16) << ",\n"; + write << dtab_t << HEX(data[i].unk18) << ",\n"; + write << dtab_t << HEX(data[i].sectnum) << ",\n"; + write << dtab_t << U_HEX(data[i].shade) << ",\n"; + write << dtab_t << U_HEX(data[i].unk1D) << ",\n"; + write << dtab_t << U_HEX(data[i].unk1E) << ",\n"; + write << dtab_t << U_HEX(data[i].unk1F) << ",\n"; + write << dtab_t << U_HEX(data[i].unk20) << ",\n"; + write << dtab_t << U_HEX(data[i].pal) << ",\n"; + write << dtab_t << U_HEX(data[i].xrepeat) << ",\n"; + write << dtab_t << U_HEX(data[i].yrepeat) << ",\n"; + write << dtab_t << U_HEX(data[i].xpanning) << ",\n"; + write << dtab_t << U_HEX(data[i].ypanning) << ",\n"; + write << dtab_t << U_HEX(data[i].pad3[0]) << ",\n"; + write << dtab_t << U_HEX(data[i].pad3[1]) << ",\n"; + write << tab_t << "}," << "\n"; + } + + write << "};\n"; + + if (Companion::Instance->IsDebug()) { + write << "// size: 0x" << std::hex << std::uppercase << (data.size() * sizeof(WallType)) << "\n"; + } + + return std::nullopt; +} + +ExportResult WallTypeBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast(raw)->list; + + WriteHeader(writer, Torch::ResourceType::WallType, 0); + writer.Write((uint32_t) data.size()); + + for (const auto &item: data) { + writer.Write(item.x); + writer.Write(item.y); + writer.Write(item.point2); + writer.Write(item.nextwall); + writer.Write(item.nextsector); + writer.Write(item.cstat); + writer.Write(item.picnum); + writer.Write(item.overpicnum); + writer.Write(item.unk14); + writer.Write(item.unk16); + writer.Write(item.unk18); + writer.Write(item.sectnum); + writer.Write(item.shade); + writer.Write(item.unk1D); + writer.Write(item.unk1E); + writer.Write(item.unk1F); + writer.Write(item.unk20); + writer.Write(item.pal); + writer.Write(item.xrepeat); + writer.Write(item.yrepeat); + writer.Write(item.xpanning); + writer.Write(item.ypanning); + writer.Write(item.pad3[2]); + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional> WallTypeFactory::parse(std::vector& buffer, YAML::Node& node) { + auto reader = Decompressor::AutoDecode(node, buffer).GetReader(); + auto count = GetSafeNode(node, "count"); + reader.SetEndianness(Torch::Endianness::Big); + std::vector list; + + for(size_t i = 0; i < count; i++) { + WallType type {}; + type.x = reader.ReadInt32(); + type.y = reader.ReadInt32(); + type.point2 = reader.ReadInt16(); + type.nextwall = reader.ReadInt16(); + type.nextsector = reader.ReadInt16(); + type.cstat = reader.ReadInt16(); + type.picnum = reader.ReadInt16(); + type.overpicnum = reader.ReadInt16(); + type.unk14 = reader.ReadInt16(); + type.unk16 = reader.ReadInt16(); + type.unk18 = reader.ReadInt16(); + type.sectnum = reader.ReadUInt16(); + type.shade = reader.ReadUByte(); + type.unk1D = reader.ReadUByte(); + type.unk1E = reader.ReadUByte(); + type.unk1F = reader.ReadUByte(); + type.unk20 = reader.ReadUByte(); + type.pal = reader.ReadUByte(); + type.xrepeat = reader.ReadUByte(); + type.yrepeat = reader.ReadUByte(); + type.xpanning = reader.ReadUByte(); + type.ypanning = reader.ReadUByte(); + type.pad3[0] = reader.ReadUByte(); + type.pad3[1] = reader.ReadUByte(); + list.push_back(type); + } + + return std::make_shared(list); +} diff --git a/src/factories/dkzh/WallTypeFactory.h b/src/factories/dkzh/WallTypeFactory.h new file mode 100644 index 00000000..27c5ff3a --- /dev/null +++ b/src/factories/dkzh/WallTypeFactory.h @@ -0,0 +1,60 @@ +#pragma once + +#include "factories/BaseFactory.h" +#include + +struct WallType { + int32_t x; + int32_t y; + int16_t point2; + int16_t nextwall; + int16_t nextsector; + int16_t cstat; + int16_t picnum; + int16_t overpicnum; + int16_t unk14; + int16_t unk16; + int16_t unk18; + uint16_t sectnum; + uint8_t shade; + uint8_t unk1D; + uint8_t unk1E; + uint8_t unk1F; + uint8_t unk20; + uint8_t pal; + uint8_t xrepeat; + uint8_t yrepeat; + uint8_t xpanning; + uint8_t ypanning; + uint8_t pad3[2]; +}; + +class WallTypeData : public IParsedData { +public: + std::vector list; + + explicit WallTypeData(const std::vector &list) : list(list) {} +}; +class WallTypeHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class WallTypeBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class WallTypeCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class WallTypeFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Header, WallTypeHeaderExporter) + REGISTER(Binary, WallTypeBinaryExporter) + REGISTER(Code, WallTypeCodeExporter) + }; + } +}; diff --git a/src/utils/Decompressor.cpp b/src/utils/Decompressor.cpp index 5139fccc..0ccafd77 100644 --- a/src/utils/Decompressor.cpp +++ b/src/utils/Decompressor.cpp @@ -9,6 +9,7 @@ extern "C" { #include #include #include +#include } std::unordered_map gCachedChunks; @@ -55,6 +56,19 @@ DataChunk* Decompressor::Decode(const std::vector& buffer, const uint32 gCachedChunks[offset] = new DataChunk{ decompressed, size }; return gCachedChunks[offset]; } + case CompressionType::EDL: { + EDLInfo info; + int32_t size = getEDLDecompressedSize((uint8_t*)in_buf); + SPDLOG_INFO("EDL decompressed size: {}", size); + auto* decompressed = new uint8_t[size]; + + if(decompressEDL(&info, (void*) in_buf, (void*) decompressed) != 0){ + throw std::runtime_error("Failed to decode EDL"); + } + + gCachedChunks[offset] = new DataChunk{ decompressed, size }; + return gCachedChunks[offset]; + } default: throw std::runtime_error("Unknown compression type"); } @@ -79,24 +93,12 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector CompressionType type = Companion::Instance->GetCurrCompressionType(); - auto fileOffset = TranslateAddr(offset, true); - - // Check if an asset in a yaml file is mio0 compressed and extract. - if (node["mio0"]) { - auto assetPtr = ASSET_PTR(offset); - auto gameSize = Companion::Instance->GetRomData().size(); - - auto fileOffset = TranslateAddr(offset, true); - offset = ASSET_PTR(offset); - - auto decoded = Decode(buffer, fileOffset + offset, CompressionType::MIO0); - auto size = node["size"] ? node["size"].as() : manualSize.value_or(decoded->size); - return { - .root = decoded, - .segment = { decoded->data, size } - }; + if(type == CompressionType::None){ + type = GetCompressionType(buffer, offset); } + auto fileOffset = TranslateAddr(offset, true); + // Check if an asset in a yaml file is tkmk00 compressed and extract (mk64). if (node["tkmk00"]) { const auto alpha = GetSafeNode(node, "alpha"); @@ -104,7 +106,6 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector const auto height = GetSafeNode(node, "height"); const auto textureSize = width * height * 2; - auto fileOffset = TranslateAddr(offset, true); offset = ASSET_PTR(offset); auto decoded = DecodeTKMK00(buffer, fileOffset + offset, textureSize, alpha); @@ -117,16 +118,24 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector // Extract a compressed file which contains many assets. switch(type) { - case CompressionType::YAY0: - case CompressionType::YAY1: case CompressionType::MIO0: { offset = ASSET_PTR(offset); - auto decoded = Decode(buffer, fileOffset, type); - auto size = node["size"] ? node["size"].as() : manualSize.value_or(decoded->size - offset); + auto decoded = Decode(buffer, fileOffset + offset, CompressionType::MIO0); + auto size = node["size"] ? node["size"].as() : manualSize.value_or(decoded->size); return { .root = decoded, - .segment = { decoded->data + offset, size } + .segment = { decoded->data, size } + }; + } + case CompressionType::EDL: + case CompressionType::YAY0: + case CompressionType::YAY1: { + auto decoded = Decode(buffer, offset, type); + auto size = node["size"] ? node["size"].as() : manualSize.value_or(decoded->size); + return { + .root = decoded, + .segment = { decoded->data, size } }; } case CompressionType::YAZ0: @@ -150,6 +159,9 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector DecompressedData Decompressor::AutoDecode(uint32_t offset, std::optional size, std::vector& buffer) { YAML::Node node; node["offset"] = offset; + if(size.has_value()){ + node["size"] = size.value(); + } return AutoDecode(node, buffer, size); } @@ -179,28 +191,32 @@ uint32_t Decompressor::TranslateAddr(uint32_t addr, bool baseAddress){ } CompressionType Decompressor::GetCompressionType(std::vector& buffer, const uint32_t offset) { - if (offset) { + if (offset != 0) { LUS::BinaryReader reader((char*) buffer.data() + offset, sizeof(uint32_t)); reader.SetEndianness(Torch::Endianness::Big); const std::string header = reader.ReadCString(); +#define CONTAINS(str) (header.find(str) != std::string::npos) // Check if a compressed header exists - if (header == "MIO0") { + if (CONTAINS("MIO0")) { + SPDLOG_INFO("MIO0 compressed segment found at offset 0x{:X}", offset); return CompressionType::MIO0; - } - - if (header == "Yay0" || header == "PERS") { + } else if (CONTAINS("Yay0") || CONTAINS("PERS")) { + SPDLOG_INFO("YAY0 compressed segment found at offset 0x{:X}", offset); return CompressionType::YAY0; - } - - if (header == "Yay1") { + } else if (CONTAINS("Yay1")) { + SPDLOG_INFO("YAY1 compressed segment found at offset 0x{:X}", offset); return CompressionType::YAY1; - } - - if (header == "Yaz0") { + } else if (CONTAINS("EDL")) { + SPDLOG_INFO("EDL compressed segment found at offset 0x{:X}", offset); + return CompressionType::EDL; + } else if (CONTAINS("Yaz0")) { + SPDLOG_INFO("YAZ0 compressed segment found at offset 0x{:X}", offset); return CompressionType::YAZ0; } + + SPDLOG_INFO("No compression found at offset 0x{:X} {}", offset, header); } return CompressionType::None; } diff --git a/src/utils/Decompressor.h b/src/utils/Decompressor.h index 22f4b249..b2985404 100644 --- a/src/utils/Decompressor.h +++ b/src/utils/Decompressor.h @@ -14,6 +14,7 @@ enum class CompressionType { YAY0, YAY1, YAZ0, + EDL }; @@ -26,8 +27,12 @@ struct DecompressedData { DataChunk* root; DataChunk segment; - LUS::BinaryReader GetReader() { - return LUS::BinaryReader(reinterpret_cast(segment.data), segment.size); + [[nodiscard]] LUS::BinaryReader GetReader() const { + return { reinterpret_cast(segment.data), segment.size }; + } + + [[nodiscard]] LUS::BinaryReader GetDecodedReader() const { + return { reinterpret_cast(root->data), root->size }; } }; diff --git a/src/utils/TorchUtils.h b/src/utils/TorchUtils.h index 8b7a3f1a..c046d8a0 100644 --- a/src/utils/TorchUtils.h +++ b/src/utils/TorchUtils.h @@ -2,26 +2,39 @@ #include #include +#include #include #include #include #include #include #include +#include namespace Torch { template< typename T > std::string to_hex(T number, const bool append0x = true) { + static_assert(std::is_integral_v, "to_hex function only accepts integral types."); std::stringstream stream; - if(append0x) { + if (append0x) { stream << "0x"; } - stream << std::setfill ('0') - << std::hex << number; - auto format = stream.str(); - std::transform(format.begin(), format.end(), format.begin(), ::toupper); - return format; + if constexpr (std::is_signed_v) { + stream << std::abs(number); + } else { + stream << number; + } + + auto formatted_string = stream.str(); + std::transform( + formatted_string.begin() + (append0x ? 2 : 0), + formatted_string.end(), + formatted_string.begin() + (append0x ? 2 : 0), + ::toupper + ); + + return formatted_string; } uint32_t translate(uint32_t offset);