mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
[WIP] Added palette and tlut export
This commit is contained in:
@@ -121,6 +121,37 @@ ia* raw2ia(const uint8_t* raw, int width, int height, int depth) {
|
||||
return img;
|
||||
}
|
||||
|
||||
ci* raw2ci_torch(const uint8_t* raw, int width, int height, int depth) {
|
||||
ci* img = NULL;
|
||||
int img_size;
|
||||
|
||||
img_size = width * height * sizeof(*img);
|
||||
img = malloc(img_size);
|
||||
if (!img) {
|
||||
ERROR("Error allocating %u bytes\n", img_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (depth) {
|
||||
case 8:
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
img[i].index = raw[i];
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
int pos = i / 2;
|
||||
img[i].index = i % 2 ? raw[pos] & 0xF : raw[pos] >> 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Error invalid depth %d\n", depth);
|
||||
break;
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
ia* raw2i(const uint8_t* raw, int width, int height, int depth) {
|
||||
ia* img = NULL;
|
||||
int img_size;
|
||||
@@ -303,6 +334,37 @@ int i2raw(uint8_t* raw, const ia* img, int width, int height, int depth) {
|
||||
return size;
|
||||
}
|
||||
|
||||
int ci2raw_torch(uint8_t* raw, const ci* img, int width, int height, int depth) {
|
||||
int size = width * height * depth / 8;
|
||||
INFO("Converting I%d %dx%d to raw\n", depth, width, height);
|
||||
|
||||
switch (depth) {
|
||||
case 8:
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
raw[i] = img[i].index;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for(int y = 0; y < height; y++) {
|
||||
for(int x = 0; x < width; x += 2) {
|
||||
const size_t pos = (y * width + x) / 2;
|
||||
|
||||
const uint8_t cR1 = img[y * width + x].index;
|
||||
const uint8_t cR2 = img[y * width + x + 1].index;
|
||||
|
||||
raw[pos] = cR1 << 4 | cR2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Error invalid depth %d\n", depth);
|
||||
size = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// internal RGBA/IA -> PNG
|
||||
//---------------------------------------------------------
|
||||
@@ -354,6 +416,27 @@ int ia2png(unsigned char** png_output, int* size_output, const ia* img, int widt
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ci2png(unsigned char** png_output, int* size_output, const ci* img, int width, int height) {
|
||||
int ret = 0;
|
||||
|
||||
// convert to format stb_image_write expects
|
||||
uint8_t* data = malloc(width * height);
|
||||
if (data) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
int idx = j * width + i;
|
||||
data[idx] = img[idx].index;
|
||||
}
|
||||
}
|
||||
|
||||
(*png_output) = stbi_write_plte_png_to_mem(data, 0, width, height, 1, NULL, 0, size_output);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PNG -> internal RGBA/IA
|
||||
//---------------------------------------------------------
|
||||
@@ -372,7 +455,7 @@ rgba* png2rgba(unsigned char* png_input, int size_input, int* width, int* height
|
||||
}
|
||||
INFO("Read %dx%d channels: %d\n", w, h, channels);
|
||||
|
||||
img_size = w * h * sizeof(*img);
|
||||
img_size = w * h * sizeof(rgba);
|
||||
img = malloc(img_size);
|
||||
if (!img) {
|
||||
ERROR("Error allocating %u bytes\n", img_size);
|
||||
@@ -421,6 +504,68 @@ rgba* png2rgba(unsigned char* png_input, int size_input, int* width, int* height
|
||||
return img;
|
||||
}
|
||||
|
||||
rgb* png2rgb(unsigned char* png_input, int size_input, int* width, int* height) {
|
||||
rgba* img = NULL;
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
int channels = 0;
|
||||
int img_size;
|
||||
|
||||
stbi_uc* data = stbi_load_from_memory(png_input, size_input, &w, &h, &channels, STBI_rgb);
|
||||
if (!data || w <= 0 || h <= 0) {
|
||||
ERROR("Error loading file\n");
|
||||
return NULL;
|
||||
}
|
||||
INFO("Read %dx%d channels: %d\n", w, h, channels);
|
||||
|
||||
img_size = w * h * sizeof(*img);
|
||||
img = malloc(img_size);
|
||||
if (!img) {
|
||||
ERROR("Error allocating %u bytes\n", img_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (channels) {
|
||||
case 3: // red, green, blue
|
||||
case 4: // red, green, blue
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int idx = j * w + i;
|
||||
img[idx].red = data[channels * idx];
|
||||
img[idx].green = data[channels * idx + 1];
|
||||
img[idx].blue = data[channels * idx + 2];
|
||||
if (channels == 4) {
|
||||
img[idx].alpha = data[channels * idx + 3];
|
||||
} else {
|
||||
img[idx].alpha = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // grey, alpha
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int idx = j * w + i;
|
||||
img[idx].red = data[2 * idx];
|
||||
img[idx].green = data[2 * idx];
|
||||
img[idx].blue = data[2 * idx];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Don't know how to read channels: %d\n", channels);
|
||||
free(img);
|
||||
img = NULL;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
stbi_image_free(data);
|
||||
|
||||
*width = w;
|
||||
*height = h;
|
||||
return img;
|
||||
}
|
||||
|
||||
ia* png2ia(unsigned char* png_input, int size_input, int* width, int* height) {
|
||||
ia* img = NULL;
|
||||
int w = 0, h = 0;
|
||||
@@ -481,6 +626,58 @@ ia* png2ia(unsigned char* png_input, int size_input, int* width, int* height) {
|
||||
return img;
|
||||
}
|
||||
|
||||
ci* png2ci(unsigned char* png_input, int size_input, int* width, int* height) {
|
||||
ci* img = NULL;
|
||||
int w = 0, h = 0;
|
||||
int channels = 0;
|
||||
int img_size;
|
||||
|
||||
stbi_uc* data = stbi_load_from_memory(png_input, size_input, &w, &h, &channels, STBI_default);
|
||||
if (!data || w <= 0 || h <= 0) {
|
||||
ERROR("Error loading file\n");
|
||||
return NULL;
|
||||
}
|
||||
INFO("Read %dx%d channels: %d\n", w, h, channels);
|
||||
|
||||
img_size = w * h * sizeof(*img);
|
||||
img = malloc(img_size);
|
||||
if (!img) {
|
||||
ERROR("Error allocating %d bytes\n", img_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (channels) {
|
||||
case 3: // red, green, blue
|
||||
case 4: // red, green, blue, alpha
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int idx = j * w + i;
|
||||
img[idx].index = data[channels * idx];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // grey, alpha
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int idx = j * w + i;
|
||||
img[idx].index = data[2 * idx];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Don't know how to read channels: %d\n", channels);
|
||||
free(img);
|
||||
img = NULL;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
stbi_image_free(data);
|
||||
|
||||
*width = w;
|
||||
*height = h;
|
||||
return img;
|
||||
}
|
||||
|
||||
// find index of palette color
|
||||
// return -1 if not found
|
||||
static int pal_find_color(const palette_t* pal, uint16_t val) {
|
||||
|
||||
@@ -12,12 +12,23 @@ typedef struct _rgba
|
||||
uint8_t alpha;
|
||||
} rgba;
|
||||
|
||||
typedef struct _rgb
|
||||
{
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
} rgb;
|
||||
|
||||
typedef struct _ia
|
||||
{
|
||||
uint8_t intensity;
|
||||
uint8_t alpha;
|
||||
} ia;
|
||||
|
||||
typedef struct _ci {
|
||||
uint8_t index;
|
||||
} ci;
|
||||
|
||||
// CI palette
|
||||
typedef struct
|
||||
{
|
||||
@@ -39,6 +50,9 @@ 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);
|
||||
|
||||
// N64 raw CI4/CI8 -> intermediate CI
|
||||
ci* raw2ci_torch(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
|
||||
@@ -53,6 +67,9 @@ 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);
|
||||
|
||||
// intermediate CI -> N64 raw CI4/CI8
|
||||
int ci2raw_torch(uint8_t* raw, const ci* img, int width, int height, int depth);
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// N64 CI <-> N64 RGBA16/IA16
|
||||
@@ -64,7 +81,6 @@ uint8_t *ci2raw(const uint8_t *rawci, const uint8_t *palette, int width, int hei
|
||||
// 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
|
||||
//---------------------------------------------------------
|
||||
@@ -75,6 +91,8 @@ int rgba2png(unsigned char** png_output, int* size_output, const rgba* img, int
|
||||
// intermediate IA write to grayscale PNG file
|
||||
int ia2png(unsigned char** png_output, int* size_output, const ia* img, int width, int height);
|
||||
|
||||
int ci2png(unsigned char** png_output, int* size_output, const ci* img, int width, int height);
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PNG -> intermediate RGBA/IA
|
||||
@@ -83,9 +101,15 @@ int ia2png(unsigned char** png_output, int* size_output, const ia* img, int widt
|
||||
// PNG file -> intermediate RGBA
|
||||
rgba *png2rgba(unsigned char* png_input, int size_input, int *width, int *height);
|
||||
|
||||
// PNG file -> intermediate RGB
|
||||
rgb* png2rgb(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);
|
||||
|
||||
// PNG file -> intermediate CI
|
||||
ci* png2ci(unsigned char* png_input, int size_input, int* width, int* height);
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// version
|
||||
|
||||
@@ -1211,6 +1211,122 @@ STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int s
|
||||
return out;
|
||||
}
|
||||
|
||||
typedef struct _pixel
|
||||
{
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
uint8_t alpha;
|
||||
} pixel;
|
||||
|
||||
STBIWDEF unsigned char *stbi_write_plte_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, pixel* plte, int plte_size, int *out_len) {
|
||||
int force_filter = stbi_write_force_png_filter;
|
||||
int ctype[5] = { -1, 3, 4, 2, 6 };
|
||||
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
|
||||
unsigned char *out,*o, *filt, *zlib;
|
||||
signed char *line_buffer;
|
||||
int j,zlen;
|
||||
|
||||
if (stride_bytes == 0)
|
||||
stride_bytes = x * n;
|
||||
|
||||
if (force_filter >= 5) {
|
||||
force_filter = -1;
|
||||
}
|
||||
|
||||
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
|
||||
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
|
||||
for (j=0; j < y; ++j) {
|
||||
int filter_type;
|
||||
if (force_filter > -1) {
|
||||
filter_type = force_filter;
|
||||
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);
|
||||
} else { // Estimate the best filter by running through all of them:
|
||||
int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
|
||||
for (filter_type = 0; filter_type < 5; filter_type++) {
|
||||
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);
|
||||
|
||||
// Estimate the entropy of the line using this filter; the less, the better.
|
||||
est = 0;
|
||||
for (i = 0; i < x*n; ++i) {
|
||||
est += abs((signed char) line_buffer[i]);
|
||||
}
|
||||
if (est < best_filter_val) {
|
||||
best_filter_val = est;
|
||||
best_filter = filter_type;
|
||||
}
|
||||
}
|
||||
if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
|
||||
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);
|
||||
filter_type = best_filter;
|
||||
}
|
||||
}
|
||||
// when we get here, filter_type contains the filter type, and line_buffer contains the data
|
||||
filt[j*(x*n+1)] = (unsigned char) filter_type;
|
||||
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
|
||||
}
|
||||
STBIW_FREE(line_buffer);
|
||||
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);
|
||||
STBIW_FREE(filt);
|
||||
if (!zlib) return 0;
|
||||
|
||||
// each tag requires 12 bytes of overhead
|
||||
// out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12 + (plte_size * 3 + 12)) + (plte_size + 12);
|
||||
// if (!out) return 0;
|
||||
// *out_len = 8 + 12+13 + 12+zlen + 12 + (plte_size * 3 + 12) + (plte_size + 12);
|
||||
|
||||
out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12 + (32 * 3 + 12));
|
||||
if (!out) return 0;
|
||||
*out_len = 8 + 12+13 + 12+zlen + 12 + (32 * 3 + 12);
|
||||
|
||||
o=out;
|
||||
STBIW_MEMMOVE(o,sig,8); o+= 8;
|
||||
stbiw__wp32(o, 13); // header length
|
||||
stbiw__wptag(o, "IHDR");
|
||||
stbiw__wp32(o, x);
|
||||
stbiw__wp32(o, y);
|
||||
*o++ = 8;
|
||||
*o++ = STBIW_UCHAR(3);
|
||||
*o++ = 0;
|
||||
*o++ = 0;
|
||||
*o++ = 0;
|
||||
stbiw__wpcrc(&o,13);
|
||||
|
||||
// WRITE PLTE Chunk
|
||||
stbiw__wp32(o, 32 * 3);
|
||||
stbiw__wptag(o, "PLTE");
|
||||
// STBIW_MEMMOVE(0, sig, 3*16); o+=3*16;
|
||||
for (j=0; j < 32; j++) {
|
||||
*o++ = STBIW_UCHAR(j);
|
||||
*o++ = STBIW_UCHAR(j);
|
||||
*o++ = STBIW_UCHAR(j);
|
||||
}
|
||||
stbiw__wpcrc(&o, 32 * 3);
|
||||
|
||||
// Write tRNS Chunk
|
||||
// stbiw__wp32(o, plte_size);
|
||||
// stbiw__wptag(o, "tRNS");
|
||||
// for (j=0; j < plte_size; j++) {
|
||||
// *o++ = STBIW_UCHAR(plte[j].alpha);
|
||||
// }
|
||||
// stbiw__wpcrc(&o, plte_size);
|
||||
|
||||
stbiw__wp32(o, zlen);
|
||||
stbiw__wptag(o, "IDAT");
|
||||
STBIW_MEMMOVE(o, zlib, zlen);
|
||||
o += zlen;
|
||||
STBIW_FREE(zlib);
|
||||
stbiw__wpcrc(&o, zlen);
|
||||
|
||||
stbiw__wp32(o,0);
|
||||
stbiw__wptag(o, "IEND");
|
||||
stbiw__wpcrc(&o,0);
|
||||
|
||||
STBIW_ASSERT(o == out + *out_len);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ extern "C" {
|
||||
#include "n64graphics/n64graphics.h"
|
||||
}
|
||||
|
||||
static const std::unordered_map <std::string, TextureFormat> gTextureTypes = {
|
||||
static const std::unordered_map <std::string, TextureFormat> gTextureFormats = {
|
||||
{ "RGBA16", { TextureType::RGBA16bpp, 16 } },
|
||||
{ "RGBA32", { TextureType::RGBA32bpp, 32 } },
|
||||
{ "CI4", { TextureType::Palette4bpp, 4 } },
|
||||
@@ -19,7 +19,7 @@ static const std::unordered_map <std::string, TextureFormat> gTextureTypes = {
|
||||
{ "IA4", { TextureType::GrayscaleAlpha4bpp, 4 } },
|
||||
{ "IA8", { TextureType::GrayscaleAlpha8bpp, 8 } },
|
||||
{ "IA16", { TextureType::GrayscaleAlpha16bpp, 16 } },
|
||||
{ "TLUT", { TextureType::TLUT, 0 } },
|
||||
{ "TLUT", { TextureType::TLUT, 16 } },
|
||||
};
|
||||
|
||||
size_t CalculateTextureSize(TextureType type, uint32_t width, uint32_t height) {
|
||||
@@ -138,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.type);
|
||||
writer.Write((uint32_t) texture->mFormat.type);
|
||||
writer.Write(texture->mWidth);
|
||||
writer.Write(texture->mHeight);
|
||||
|
||||
@@ -149,7 +149,7 @@ void TextureBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedD
|
||||
|
||||
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;
|
||||
auto format = texture->mFormat;
|
||||
uint8_t* raw = new uint8_t[CalculateTextureSize(format.type, texture->mWidth, texture->mHeight) * 2];
|
||||
int size = 0;
|
||||
|
||||
@@ -159,6 +159,7 @@ void TextureModdingExporter::Export(std::ostream&write, std::shared_ptr<IParsedD
|
||||
(*replacement) += "." + ext + ".png";
|
||||
|
||||
switch (format.type) {
|
||||
case TextureType::TLUT:
|
||||
case TextureType::RGBA16bpp:
|
||||
case TextureType::RGBA32bpp: {
|
||||
rgba* imgr = raw2rgba(texture->mBuffer.data(), texture->mWidth, texture->mHeight, format.depth);
|
||||
@@ -177,6 +178,14 @@ void TextureModdingExporter::Export(std::ostream&write, std::shared_ptr<IParsedD
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TextureType::Palette8bpp:
|
||||
case TextureType::Palette4bpp: {
|
||||
ci* imgi = raw2ci_torch(texture->mBuffer.data(), texture->mWidth, texture->mHeight, format.depth);
|
||||
if(ci2png(&raw, &size, imgi, 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);
|
||||
@@ -208,11 +217,11 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(!gTextureTypes.contains(format)) {
|
||||
if(!gTextureFormats.contains(format)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TextureFormat fmt = gTextureTypes.at(format);
|
||||
TextureFormat fmt = gTextureFormats.at(format);
|
||||
|
||||
if(fmt.type == TextureType::TLUT){
|
||||
width = GetSafeNode<uint32_t>(node, "colors");
|
||||
@@ -222,7 +231,7 @@ 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).type, width, height));
|
||||
size = GetSafeNode<uint32_t>(node, "size", CalculateTextureSize(gTextureFormats.at(format).type, width, height));
|
||||
auto [_, segment] = Decompressor::AutoDecode(node, buffer, size);
|
||||
std::vector<uint8_t> result;
|
||||
|
||||
@@ -264,11 +273,11 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse_modding(std::v
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(!gTextureTypes.contains(format)) {
|
||||
if(!gTextureFormats.contains(format)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TextureFormat fmt = gTextureTypes.at(format);
|
||||
TextureFormat fmt = gTextureFormats.at(format);
|
||||
if(fmt.type == TextureType::TLUT){
|
||||
width = GetSafeNode<uint32_t>(node, "colors");
|
||||
height = 1;
|
||||
@@ -279,6 +288,7 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse_modding(std::v
|
||||
|
||||
uint8_t* raw;
|
||||
switch (fmt.type) {
|
||||
case TextureType::TLUT:
|
||||
case TextureType::RGBA16bpp:
|
||||
case TextureType::RGBA32bpp: {
|
||||
const auto imgr = png2rgba(buffer.data(), buffer.size(), &width, &height);
|
||||
@@ -301,6 +311,17 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse_modding(std::v
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TextureType::Palette8bpp:
|
||||
case TextureType::Palette4bpp: {
|
||||
SPDLOG_WARN("Converting PNG to CI texture is kind of broken, use at your own risk!");
|
||||
const auto imgi = png2ci(buffer.data(), buffer.size(), &width, &height);
|
||||
size = width * height * fmt.depth / 8;
|
||||
raw = new uint8_t[size];
|
||||
if(ci2raw_torch(raw, imgi, 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);
|
||||
|
||||
@@ -24,12 +24,12 @@ struct TextureFormat {
|
||||
|
||||
class TextureData : public IParsedData {
|
||||
public:
|
||||
TextureFormat mType;
|
||||
TextureFormat mFormat;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
std::vector<uint8_t> mBuffer;
|
||||
|
||||
TextureData(TextureFormat type, uint32_t width, uint32_t height, std::vector<uint8_t>& buffer) : mType(type), mWidth(width), mHeight(height), mBuffer(std::move(buffer)) {}
|
||||
TextureData(TextureFormat format, uint32_t width, uint32_t height, std::vector<uint8_t>& buffer) : mFormat(format), mWidth(width), mHeight(height), mBuffer(std::move(buffer)) {}
|
||||
};
|
||||
|
||||
class TextureHeaderExporter : public BaseExporter {
|
||||
|
||||
Reference in New Issue
Block a user