diff options
Diffstat (limited to 'src/factories/TextureFactory.cpp')
| -rw-r--r-- | src/factories/TextureFactory.cpp | 176 |
1 files changed, 157 insertions, 19 deletions
diff --git a/src/factories/TextureFactory.cpp b/src/factories/TextureFactory.cpp index 5a0caad..6f1de04 100644 --- a/src/factories/TextureFactory.cpp +++ b/src/factories/TextureFactory.cpp @@ -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,105 @@ 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); + 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); +} + +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); @@ -196,5 +334,5 @@ 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); } |
