From 486befa486b15edf5403b1fca6c4e53d42cfe574 Mon Sep 17 00:00:00 2001 From: Lilith Naomi Nightingale Date: Sun, 25 Apr 2021 17:54:02 +0100 Subject: [PATCH] [bxon] tpGxTexHead support [kaineconv] tool to convert xap files --- .clang-format | 6 +- kaine/CMakeLists.txt | 6 +- kaine/private/CMakeLists.txt | 7 +- kaine/private/{arc => }/arc.cpp | 2 +- kaine/private/arc/CMakeLists.txt | 3 - kaine/private/{bxon => }/bxon.cpp | 2 +- kaine/private/bxon/CMakeLists.txt | 5 -- kaine/private/bxon/types/CMakeLists.txt | 3 - kaine/private/bxon_types/CMakeLists.txt | 3 + .../tp_archive_file_param.cpp | 6 +- kaine/private/bxon_types/tp_gx_tex_head.cpp | 85 +++++++++++++++++++ kaine/private/{pack => }/pack.cpp | 12 +-- kaine/private/pack/CMakeLists.txt | 3 - kaine/public/kaine/{arc => }/arc.hpp | 2 +- kaine/public/kaine/{bxon => }/bxon.hpp | 8 +- kaine/public/kaine/bxon_types.hpp | 10 +++ .../types => bxon_types}/abstract_bxon.hpp | 2 +- .../tp_archive_file_param.hpp | 8 +- .../kaine/bxon_types/tp_gx_tex_head.hpp | 74 ++++++++++++++++ .../{ => generated}/kaine_export_clang.a.h | 0 .../{ => generated}/kaine_export_linux.a.h | 0 .../{ => generated}/kaine_export_win.a.h | 0 kaine/public/kaine/kaine.hpp | 8 +- kaine/public/kaine/kaine_export.h | 6 +- kaine/public/kaine/{pack => }/pack.hpp | 16 ++-- research/pack.txt | 8 +- tool/CMakeLists.txt | 1 + tool/emil/emil.cpp | 52 ++++-------- tool/emil/emil.hpp | 5 -- tool/kaineconv/CMakeLists.txt | 8 ++ tool/kaineconv/kaineconv.cpp | 84 ++++++++++++++++++ vendor/standard_dragon | 2 +- 32 files changed, 331 insertions(+), 106 deletions(-) rename kaine/private/{arc => }/arc.cpp (98%) delete mode 100644 kaine/private/arc/CMakeLists.txt rename kaine/private/{bxon => }/bxon.cpp (97%) delete mode 100644 kaine/private/bxon/CMakeLists.txt delete mode 100644 kaine/private/bxon/types/CMakeLists.txt create mode 100644 kaine/private/bxon_types/CMakeLists.txt rename kaine/private/{bxon/types => bxon_types}/tp_archive_file_param.cpp (94%) create mode 100644 kaine/private/bxon_types/tp_gx_tex_head.cpp rename kaine/private/{pack => }/pack.cpp (86%) delete mode 100644 kaine/private/pack/CMakeLists.txt rename kaine/public/kaine/{arc => }/arc.hpp (96%) rename kaine/public/kaine/{bxon => }/bxon.hpp (88%) create mode 100644 kaine/public/kaine/bxon_types.hpp rename kaine/public/kaine/{bxon/types => bxon_types}/abstract_bxon.hpp (85%) rename kaine/public/kaine/{bxon/types => bxon_types}/tp_archive_file_param.hpp (92%) create mode 100644 kaine/public/kaine/bxon_types/tp_gx_tex_head.hpp rename kaine/public/kaine/{ => generated}/kaine_export_clang.a.h (100%) rename kaine/public/kaine/{ => generated}/kaine_export_linux.a.h (100%) rename kaine/public/kaine/{ => generated}/kaine_export_win.a.h (100%) rename kaine/public/kaine/{pack => }/pack.hpp (82%) delete mode 100644 tool/emil/emil.hpp create mode 100644 tool/kaineconv/CMakeLists.txt create mode 100644 tool/kaineconv/kaineconv.cpp diff --git a/.clang-format b/.clang-format index 3dfd912..92399ef 100644 --- a/.clang-format +++ b/.clang-format @@ -2,8 +2,8 @@ BasedOnStyle: LLVM AccessModifierOffset: -4 AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignOperands: true +AlignConsecutiveAssignments: None +AlignOperands: Align AllowAllArgumentsOnNextLine: false AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false @@ -56,7 +56,7 @@ SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 +SpacesBeforeTrailingComments: 0 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: false diff --git a/kaine/CMakeLists.txt b/kaine/CMakeLists.txt index 07801e1..9ed4b70 100644 --- a/kaine/CMakeLists.txt +++ b/kaine/CMakeLists.txt @@ -10,11 +10,11 @@ set_target_properties(kaine PROPERTIES POSITION_INDEPENDENT_CODE 1) target_compile_definitions(kaine PRIVATE DRAGON_LIBRARY_NAME="kaine") if (MSVC) - generate_export_header(kaine BASE_NAME kaine DEFINE_NO_DEPRECATED EXPORT_FILE_NAME ${PROJECT_SOURCE_DIR}/public/kaine/kaine_export_win.a.h) + generate_export_header(kaine BASE_NAME kaine DEFINE_NO_DEPRECATED EXPORT_FILE_NAME ${PROJECT_SOURCE_DIR}/public/kaine/generated/kaine_export_win.a.h) elseif (WIN32_CLANG) - generate_export_header(kaine BASE_NAME kaine DEFINE_NO_DEPRECATED EXPORT_FILE_NAME ${PROJECT_SOURCE_DIR}/public/kaine/kaine_export_clang.a.h) + generate_export_header(kaine BASE_NAME kaine DEFINE_NO_DEPRECATED EXPORT_FILE_NAME ${PROJECT_SOURCE_DIR}/public/kaine/generated/kaine_export_clang.a.h) else () - generate_export_header(kaine BASE_NAME kaine DEFINE_NO_DEPRECATED EXPORT_FILE_NAME ${PROJECT_SOURCE_DIR}/public/kaine/kaine_export_linux.a.h) + generate_export_header(kaine BASE_NAME kaine DEFINE_NO_DEPRECATED EXPORT_FILE_NAME ${PROJECT_SOURCE_DIR}/public/kaine/generated/kaine_export_linux.a.h) endif () target_include_directories(kaine PUBLIC ${PROJECT_SOURCE_DIR}/public) diff --git a/kaine/private/CMakeLists.txt b/kaine/private/CMakeLists.txt index c857f15..d537ca7 100644 --- a/kaine/private/CMakeLists.txt +++ b/kaine/private/CMakeLists.txt @@ -1,7 +1,6 @@ project(kaine) -target_sources(kaine PRIVATE kaine.cpp) +target_sources(kaine PRIVATE kaine.cpp arc.cpp bxon.cpp pack.cpp) + +add_subdirectory("bxon_types") -add_subdirectory("arc") -add_subdirectory("bxon") -add_subdirectory("pack") diff --git a/kaine/private/arc/arc.cpp b/kaine/private/arc.cpp similarity index 98% rename from kaine/private/arc/arc.cpp rename to kaine/private/arc.cpp index e8a847d..f1f7a31 100644 --- a/kaine/private/arc/arc.cpp +++ b/kaine/private/arc.cpp @@ -2,7 +2,7 @@ // Created by Lilith on 2021-04-24. // -#include +#include #include #include diff --git a/kaine/private/arc/CMakeLists.txt b/kaine/private/arc/CMakeLists.txt deleted file mode 100644 index 9e6865e..0000000 --- a/kaine/private/arc/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -project(kaine_arc) - -target_sources(kaine PRIVATE arc.cpp) diff --git a/kaine/private/bxon/bxon.cpp b/kaine/private/bxon.cpp similarity index 97% rename from kaine/private/bxon/bxon.cpp rename to kaine/private/bxon.cpp index ca227ac..56a9215 100644 --- a/kaine/private/bxon/bxon.cpp +++ b/kaine/private/bxon.cpp @@ -2,7 +2,7 @@ // Created by Lilith on 2021-04-24. // -#include +#include #include #include diff --git a/kaine/private/bxon/CMakeLists.txt b/kaine/private/bxon/CMakeLists.txt deleted file mode 100644 index 1a793fd..0000000 --- a/kaine/private/bxon/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -project(kaine_bxon) - -target_sources(kaine PRIVATE bxon.cpp) - -add_subdirectory("types") diff --git a/kaine/private/bxon/types/CMakeLists.txt b/kaine/private/bxon/types/CMakeLists.txt deleted file mode 100644 index c7d87e1..0000000 --- a/kaine/private/bxon/types/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -project(kaine_bxon_types) - -target_sources(kaine PRIVATE tp_archive_file_param.cpp) diff --git a/kaine/private/bxon_types/CMakeLists.txt b/kaine/private/bxon_types/CMakeLists.txt new file mode 100644 index 0000000..30845e2 --- /dev/null +++ b/kaine/private/bxon_types/CMakeLists.txt @@ -0,0 +1,3 @@ +project(kaine_bxon_types) + +target_sources(kaine PRIVATE tp_archive_file_param.cpp tp_gx_tex_head.cpp) diff --git a/kaine/private/bxon/types/tp_archive_file_param.cpp b/kaine/private/bxon_types/tp_archive_file_param.cpp similarity index 94% rename from kaine/private/bxon/types/tp_archive_file_param.cpp rename to kaine/private/bxon_types/tp_archive_file_param.cpp index 5e6bc3f..b233fbf 100644 --- a/kaine/private/bxon/types/tp_archive_file_param.cpp +++ b/kaine/private/bxon_types/tp_archive_file_param.cpp @@ -2,7 +2,7 @@ // Created by Lilith on 2021-04-24. // -#include +#include #include #include @@ -16,12 +16,12 @@ kaine::bxon_types::tp_archive_file_param::tp_archive_file_param(std::shared_ptr< assert(data_end - data_start == EXPECTED_DATA_SIZE); #endif - if (buffer->size() < EXPECTED_DATA_SIZE) { throw dragon::exception::invalid_data("Buffer passed to bxon is not a valid bxon buffer."); } + if (buffer->size() < EXPECTED_DATA_SIZE) { throw dragon::exception::invalid_data("Buffer passed to tp_archive_file_param is not a valid tp_archive_file_param buffer."); } buffer->copy(data_start, 0, EXPECTED_DATA_SIZE); uint8_t *ptr = buffer->data(); - auto offset = 0u; + uint32_t offset; if (rel_offset_archive_list > 0) { offset = rel_offset_archive_list + ARC_PARAM_OFFSET; diff --git a/kaine/private/bxon_types/tp_gx_tex_head.cpp b/kaine/private/bxon_types/tp_gx_tex_head.cpp new file mode 100644 index 0000000..6e794ce --- /dev/null +++ b/kaine/private/bxon_types/tp_gx_tex_head.cpp @@ -0,0 +1,85 @@ +// +// Created by Lilith on 2021-04-25. +// + +#include + +#include + +#include +#include + +kaine::bxon_types::tp_gx_tex_head::tp_gx_tex_head(std::shared_ptr> &buffer) { + auto data_start = reinterpret_cast(&width); +#ifndef NDEBUG + auto data_end = reinterpret_cast(&rel_offset_mip_surface) + sizeof(uint32_t); + assert(data_end - data_start == EXPECTED_DATA_SIZE); +#endif + + if (buffer->size() < EXPECTED_DATA_SIZE) { throw dragon::exception::invalid_data("Buffer passed to tp_gx_tex_head is not a valid tp_gx_tex_head buffer."); } + + buffer->copy(data_start, 0, EXPECTED_DATA_SIZE); + + uint8_t *ptr = buffer->data(); + uint32_t offset; + + if (rel_offset_mip_surface > 0) { + offset = rel_offset_mip_surface + MIP_SURFACE_OFFSET; + mip_surfaces = dragon::Array(reinterpret_cast(ptr + offset), mip_surface_count, true); + } +} + +std::shared_ptr> kaine::bxon_types::tp_gx_tex_head::generate_dds(std::shared_ptr> &resource, uintptr_t *offset) const { + auto dds = standard_dragon::support::DDS{}; + dds.dx9.linear_size = total_image_size; + dds.dx9.width = width; + dds.dx9.height = height; + dds.dx9.mip_count = mip_surface_count; + dds.dx10.array_size = surfaces; + switch (format) { + default: + case XonSurfaceFormat::UNKNOWN: + std::cerr << "warn: unrecognized XonSurfaceFormat 0x" << HEXLOG32 << static_cast(format) << " defaulting to BC3_UNORM" << std::endl; + dds.dx10.format = standard_dragon::support::DXGIFormat::BC3_UNORM; + break; + case XonSurfaceFormat::R8G8B8A8_UNORM: + dds.dx10.format = standard_dragon::support::DXGIFormat::R8G8B8A8_UNORM; + break; + case XonSurfaceFormat::R8G8B8A8_UNORM_SRGB: + dds.dx10.format = standard_dragon::support::DXGIFormat::R8G8B8A8_UNORM_SRGB; + break; + case XonSurfaceFormat::BC1_UNORM: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC1_UNORM; + break; + case XonSurfaceFormat::BC1_UNORM_SRGB: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC1_UNORM_SRGB; + break; + case XonSurfaceFormat::BC2_UNORM: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC2_UNORM; + break; + case XonSurfaceFormat::BC2_UNORM_SRGB: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC2_UNORM_SRGB; + break; + case XonSurfaceFormat::BC3_UNORM: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC3_UNORM; + break; + case XonSurfaceFormat::BC3_UNORM_SRGB: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC3_UNORM_SRGB; + break; + case XonSurfaceFormat::BC4_UNORM: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC4_UNORM; + break; + case XonSurfaceFormat::BC5_UNORM: + dds.dx10.format = standard_dragon::support::DXGIFormat::BC5_UNORM; + break; + case XonSurfaceFormat::R32G32B32A32_FLOAT: + dds.dx10.format = standard_dragon::support::DXGIFormat::R32G32B32A32_FLOAT; + break; + } + + auto buffer = std::make_shared>(total_image_size + sizeof(standard_dragon::support::DDS), nullptr); + std::copy_n(reinterpret_cast(&dds), sizeof(standard_dragon::support::DDS), buffer->data()); + auto ptr = reinterpret_cast(buffer->data() + sizeof(standard_dragon::support::DDS)); + resource->lpcopy(&ptr, offset, total_image_size); + return buffer; +} diff --git a/kaine/private/pack/pack.cpp b/kaine/private/pack.cpp similarity index 86% rename from kaine/private/pack/pack.cpp rename to kaine/private/pack.cpp index 1a234a2..8f9def6 100644 --- a/kaine/private/pack/pack.cpp +++ b/kaine/private/pack.cpp @@ -2,7 +2,7 @@ // Created by Lilith on 2021-04-25. // -#include +#include #include @@ -30,12 +30,12 @@ kaine::pack::pack(dragon::Array &buffer) { uint32_t offset; if (rel_offset_preload > 0) { offset = rel_offset_preload + PRELOAD_OFFSET; - preload = dragon::Array(reinterpret_cast(ptr + offset), preload_count, true); + dependencies = dragon::Array(reinterpret_cast(ptr + offset), preload_count, true); for (auto i = 0; i < preload_count; ++i) { - auto param = preload[i]; + auto param = dependencies[i]; if (param.rel_offset_name > 0) { - auto name_offset = offset + sizeof(XapPreload) * i + param.rel_offset_name + PRELOAD_NAME_OFFSET; - preload_names[param.id] = std::string(reinterpret_cast(ptr + name_offset)); + auto name_offset = offset + sizeof(XapDependency) * i + param.rel_offset_name + PRELOAD_NAME_OFFSET; + dependency_names[param.id] = std::string(reinterpret_cast(ptr + name_offset)); } } } @@ -74,7 +74,7 @@ kaine::pack::pack(dragon::Array &buffer) { } } - if(resource_size > 0) { + if (resource_size > 0) { resource = std::make_shared>(ptr + serialized_size, resource_size, true); } } diff --git a/kaine/private/pack/CMakeLists.txt b/kaine/private/pack/CMakeLists.txt deleted file mode 100644 index ebd2c44..0000000 --- a/kaine/private/pack/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -project(kaine_pack) - -target_sources(kaine PRIVATE pack.cpp) diff --git a/kaine/public/kaine/arc/arc.hpp b/kaine/public/kaine/arc.hpp similarity index 96% rename from kaine/public/kaine/arc/arc.hpp rename to kaine/public/kaine/arc.hpp index 4ab6be7..6f49915 100644 --- a/kaine/public/kaine/arc/arc.hpp +++ b/kaine/public/kaine/arc.hpp @@ -23,4 +23,4 @@ namespace kaine { std::shared_ptr> get_file(uint64_t offset, uint64_t size); std::shared_ptr> decompress_file(uint64_t offset, uint64_t csize, uint64_t size); }; -} // namespace kaine +}// namespace kaine diff --git a/kaine/public/kaine/bxon/bxon.hpp b/kaine/public/kaine/bxon.hpp similarity index 88% rename from kaine/public/kaine/bxon/bxon.hpp rename to kaine/public/kaine/bxon.hpp index 437fc91..1954d66 100644 --- a/kaine/public/kaine/bxon/bxon.hpp +++ b/kaine/public/kaine/bxon.hpp @@ -4,7 +4,7 @@ #pragma once -#include +#include #include #include @@ -39,10 +39,10 @@ namespace kaine { template typename std::enable_if::value, std::shared_ptr>::type get_instance() { - if (T::get_name() != name) { - throw dragon::exception::invalid_data("expected type to be " + name + " instead got " + T::get_name()); + if (name != T::bxon_name) { + throw dragon::exception::invalid_data("expected type to be " + name + " instead got " + T::bxon_name); } return std::make_shared(data); } }; -} // namespace kaine \ No newline at end of file +}// namespace kaine \ No newline at end of file diff --git a/kaine/public/kaine/bxon_types.hpp b/kaine/public/kaine/bxon_types.hpp new file mode 100644 index 0000000..62965ad --- /dev/null +++ b/kaine/public/kaine/bxon_types.hpp @@ -0,0 +1,10 @@ +// +// Created by Lilith on 2021-04-25. +// + +#pragma once + +#include + +#include +#include diff --git a/kaine/public/kaine/bxon/types/abstract_bxon.hpp b/kaine/public/kaine/bxon_types/abstract_bxon.hpp similarity index 85% rename from kaine/public/kaine/bxon/types/abstract_bxon.hpp rename to kaine/public/kaine/bxon_types/abstract_bxon.hpp index 58f1aa8..c176caf 100644 --- a/kaine/public/kaine/bxon/types/abstract_bxon.hpp +++ b/kaine/public/kaine/bxon_types/abstract_bxon.hpp @@ -9,4 +9,4 @@ namespace kaine::bxon_types { public: virtual ~abstract_bxon() noexcept = default; }; -} // namespace kaine::bxon_types \ No newline at end of file +}// namespace kaine::bxon_types \ No newline at end of file diff --git a/kaine/public/kaine/bxon/types/tp_archive_file_param.hpp b/kaine/public/kaine/bxon_types/tp_archive_file_param.hpp similarity index 92% rename from kaine/public/kaine/bxon/types/tp_archive_file_param.hpp rename to kaine/public/kaine/bxon_types/tp_archive_file_param.hpp index a7ec14e..9eb5668 100644 --- a/kaine/public/kaine/bxon/types/tp_archive_file_param.hpp +++ b/kaine/public/kaine/bxon_types/tp_archive_file_param.hpp @@ -4,8 +4,8 @@ #pragma once -#include -#include +#include +#include #include #include @@ -64,6 +64,6 @@ namespace kaine::bxon_types { std::shared_ptr> read_file(kaine::arc &archive, uint32_t hash); static std::shared_ptr> read_file(kaine::arc &archive, ArchiveFileParam ¶m); - static std::string get_name() { return "tpArchiveFileParam"; } + static constexpr const char *bxon_name = "tpArchiveFileParam"; }; -} // namespace kaine::bxon_types \ No newline at end of file +}// namespace kaine::bxon_types \ No newline at end of file diff --git a/kaine/public/kaine/bxon_types/tp_gx_tex_head.hpp b/kaine/public/kaine/bxon_types/tp_gx_tex_head.hpp new file mode 100644 index 0000000..7ec91e9 --- /dev/null +++ b/kaine/public/kaine/bxon_types/tp_gx_tex_head.hpp @@ -0,0 +1,74 @@ +// +// Created by Lilith on 2021-04-25. +// + +#pragma once + +#include +#include + +#include +#include + +#include + +namespace kaine::bxon_types { + class KAINE_EXPORT tp_gx_tex_head : public abstract_bxon { + private: + static constexpr uintptr_t EXPECTED_DATA_SIZE = 0x24; + static constexpr uintptr_t MIP_SURFACE_OFFSET = 0x20; + + public: + explicit tp_gx_tex_head(std::shared_ptr> &buffer); + ~tp_gx_tex_head() override = default; + +#pragma pack(push, 4) + typedef struct TEX_HEAD_MIP_SURFACE { + uint32_t offset; + uint32_t unknown_1; + uint32_t unknown_2; + uint32_t unknown_3; + uint32_t size; + uint32_t unknown_5; + uint32_t width; + uint32_t height; + uint32_t unknown_8; + uint32_t unknown_9; + } TexHeadMip; + DRAGON_ASSERT(sizeof(TEX_HEAD_MIP_SURFACE) == 0x28, "ArchiveArcParam has an invalid size"); + + enum class XonSurfaceFormat : uint32_t { + UNKNOWN = 0, + R8G8B8A8_UNORM = 0x00010800, + R8G8B8A8_UNORM_SRGB = 0x00010B00, + BC1_UNORM = 0x00010F00, + BC1_UNORM_SRGB = 0x00011000, + BC2_UNORM = 0x00011100, + BC2_UNORM_SRGB = 0x00011200, + BC3_UNORM = 0x00011300, + BC3_UNORM_SRGB = 0x00011400, + BC4_UNORM = 0x00011500, + BC5_UNORM = 0x00011600, + R32G32B32A32_FLOAT = 0x00030000, + }; + + struct { + uint32_t width = 0; + uint32_t height = 0; + uint32_t surfaces = 0; + uint32_t unknown_1 = 0; + uint32_t total_image_size = 0; + uint32_t unknown_2 = 0; + XonSurfaceFormat format = XonSurfaceFormat::UNKNOWN; + uint32_t mip_surface_count = 0; + uint32_t rel_offset_mip_surface = 0; + }; +#pragma pack(pop) + + dragon::Array mip_surfaces; + + std::shared_ptr> generate_dds(std::shared_ptr> &resource, uintptr_t *offset) const; + + static constexpr const char *bxon_name = "tpGxTexHead"; + }; +}// namespace kaine::bxon_types diff --git a/kaine/public/kaine/kaine_export_clang.a.h b/kaine/public/kaine/generated/kaine_export_clang.a.h similarity index 100% rename from kaine/public/kaine/kaine_export_clang.a.h rename to kaine/public/kaine/generated/kaine_export_clang.a.h diff --git a/kaine/public/kaine/kaine_export_linux.a.h b/kaine/public/kaine/generated/kaine_export_linux.a.h similarity index 100% rename from kaine/public/kaine/kaine_export_linux.a.h rename to kaine/public/kaine/generated/kaine_export_linux.a.h diff --git a/kaine/public/kaine/kaine_export_win.a.h b/kaine/public/kaine/generated/kaine_export_win.a.h similarity index 100% rename from kaine/public/kaine/kaine_export_win.a.h rename to kaine/public/kaine/generated/kaine_export_win.a.h diff --git a/kaine/public/kaine/kaine.hpp b/kaine/public/kaine/kaine.hpp index c841edd..917549a 100644 --- a/kaine/public/kaine/kaine.hpp +++ b/kaine/public/kaine/kaine.hpp @@ -12,13 +12,13 @@ #include -#include -#include -#include +#include +#include +#include #include namespace kaine { KAINE_EXPORT std::string get_version_str(); KAINE_EXPORT int get_version(); -} // namespace kaine +}// namespace kaine diff --git a/kaine/public/kaine/kaine_export.h b/kaine/public/kaine/kaine_export.h index 6ac65df..b65f2fa 100644 --- a/kaine/public/kaine/kaine_export.h +++ b/kaine/public/kaine/kaine_export.h @@ -6,10 +6,10 @@ #ifdef _WIN32 #ifdef _WIN32_CLANG -#include +#include #else -#include +#include #endif #else -#include +#include #endif diff --git a/kaine/public/kaine/pack/pack.hpp b/kaine/public/kaine/pack.hpp similarity index 82% rename from kaine/public/kaine/pack/pack.hpp rename to kaine/public/kaine/pack.hpp index bb3bc65..79059b9 100644 --- a/kaine/public/kaine/pack/pack.hpp +++ b/kaine/public/kaine/pack.hpp @@ -24,19 +24,19 @@ namespace kaine { static constexpr uint32_t PRELOAD_NAME_OFFSET = 0x4; static constexpr uint32_t FILE_NAME_OFFSET = 0x4; static constexpr uint32_t FILE_DATA_OFFSET = 0xC; - static constexpr uint32_t FILE_STR_OFFSET = 0x10; // unused + static constexpr uint32_t FILE_STR_OFFSET = 0x10;// unused public: explicit pack(dragon::Array &buffer); ~pack() = default; #pragma pack(push, 4) - typedef struct XAP_PRELOAD { + typedef struct XAP_DEPENDENCY { uint32_t id; uint32_t rel_offset_name; uint32_t unknown; - } XapPreload; - DRAGON_ASSERT(sizeof(XapPreload) == 0xC, "XapPreload has an invalid size"); + } XapDependency; + DRAGON_ASSERT(sizeof(XAP_DEPENDENCY) == 0xC, "XAP_DEPENDENCY has an invalid size"); typedef struct XAP_FILE { uint32_t id; @@ -45,7 +45,7 @@ namespace kaine { uint32_t rel_offset_data; uint32_t rel_offset_str; } XapFile; - DRAGON_ASSERT(sizeof(XapFile) == 0x14, "XapFile has an invalid size"); + DRAGON_ASSERT(sizeof(XAP_FILE) == 0x14, "XAP_FILE has an invalid size"); struct { uint32_t magic = FOURCC; @@ -62,8 +62,8 @@ namespace kaine { }; #pragma pack(pop) - dragon::Array preload; - std::map preload_names; + dragon::Array dependencies; + std::map dependency_names; dragon::Array headers; std::map header_names; @@ -75,4 +75,4 @@ namespace kaine { std::shared_ptr> resource; }; -} // namespace kaine +}// namespace kaine diff --git a/research/pack.txt b/research/pack.txt index a9c8f8e..36e9824 100644 --- a/research/pack.txt +++ b/research/pack.txt @@ -9,15 +9,15 @@ header: total_size (4) serialized_size (4) note: this is the size of the PACK data, seeking to this number will be where resource data starts. resource_size (4) note: this is data that exists inherently in the pack, always after all the files. - note 2: keep track of the offset, each bxon doesn't specify resource offset. alignment is 0x80. - preload_count (4) - rel_offset_preload_table (4) -> preload[] + note 2: keep track of the offset, each bxon doesn't specify resource offset. alignment is 0x40. + dependency_count (4) + rel_offset_dependency_table (4) -> dependency[] pack_count (4) rel_offset_header_table (4) -> file[] file_count (4) rel_offset_file_table (4) -> file[] -preload: +dependency: id (4) rel_offset_name (4) -> null terminated string unknown (4) diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt index c7874d8..f47028e 100644 --- a/tool/CMakeLists.txt +++ b/tool/CMakeLists.txt @@ -1,3 +1,4 @@ project(TOOL) add_subdirectory("emil") +add_subdirectory("kaineconv") diff --git a/tool/emil/emil.cpp b/tool/emil/emil.cpp index 3473771..6082bef 100644 --- a/tool/emil/emil.cpp +++ b/tool/emil/emil.cpp @@ -2,7 +2,9 @@ // Created by Lilith on 2021-04-24. // -#include +// emil extracts xap files from arc files. + +#include #include void process_dir(const std::filesystem::path &data_dir, const std::filesystem::path &target_dir) { @@ -12,9 +14,16 @@ void process_dir(const std::filesystem::path &data_dir, const std::filesystem::p std::shared_ptr file = std::make_shared(info_path, std::ios::binary | std::ios::in); auto info_arc = kaine::arc(file, true); auto info_data = info_arc.get_file(0, 0); + auto info_name = data_dir.filename().string() + "_info.bxon"; auto info_bxon = kaine::bxon(*info_data); auto info = info_bxon.get_instance(); + std::cout << "saving " << info_name << std::endl; + if (!std::filesystem::exists(target_dir)) { + std::filesystem::create_directories(target_dir); + } + dragon::write_file(target_dir / info_name, *info_data); + std::vector archives; archives.reserve(info->archive_count); for (auto i = 0; i < info->archive_count; ++i) { @@ -23,50 +32,21 @@ void process_dir(const std::filesystem::path &data_dir, const std::filesystem::p } for (auto ¶m : info->files) { - auto dest = target_dir / info->file_names[param.hash]; + auto dest = target_dir / (info->file_names[param.hash] + ".xap"); auto archive = archives[param.index]; auto data = info->read_file(archive, param); if (data == nullptr) { continue; } - auto xap = kaine::pack(*data); - - for (const auto &xap_header : xap.headers) { - auto header_dest = dest / xap.header_names[xap_header.id]; - auto dest_path = header_dest.parent_path(); + std::cout << "saving " << (info->file_names[param.hash] + ".xap"); - if (!std::filesystem::exists(dest_path)) { - std::filesystem::create_directories(dest_path); - } - - dragon::write_file(header_dest, *xap.header_data[xap_header.id]); + auto dest_path = dest.parent_path(); + if (!std::filesystem::exists(dest_path)) { + std::filesystem::create_directories(dest_path); } - for (const auto &xap_file : xap.files) { - auto file_dest = dest / xap.file_names[xap_file.id]; - auto dest_path = file_dest.parent_path(); - - if (!std::filesystem::exists(dest_path)) { - std::filesystem::create_directories(dest_path); - } - - std::cout << info->file_names[param.hash] << "/" << xap.file_names[xap_file.id] << std::endl; - - dragon::write_file(file_dest, *xap.file_data[xap_file.id]); - } - - if(xap.resource != nullptr) { - auto file_dest = dest / xap.header_names[xap.headers[0].id]; - file_dest.replace_extension(".xap.asset"); - auto dest_path = file_dest.parent_path(); - - if (!std::filesystem::exists(dest_path)) { - std::filesystem::create_directories(dest_path); - } - - dragon::write_file(file_dest, *xap.resource); - } + dragon::write_file(dest_path, *data); } } diff --git a/tool/emil/emil.hpp b/tool/emil/emil.hpp deleted file mode 100644 index 6739457..0000000 --- a/tool/emil/emil.hpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by Lilith on 2021-04-24. -// - -#pragma once diff --git a/tool/kaineconv/CMakeLists.txt b/tool/kaineconv/CMakeLists.txt new file mode 100644 index 0000000..f5e5718 --- /dev/null +++ b/tool/kaineconv/CMakeLists.txt @@ -0,0 +1,8 @@ +project(TOOL_kaineconv) + +add_executable(kaineconv kaineconv.cpp) +target_link_libraries(kaineconv kaine) +target_link_libraries(kaineconv standard_dragon) + +include(GNUInstallDirs) +install(TARGETS kaineconv RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/tool/kaineconv/kaineconv.cpp b/tool/kaineconv/kaineconv.cpp new file mode 100644 index 0000000..4b50b65 --- /dev/null +++ b/tool/kaineconv/kaineconv.cpp @@ -0,0 +1,84 @@ +// +// Created by Lilith on 2021-04-25. +// + +#include +#include +#include + +typedef std::shared_ptr> (*convert_bxon)(kaine::bxon &bxon, std::shared_ptr> &resources, uintptr_t *offset); + +std::shared_ptr> convert_gxtex(kaine::bxon &bxon, std::shared_ptr> &resources, uintptr_t *offset) { + auto tex_head = bxon.get_instance(); + return tex_head->generate_dds(resources, offset); +} + +typedef struct KAINE_CONV_HANDLER { + const char *name; + const char *extension; + convert_bxon convert; +} KaineConverterInfo; + +const KaineConverterInfo Handlers[] = { + {kaine::bxon_types::tp_gx_tex_head::bxon_name, ".dds", convert_gxtex}, + {nullptr, nullptr, nullptr}}; + +std::shared_ptr> convert(kaine::bxon &bxon, std::shared_ptr> &resources, uintptr_t *offset, std::filesystem::path &path) { + auto i = 0; + while (true) { + if (Handlers[i].convert == nullptr) { + break; + } + + if (Handlers[i].name == bxon.name) { + auto result = Handlers[i].convert(bxon, resources, offset); + if (result == nullptr) { + continue; + } + if (Handlers[i].extension != nullptr) { + path = path.replace_extension(Handlers[i].extension); + } + return result; + } + } + std::cerr << "cannot convert type " << bxon.name << "!" << std::endl; + return nullptr; +} + +int main(int argc, char **argv) { + for (auto i = 1; i < argc; ++i) { + auto path = std::filesystem::path(argv[i]); + if (!std::filesystem::exists(path)) { + std::cerr << argv[i] << " does not exist" << std::endl; + continue; + } + try { + auto pack_data = dragon::read_file(path); + auto pack = kaine::pack(pack_data); + path = path.replace_extension(); + uintptr_t offset = 0; + for (const auto &file : pack.files) { + auto file_name = pack.file_names[file.id]; + auto file_path = path / file_name; + try { + auto bxon = kaine::bxon(*pack.file_data[file.id]); + std::cout << file_name << std::endl; + auto converted_data = convert(bxon, pack.resource, &offset, file_path); + if (converted_data == nullptr) { + continue; + } + auto file_dir = file_path.parent_path(); + if (!std::filesystem::exists(file_dir)) { + std::filesystem::create_directories(file_dir); + } + dragon::write_file(file_path, *converted_data); + offset = dragon::Align(offset, 0x40); + } catch (std::exception &exception) { + std::cerr << "can't convert " << file_name << " - error: " << exception.what() << std::endl; + } + } + } catch (std::exception &exception) { + std::cerr << "can't convert " << argv[i] << " - error: " << exception.what() << std::endl; + } + } +} \ No newline at end of file diff --git a/vendor/standard_dragon b/vendor/standard_dragon index 985bbeb..11ca6e4 160000 --- a/vendor/standard_dragon +++ b/vendor/standard_dragon @@ -1 +1 @@ -Subproject commit 985bbeb168dfcac79994bcec94b416483579674f +Subproject commit 11ca6e4c721776809bc54eb7a1a62eba077f8806