X-Git-Url: https://git.draconx.ca/gitweb/liblbx.git/blobdiff_plain/4ec9360786d0bb19cffc76818c1a4c33043f68e1..HEAD:/src/png.c diff --git a/src/png.c b/src/png.c index 288cf77..cc885f7 100644 --- a/src/png.c +++ b/src/png.c @@ -1,7 +1,7 @@ /* * 2ooM: The Master of Orion II Reverse Engineering Project * PNG output routines for lbximg extration. - * Copyright © 2013 Nick Bowler + * Copyright © 2013-2014 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -36,18 +37,6 @@ struct file_info { FILE *f; }; -static int is_masked(unsigned char **mask, unsigned width, unsigned height) -{ - for (unsigned y = 0; y < height; y++) { - for (unsigned x = 0; x < width; x++) { - if (mask[y][x] == 0) - return 1; - } - } - - return 0; -} - static void fatal(png_structp png, int err, const char *fmt, ...) { va_list ap; @@ -93,13 +82,33 @@ static void flush_data(png_structp png) } } +static inline unsigned scale6to8(unsigned x) +{ + assert(x <= 0x3f); + + return x*0xff / 0x3f; +} + +/* Scale the 18-bit LBX palette into a 24-bit PNG palette. */ +static void fill_png_palette(png_color *out, const struct lbx_colour *in) +{ + for (unsigned i = 0; i < 256; i++) { + out[i] = (struct png_color_struct) { + .red = scale6to8(in[i].red), + .green = scale6to8(in[i].green), + .blue = scale6to8(in[i].blue), + }; + } +} + static void write_rgba_frame(png_structp png, png_infop info, - unsigned char **framedata, unsigned char **mask, - struct lbx_colour *palette) + unsigned char *pixels, unsigned char *mask, + struct lbx_colour *lbx_palette) { png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); + png_color png_palette[256]; unsigned char (*row)[4]; jmp_buf parent; @@ -121,12 +130,18 @@ write_rgba_frame(png_structp png, png_infop info, } png_write_info(png, info); + fill_png_palette(png_palette, lbx_palette); for (png_uint_32 y = 0; y < height; y++) { for (png_uint_32 x = 0; x < width; x++) { - row[x][0] = palette[framedata[y][x]].red; - row[x][1] = palette[framedata[y][x]].green; - row[x][2] = palette[framedata[y][x]].blue; - row[x][3] = mask[y][x] ? -1 : 0; + unsigned long offset = (unsigned long) y * width + x; + png_color *c = &png_palette[pixels[offset]]; + bool vis; + + vis = mask[offset/CHAR_BIT] & (1u << offset%CHAR_BIT); + row[x][0] = c->red; + row[x][1] = c->green; + row[x][2] = c->blue; + row[x][3] = -vis; } png_write_row(png, (void *)row); } @@ -137,7 +152,7 @@ write_rgba_frame(png_structp png, png_infop info, static void write_masked_index_frame(png_structp png, png_infop info, - unsigned char **framedata, unsigned char **mask) + unsigned char *pixels, unsigned char *mask) { png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); @@ -164,8 +179,12 @@ write_masked_index_frame(png_structp png, png_infop info, png_write_info(png, info); for (png_uint_32 y = 0; y < height; y++) { for (png_uint_32 x = 0; x < width; x++) { - row[x][0] = framedata[y][x]; - row[x][1] = mask[y][x] ? -1 : 0; + unsigned long offset = (unsigned long) y * width + x; + bool vis; + + vis = mask[offset/CHAR_BIT] & (1u << offset%CHAR_BIT); + row[x][0] = pixels[offset]; + row[x][1] = -vis; } png_write_row(png, (void *)row); } @@ -175,37 +194,37 @@ write_masked_index_frame(png_structp png, png_infop info, } static void -write_palette_frame(png_structp png, png_infop info, - unsigned char **framedata, struct lbx_colour *palette) +write_index_frame(png_structp png, png_infop info, unsigned char *pixels) { - png_color png_palette[256]; + png_uint_32 width = png_get_image_width(png, info); + png_uint_32 height = png_get_image_height(png, info); - for (unsigned i = 0; i < 256; i++) { - png_palette[i] = (png_color) { - .red = palette[i].red, - .green = palette[i].green, - .blue = palette[i].blue, - }; - } + png_write_info(png, info); + for (png_uint_32 y = 0; y < height; y++) { + unsigned long offset = (unsigned long) y * width; - png_set_PLTE(png, info, png_palette, 256); - png_set_rows(png, info, framedata); - png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); + png_write_row(png, (void *)(pixels+offset)); + } + png_write_end(png, NULL); } static void -write_index_frame(png_structp png, png_infop info, unsigned char **framedata) +write_palette_frame(png_structp png, png_infop info, + unsigned char *pixels, struct lbx_colour *lbx_palette) { - png_set_rows(png, info, framedata); - png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); + png_color png_palette[256]; + fill_png_palette(png_palette, lbx_palette); + png_set_PLTE(png, info, png_palette, 256); + + write_index_frame(png, info, pixels); } int img_output_png(FILE *f, const char *filename, unsigned width, unsigned height, - unsigned char **framedata, unsigned char **mask, - struct lbx_colour *palette) + unsigned char *pixels, unsigned char *mask, + struct lbx_colour *palette) { - bool masked = is_masked(mask, width, height); + bool masked = img_is_masked(mask, width, height); struct file_info file = { filename, f }; png_structp png; png_infop info; @@ -243,28 +262,28 @@ int img_output_png(FILE *f, const char *filename, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - write_rgba_frame(png, info, framedata, mask, palette); + write_rgba_frame(png, info, pixels, mask, palette); } else if (palette) { png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - write_palette_frame(png, info, framedata, palette); + write_palette_frame(png, info, pixels, palette); } else if (masked) { png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_GRAY_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - write_masked_index_frame(png, info, framedata, mask); + write_masked_index_frame(png, info, pixels, mask); } else { png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - write_index_frame(png, info, framedata); + write_index_frame(png, info, pixels); } png_destroy_write_struct(&png, &info);