Added asset mods support

This commit is contained in:
KiritoDv
2024-02-21 20:38:05 -06:00
committed by Lywx
parent 3845d02cf6
commit 70a6bb7cf1
27 changed files with 10731 additions and 35 deletions
+12 -5
View File
@@ -122,22 +122,29 @@ else()
endif()
# Fetch Dependencies
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/binarytools)
if(EXISTS "/mnt/c/WINDOWS/system32/wsl.exe")
FetchContent_Declare(
GSL
GIT_REPOSITORY https://github.com/Microsoft/GSL.git
GIT_TAG a3534567187d2edc428efd3f13466ff75fe5805c
)
FetchContent_MakeAvailable(GSL)
target_link_libraries(${PROJECT_NAME} PRIVATE GSL)
endif()
)
FetchContent_MakeAvailable(GSL)
target_link_libraries(${PROJECT_NAME} PRIVATE GSL)
endif()
# Link BinaryTools
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/binarytools)
add_dependencies(${PROJECT_NAME} BinaryTools)
target_link_libraries(${PROJECT_NAME} PRIVATE BinaryTools)
# Link n64graphics
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/n64graphics)
add_dependencies(${PROJECT_NAME} N64Graphics)
target_link_libraries(${PROJECT_NAME} PRIVATE N64Graphics)
# Link StormLib
set(STORMLIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/StormLib)
+10
View File
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.12)
project(N64Graphics)
set(CMAKE_CXX_STANDARD 20)
file(GLOB CXX_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
set(SRC_DIR ${CXX_FILES})
add_library(${PROJECT_NAME} STATIC ${SRC_DIR})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
#ifndef N64GRAPHICS_H_
#define N64GRAPHICS_H_
#include <stdint.h>
// intermediate formats
typedef struct _rgba
{
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
} rgba;
typedef struct _ia
{
uint8_t intensity;
uint8_t alpha;
} ia;
// CI palette
typedef struct
{
uint16_t data[256];
int max; // max number of entries
int used; // number of entries used
} palette_t;
//---------------------------------------------------------
// N64 RGBA/IA/I/CI -> intermediate RGBA/IA
//---------------------------------------------------------
// N64 raw RGBA16/RGBA32 -> intermediate RGBA
rgba *raw2rgba(const uint8_t *raw, int width, int height, int depth);
// N64 raw IA1/IA4/IA8/IA16 -> intermediate IA
ia *raw2ia(const uint8_t *raw, int width, int height, int depth);
// N64 raw I4/I8 -> intermediate IA
ia *raw2i(const uint8_t *raw, int width, int height, int depth);
//---------------------------------------------------------
// intermediate RGBA/IA -> N64 RGBA/IA/I/CI
// returns length written to 'raw' used or -1 on error
//---------------------------------------------------------
// intermediate RGBA -> N64 raw RGBA16/RGBA32
int rgba2raw(uint8_t *raw, const rgba *img, int width, int height, int depth);
// intermediate IA -> N64 raw IA1/IA4/IA8/IA16
int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
// intermediate IA -> N64 raw I4/I8
int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
//---------------------------------------------------------
// N64 CI <-> N64 RGBA16/IA16
//---------------------------------------------------------
// N64 CI raw data and palette to raw data (either RGBA16 or IA16)
uint8_t *ci2raw(const uint8_t *rawci, const uint8_t *palette, int width, int height, int ci_depth);
// convert from raw (RGBA16 or IA16) format to CI + palette
int raw2ci(uint8_t *rawci, palette_t *pal, const uint8_t *raw, int raw_len, int ci_depth);
//---------------------------------------------------------
// intermediate RGBA/IA -> PNG
//---------------------------------------------------------
// intermediate RGBA write to PNG file
int rgba2png(unsigned char** png_output, int* size_output, const rgba* img, int width, int height);
// intermediate IA write to grayscale PNG file
int ia2png(unsigned char** png_output, int* size_output, const ia* img, int width, int height);
//---------------------------------------------------------
// PNG -> intermediate RGBA/IA
//---------------------------------------------------------
// PNG file -> intermediate RGBA
rgba *png2rgba(unsigned char* png_input, int size_input, int *width, int *height);
// PNG file -> intermediate IA
ia *png2ia(unsigned char* png_input, int size_input, int *width, int *height);
//---------------------------------------------------------
// version
//---------------------------------------------------------
// get version of underlying graphics reading library
const char *n64graphics_get_read_version(void);
// get version of underlying graphics writing library
const char *n64graphics_get_write_version(void);
#endif // N64GRAPHICS_H_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+89 -3
View File
@@ -18,6 +18,7 @@
#include "factories/LightsFactory.h"
#include "factories/mk64/WaypointFactory.h"
#include "spdlog/spdlog.h"
#include "hj/sha1.h"
#include <fstream>
#include <iostream>
@@ -79,7 +80,29 @@ void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binar
return;
}
auto result = factory->get()->parse(this->gRomData, node);
auto impl = factory->get();
std::optional<std::shared_ptr<IParsedData>> result;
if(this->gConfig.modding) {
if(impl->SupportModdedAssets() && this->gModdedAssetPaths.contains(name)) {
auto path = fs::path(this->gConfig.moddingPath) / this->gModdedAssetPaths[name];
if(!fs::exists(path)) {
SPDLOG_ERROR("Modded asset {} not found", this->gModdedAssetPaths[name]);
return;
}
std::ifstream input(path, std::ios::binary);
std::vector<uint8_t> data = std::vector<uint8_t>( std::istreambuf_iterator( input ), {});
input.close();
result = factory->get()->parse_modding(data, node);
} else {
result = factory->get()->parse(this->gRomData, node);
}
} else {
result = factory->get()->parse(this->gRomData, node);
}
if(!result.has_value()){
SPDLOG_ERROR("Failed to process {}", name);
return;
@@ -117,6 +140,29 @@ void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binar
binary->CreateFile(name, std::vector(data.begin(), data.end()));
break;
}
case ExportType::Modding: {
stream.str("");
stream.clear();
std::string ogname = name;
exporter->get()->Export(stream, result.value(), name, node, &name);
auto data = stream.str();
if(data.empty()) {
break;
}
std::string dpath = Instance->GetOutputPath() + "/" + name;
if(!exists(fs::path(dpath).parent_path())){
create_directories(fs::path(dpath).parent_path());
}
this->gModdedAssetPaths[ogname] = name;
std::ofstream file(dpath, std::ios::binary);
file.write(data.c_str(), data.size());
file.close();
break;
}
default: {
exporter->get()->Export(stream, result.value(), name, node, &name);
@@ -141,6 +187,20 @@ void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binar
}
}
void Companion::ParseModdingConfig() {
auto path = fs::path(this->gConfig.moddingPath) / "modding.yml";
if(!fs::exists(path)) {
throw std::runtime_error("No modding config found, please run in export mode first");
}
auto modding = YAML::LoadFile(path);
for(auto assets = modding["assets"].begin(); assets != modding["assets"].end(); ++assets) {
auto name = assets->first.as<std::string>();
auto asset = assets->second.as<std::string>();
this->gModdedAssetPaths[name] = asset;
}
}
void Companion::ParseCurrentFileConfig(YAML::Node node) {
if(node["segments"]) {
for(auto segment = node["segments"].begin(); segment != node["segments"].end(); ++segment) {
@@ -214,7 +274,9 @@ void Companion::Process() {
auto path = rom["path"].as<std::string>();
auto opath = cfg["output"];
auto gbi = cfg["gbi"];
auto modding_path = opath && opath["modding"] ? opath["modding"].as<std::string>() : "modding";
this->gConfig.moddingPath = modding_path;
switch (this->gConfig.exporterType) {
case ExportType::Binary: {
this->gConfig.outputPath = opath && opath["binary"] ? opath["binary"].as<std::string>() : "generic.otr";
@@ -228,6 +290,10 @@ void Companion::Process() {
this->gConfig.outputPath = opath && opath["code"] ? opath["code"].as<std::string>() : "code";
break;
}
case ExportType::Modding: {
this->gConfig.outputPath = modding_path;
break;
}
}
if(gbi) {
@@ -264,6 +330,10 @@ void Companion::Process() {
};
}
if(this->gConfig.exporterType == ExportType::Code && this->gConfig.modding) {
this->ParseModdingConfig();
}
if(std::holds_alternative<std::vector<std::string>>(this->gWriteOrder)) {
for (auto& [key, _] : this->gFactories) {
auto entries = std::get<std::vector<std::string>>(this->gWriteOrder);
@@ -415,8 +485,20 @@ void Companion::Process() {
spdlog::set_pattern(line);
}
if(this->gConfig.exporterType != ExportType::Binary){
auto fsout = fs::path(this->gConfig.outputPath);
auto fsout = fs::path(this->gConfig.outputPath);
if(this->gConfig.exporterType == ExportType::Modding) {
fsout /= "modding.yml";
YAML::Node modding;
for (const auto& [key, value] : this->gModdedAssetPaths) {
modding["assets"][key] = value;
}
std::ofstream file(fsout.string(), std::ios::binary);
file << modding;
file.close();
} else if(this->gConfig.exporterType != ExportType::Binary){
std::string filename = this->gCurrentDirectory.filename().string();
switch (this->gConfig.exporterType) {
@@ -627,4 +709,8 @@ std::optional<std::tuple<std::string, YAML::Node>> Companion::GetNodeByAddr(cons
std::string Companion::NormalizeAsset(const std::string& name) const {
auto path = fs::path(this->gCurrentFile).stem().string() + "_" + name;
return path;
}
std::string Companion::CalculateHash(const std::vector<uint8_t>& data) {
return Chocobo1::SHA1().addData(data).finalize().toString();
}
+10 -3
View File
@@ -42,18 +42,21 @@ struct TorchConfig {
GBIConfig gbi;
SegmentConfig segment;
std::string outputPath;
std::string moddingPath;
ExportType exporterType;
bool otrMode;
bool debug;
bool modding;
};
class Companion {
public:
static Companion* Instance;
explicit Companion(std::filesystem::path rom, const bool otr, const bool debug) : gRomPath(std::move(rom)), gCartridge(nullptr) {
explicit Companion(std::filesystem::path rom, const bool otr, const bool debug, const bool modding = false) : gRomPath(std::move(rom)), gCartridge(nullptr) {
this->gConfig.otrMode = otr;
this->gConfig.debug = debug;
this->gConfig.modding = modding;
}
void Init(ExportType type);
@@ -73,6 +76,7 @@ public:
std::optional<std::tuple<std::string, YAML::Node>> GetNodeByAddr(uint32_t addr);
std::optional<std::shared_ptr<BaseFactory>> GetFactory(const std::string& type);
static std::string CalculateHash(const std::vector<uint8_t>& data);
static void Pack(const std::string& folder, const std::string& output);
std::string NormalizeAsset(const std::string& name) const;
@@ -81,6 +85,7 @@ public:
std::optional<std::tuple<std::string, YAML::Node>> RegisterAsset(const std::string& name, YAML::Node& node);
private:
TorchConfig gConfig;
YAML::Node gModdingConfig;
fs::path gCurrentDirectory;
std::vector<uint8_t> gRomData;
std::filesystem::path gRomPath;
@@ -92,11 +97,13 @@ private:
uint32_t gCurrentPad = 0;
std::variant<std::vector<std::string>, std::string> gWriteOrder;
std::unordered_map<std::string, std::shared_ptr<BaseFactory>> gFactories;
std::map<std::string, std::map<std::string, std::pair<YAML::Node, bool>>> gAssetDependencies;
std::map<std::string, std::map<std::string, std::vector<std::pair<uint32_t, std::string>>>> gWriteMap;
std::unordered_map<std::string, std::string> gModdedAssetPaths;
std::unordered_map<std::string, std::map<std::string, std::pair<YAML::Node, bool>>> gAssetDependencies;
std::unordered_map<std::string, std::map<std::string, std::vector<std::pair<uint32_t, std::string>>>> gWriteMap;
std::unordered_map<std::string, std::unordered_map<uint32_t, std::tuple<std::string, YAML::Node>>> gAddrMap;
void ParseCurrentFileConfig(YAML::Node node);
void ParseModdingConfig();
void RegisterFactory(const std::string& type, const std::shared_ptr<BaseFactory>& factory);
void ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary);
};
+4
View File
@@ -5,7 +5,11 @@
class AudioHeaderFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {};
}
bool SupportModdedAssets() override { return false; }
};
+4
View File
@@ -20,9 +20,13 @@ class BankBinaryExporter : public BaseExporter {
class BankFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Binary, BankBinaryExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
+3
View File
@@ -26,6 +26,7 @@ enum class ExportType {
Header,
Code,
Binary,
Modding,
};
template<typename T>
@@ -72,6 +73,7 @@ public:
class BaseFactory {
public:
virtual std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) = 0;
virtual std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) = 0;
std::optional<std::shared_ptr<BaseExporter>> GetExporter(ExportType type) {
auto exporters = this->GetExporters();
if (exporters.find(type) != exporters.end()) {
@@ -79,6 +81,7 @@ public:
}
return std::nullopt;
}
virtual bool SupportModdedAssets() = 0;
private:
virtual std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() = 0;
};
+4
View File
@@ -13,10 +13,14 @@ class BlobCodeExporter : public BaseExporter {
class BlobFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Binary, BlobBinaryExporter)
REGISTER(Code, BlobCodeExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
+4
View File
@@ -25,6 +25,9 @@ class DListCodeExporter : public BaseExporter {
class DListFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Header, DListHeaderExporter)
@@ -32,4 +35,5 @@ public:
REGISTER(Code, DListCodeExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
+4
View File
@@ -56,6 +56,9 @@ class LightsCodeExporter : public BaseExporter {
class LightsFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Code, LightsCodeExporter)
@@ -63,4 +66,5 @@ public:
REGISTER(Binary, LightsBinaryExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
+4 -1
View File
@@ -19,10 +19,13 @@ class SampleBinaryExporter : public BaseExporter {
class SampleFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Binary, SampleBinaryExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
+4
View File
@@ -21,9 +21,13 @@ class SequenceBinaryExporter : public BaseExporter {
class SequenceFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Binary, SequenceBinaryExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
+157 -19
View File
@@ -4,18 +4,22 @@
#include "Companion.h"
#include <iomanip>
static const std::unordered_map <std::string, TextureType> gTextureTypes = {
{ "RGBA16", TextureType::RGBA16bpp },
{ "RGBA32", TextureType::RGBA32bpp },
{ "CI4", TextureType::Palette4bpp },
{ "CI8", TextureType::Palette8bpp },
{ "I4", TextureType::Grayscale4bpp },
{ "I8", TextureType::Grayscale8bpp },
{ "IA1", TextureType::GrayscaleAlpha1bpp },
{ "IA4", TextureType::GrayscaleAlpha4bpp },
{ "IA8", TextureType::GrayscaleAlpha8bpp },
{ "IA16", TextureType::GrayscaleAlpha16bpp },
{ "TLUT", TextureType::TLUT },
extern "C" {
#include "n64graphics/n64graphics.h"
}
static const std::unordered_map <std::string, TextureFormat> gTextureTypes = {
{ "RGBA16", { TextureType::RGBA16bpp, 16 } },
{ "RGBA32", { TextureType::RGBA32bpp, 32 } },
{ "CI4", { TextureType::Palette4bpp, 4 } },
{ "CI8", { TextureType::Palette8bpp, 8 } },
{ "I4", { TextureType::Grayscale4bpp, 4 } },
{ "I8", { TextureType::Grayscale8bpp, 8 } },
{ "IA1", { TextureType::GrayscaleAlpha1bpp, 1 } },
{ "IA4", { TextureType::GrayscaleAlpha4bpp, 4 } },
{ "IA8", { TextureType::GrayscaleAlpha8bpp, 8 } },
{ "IA16", { TextureType::GrayscaleAlpha16bpp, 16 } },
{ "TLUT", { TextureType::TLUT, 0 } },
};
size_t CalculateTextureSize(TextureType type, uint32_t width, uint32_t height) {
@@ -134,7 +138,7 @@ void TextureBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedD
WriteHeader(writer, LUS::ResourceType::Texture, 0);
writer.Write((uint32_t) texture->mType);
writer.Write((uint32_t) texture->mType.type);
writer.Write(texture->mWidth);
writer.Write(texture->mHeight);
@@ -143,6 +147,53 @@ void TextureBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedD
writer.Finish(write);
}
void TextureModdingExporter::Export(std::ostream&write, std::shared_ptr<IParsedData> data, std::string&entryName, YAML::Node&node, std::string* replacement) {
auto texture = std::static_pointer_cast<TextureData>(data);
auto format = texture->mType;
uint8_t* raw = new uint8_t[CalculateTextureSize(format.type, texture->mWidth, texture->mHeight) * 2];
int size = 0;
auto ext = GetSafeNode<std::string>(node, "format");
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
(*replacement) += "." + ext + ".png";
switch (format.type) {
case TextureType::RGBA16bpp:
case TextureType::RGBA32bpp: {
rgba* imgr = raw2rgba(texture->mBuffer.data(), texture->mWidth, texture->mHeight, format.depth);
if(rgba2png(&raw, &size, imgr, texture->mWidth, texture->mHeight)) {
throw std::runtime_error("Failed to convert texture to PNG");
}
break;
}
case TextureType::GrayscaleAlpha16bpp:
case TextureType::GrayscaleAlpha8bpp:
case TextureType::GrayscaleAlpha4bpp:
case TextureType::GrayscaleAlpha1bpp: {
ia* imgia = raw2ia(texture->mBuffer.data(), texture->mWidth, texture->mHeight, format.depth);
if(ia2png(&raw, &size, imgia, texture->mWidth, texture->mHeight)) {
throw std::runtime_error("Failed to convert texture to PNG");
}
break;
}
case TextureType::Grayscale8bpp:
case TextureType::Grayscale4bpp: {
ia* imgi = raw2i(texture->mBuffer.data(), texture->mWidth, texture->mHeight, format.depth);
if(ia2png(&raw, &size, imgi, texture->mWidth, texture->mHeight)) {
throw std::runtime_error("Failed to convert texture to PNG");
}
break;
}
default: {
SPDLOG_ERROR("Unsupported texture format for modding: {}", ext);
}
}
write.write(reinterpret_cast<char*>(raw), size);
}
std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
auto format = GetSafeNode<std::string>(node, "format");
uint32_t width;
@@ -161,9 +212,9 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
return std::nullopt;
}
TextureType type = gTextureTypes.at(format);
TextureFormat fmt = gTextureTypes.at(format);
if(type == TextureType::TLUT){
if(fmt.type == TextureType::TLUT){
width = GetSafeNode<uint32_t>(node, "colors");
height = 1;
} else {
@@ -171,18 +222,18 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
height = GetSafeNode<uint32_t>(node, "height");
}
size = GetSafeNode<uint32_t>(node, "size", CalculateTextureSize(gTextureTypes.at(format), width, height));
size = GetSafeNode<uint32_t>(node, "size", CalculateTextureSize(gTextureTypes.at(format).type, width, height));
auto [_, segment] = Decompressor::AutoDecode(node, buffer, size);
std::vector<uint8_t> result;
if(type == TextureType::GrayscaleAlpha1bpp){
if(fmt.type == TextureType::GrayscaleAlpha1bpp){
result = alloc_ia8_text_from_i1(reinterpret_cast<uint16_t*>(segment.data), 8, 16);
} else {
result = std::vector(segment.data, segment.data + segment.size);
}
SPDLOG_INFO("Texture: {}", format);
if(type == TextureType::TLUT){
if(fmt.type == TextureType::TLUT){
SPDLOG_INFO("Colors: {}", width);
} else {
SPDLOG_INFO("Width: {}", width);
@@ -196,5 +247,92 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
return std::nullopt;
}
return std::make_shared<TextureData>(type, width, height, result);
return std::make_shared<TextureData>(fmt, width, height, result);
}
std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse_modding(std::vector<uint8_t>& buffer, YAML::Node& node) {
auto format = GetSafeNode<std::string>(node, "format");
int width;
int height;
uint32_t size;
auto offset = GetSafeNode<uint32_t>(node, "offset");
if (format.empty()) {
SPDLOG_ERROR("Texture entry at {:X} in yaml missing format node\n\
Please add one of the following formats\n\
rgba16, rgba32, ia16, ia8, ia4, i8, i4, ci8, ci4, 1bpp, tlut", offset);
return std::nullopt;
}
if(!gTextureTypes.contains(format)) {
return std::nullopt;
}
TextureFormat fmt = gTextureTypes.at(format);
if(fmt.type == TextureType::TLUT){
width = GetSafeNode<uint32_t>(node, "colors");
height = 1;
} else {
width = GetSafeNode<uint32_t>(node, "width");
height = GetSafeNode<uint32_t>(node, "height");
}
uint8_t* raw;
switch (fmt.type) {
case TextureType::RGBA16bpp:
case TextureType::RGBA32bpp: {
const auto imgr = png2rgba(buffer.data(), buffer.size(), &width, &height);
size = width * height * fmt.depth / 8;
raw = new uint8_t[size];
if(rgba2raw(raw, imgr, width, height, fmt.depth) <= 0){
throw std::runtime_error("Failed to convert PNG to texture");
}
break;
}
case TextureType::GrayscaleAlpha16bpp:
case TextureType::GrayscaleAlpha8bpp:
case TextureType::GrayscaleAlpha4bpp:
case TextureType::GrayscaleAlpha1bpp: {
const auto imgia = png2ia(buffer.data(), buffer.size(), &width, &height);
size = width * height * fmt.depth / 8;
raw = new uint8_t[size];
if(ia2raw(raw, imgia, width, height, fmt.depth) <= 0){
throw std::runtime_error("Failed to convert PNG to texture");
}
break;
}
case TextureType::Grayscale8bpp:
case TextureType::Grayscale4bpp: {
const auto imgi = png2ia(buffer.data(), buffer.size(), &width, &height);
size = width * height * fmt.depth / 8;
raw = new uint8_t[size];
if(i2raw(raw, imgi, width, height, fmt.depth) <= 0){
throw std::runtime_error("Failed to convert PNG to texture");
}
break;
}
default: {
SPDLOG_ERROR("Unsupported texture format for modding: {}", format);
return std::nullopt;
}
}
auto result = std::vector(raw, raw + size);
SPDLOG_INFO("Texture: {}", format);
if(fmt.type == TextureType::TLUT){
SPDLOG_INFO("Colors: {}", width);
} else {
SPDLOG_INFO("Width: {}", width);
SPDLOG_INFO("Height: {}", height);
}
SPDLOG_INFO("Size: {}", size);
SPDLOG_INFO("Offset: 0x{:X}", offset);
SPDLOG_INFO("Is Compressed: {}", Decompressor::IsCompressed(node) ? "true" : "false");
if(result.size() == 0){
return std::nullopt;
}
return std::make_shared<TextureData>(fmt, width, height, result);
}
+14 -2
View File
@@ -17,14 +17,19 @@ enum class TextureType {
TLUT
};
struct TextureFormat {
TextureType type;
uint32_t depth;
};
class TextureData : public IParsedData {
public:
TextureType mType;
TextureFormat mType;
uint32_t mWidth;
uint32_t mHeight;
std::vector<uint8_t> mBuffer;
TextureData(TextureType type, uint32_t width, uint32_t height, std::vector<uint8_t>& buffer) : mType(type), mWidth(width), mHeight(height), mBuffer(std::move(buffer)) {}
TextureData(TextureFormat type, uint32_t width, uint32_t height, std::vector<uint8_t>& buffer) : mType(type), mWidth(width), mHeight(height), mBuffer(std::move(buffer)) {}
};
class TextureHeaderExporter : public BaseExporter {
@@ -39,14 +44,21 @@ class TextureBinaryExporter : public BaseExporter {
void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
};
class TextureModdingExporter : public BaseExporter {
void Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
};
class TextureFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override;
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Header, TextureHeaderExporter)
REGISTER(Binary, TextureBinaryExporter)
REGISTER(Code, TextureCodeExporter)
REGISTER(Modding, TextureModdingExporter)
};
}
bool SupportModdedAssets() override { return true; }
};
+4
View File
@@ -31,6 +31,9 @@ class VtxCodeExporter : public BaseExporter {
class VtxFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Code, VtxCodeExporter)
@@ -38,4 +41,5 @@ public:
REGISTER(Binary, VtxBinaryExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
+4
View File
@@ -33,6 +33,9 @@ namespace MK64 {
class WaypointFactory : public BaseFactory {
public:
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
return std::nullopt;
}
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Code, WaypointCodeExporter)
@@ -40,5 +43,6 @@ namespace MK64 {
REGISTER(Binary, WaypointBinaryExporter)
};
}
bool SupportModdedAssets() override { return false; }
};
}

Some files were not shown because too many files have changed in this diff Show More