#include <console.h>
#ifdef TCOD_CONSOLE_SUPPORT
#include <zlib.h>
#include <libtcod_int.h>
#include <console_types.h>
#include <color.h>
#if UINT_MAX != 0xffffffff
#error int type must be 32-bit!
#endif
#ifdef TCOD_SDL2
#include <SDL_endian.h>
#if SDL_BYTEORDER != SDL_LIL_ENDIAN
#error byte-order must be little endian!
#endif
#endif
struct RexPaintHeader {
int version;
int layer_count;
};
struct RexPaintLayerChunk {
int width;
int height;
};
struct RexPaintTile {
int ch;
TCOD_color_t fg;
TCOD_color_t bg;
};
static int load_gz_confirm(gzFile gz_file, void *data, size_t length) {
if (gzread(gz_file, data, (int)length) != length) { return -1; }
return 0;
}
static int load_header(gzFile gz_file, struct RexPaintHeader *xp_header) {
return load_gz_confirm(gz_file, xp_header, sizeof(xp_header[0]));
}
static int load_layer(gzFile gz_file, struct RexPaintLayerChunk *xp_layer) {
return load_gz_confirm(gz_file, xp_layer, sizeof(xp_layer[0]));
}
static int load_tile(gzFile gz_file, struct RexPaintTile *tile) {
return (
load_gz_confirm(gz_file, &tile->ch, sizeof(tile->ch)) ||
load_gz_confirm(gz_file, &tile->fg, sizeof(tile->fg)) ||
load_gz_confirm(gz_file, &tile->bg, sizeof(tile->bg))
);
}
static int load_tiles(
gzFile gz_file, TCOD_console_t console, int transparent) {
int x, y;
const int width = TCOD_console_get_width(console);
const int height = TCOD_console_get_height(console);
for (x = 0; x < width; ++x) {
for (y = 0; y < height; ++y) {
struct RexPaintTile tile;
if (load_tile(gz_file, &tile)) {
return -1;
}
if (transparent &&
tile.bg.r == 0xff &&
tile.bg.g == 0x00 &&
tile.bg.b == 0xff) { continue; }
TCOD_console_set_char(console, x, y, tile.ch);
TCOD_console_set_char_foreground(console, x, y, tile.fg);
TCOD_console_set_char_background(console, x, y, tile.bg, TCOD_BKGND_SET);
}
}
return 0;
}
static TCOD_console_t load_console(gzFile gz_file) {
struct RexPaintLayerChunk xp_layer;
TCOD_console_t console;
if (load_layer(gz_file, &xp_layer)) { return NULL; }
console = TCOD_console_new(xp_layer.width, xp_layer.height);
if (!console) { return NULL; }
if (load_tiles(gz_file, console, 0)) {
TCOD_console_delete(console);
return NULL;
}
return console;
}
static TCOD_list_t load_consoleList(gzFile gz_file) {
struct RexPaintHeader xp_header;
TCOD_list_t console_list;
int i;
if (load_header(gz_file, &xp_header)) { return NULL; }
console_list = TCOD_list_allocate(xp_header.layer_count);
if (!console_list) { return NULL; }
for (i = 0; i < xp_header.layer_count; ++i) {
TCOD_console_t console = load_console(gz_file);
if (!console) {
while (!TCOD_list_is_empty(console_list)) {
TCOD_console_delete(TCOD_list_pop(console_list));
}
TCOD_list_delete(console_list);
return NULL;
}
TCOD_list_push(console_list, console);
}
return console_list;
}
static TCOD_console_t combine_console_list(TCOD_list_t console_list) {
TCOD_console_t main_console;
if (!console_list) { return NULL; }
TCOD_list_reverse(console_list);
main_console = TCOD_list_pop(console_list);
while (!TCOD_list_is_empty(console_list)) {
TCOD_console_t console = TCOD_list_pop(console_list);
TCOD_console_set_key_color(console, TCOD_fuchsia);
TCOD_console_blit(console, 0, 0, 0, 0, main_console, 0, 0, 1.0f, 1.0f);
TCOD_console_delete(console);
}
TCOD_list_delete(console_list);
return main_console;
}
TCOD_list_t TCOD_console_list_from_xp(const char *filename) {
int z_errno = Z_ERRNO;
TCOD_list_t console_list;
gzFile gz_file = gzopen(filename, "rb");
if (!gz_file) {
TCOD_fatal("Could not open file: '%s'", filename);
return NULL;
}
console_list = load_consoleList(gz_file);
if (!console_list){
TCOD_fatal("Error parsing '%s'\n%s", filename, gzerror(gz_file, &z_errno));
}
gzclose(gz_file);
return console_list;
}
TCOD_console_t TCOD_console_from_xp(const char *filename) {
return combine_console_list(TCOD_console_list_from_xp(filename));
}
bool TCOD_console_load_xp(TCOD_console_t con, const char *filename) {
TCOD_console_t xp_console = TCOD_console_from_xp(filename);
if (!xp_console) { return false; }
if (TCOD_console_get_width(con) != TCOD_console_get_width(xp_console) ||
TCOD_console_get_height(con) != TCOD_console_get_height(xp_console)) {
TCOD_console_delete(xp_console);
return false;
}
TCOD_console_blit(xp_console, 0, 0, 0, 0, con, 0, 0, 1.0f, 1.0f);
TCOD_console_delete(xp_console);
return true;
}
static int write_header(gzFile gz_file, struct RexPaintHeader *xp_header) {
if (!gzwrite(gz_file, xp_header, sizeof(xp_header[0]))) {
return -1;
}
return 0;
}
static int write_layer(gzFile gz_file, struct RexPaintLayerChunk *xp_layer) {
if (!gzwrite(gz_file, xp_layer, sizeof(xp_layer[0]))) {
return -1;
}
return 0;
}
static int write_tile(gzFile gz_file, struct RexPaintTile *tile) {
if (!gzwrite(gz_file, &tile->ch, sizeof(tile->ch)) ||
!gzwrite(gz_file, &tile->fg, sizeof(tile->fg)) ||
!gzwrite(gz_file, &tile->bg, sizeof(tile->bg))) {
return -1;
}
return 0;
}
static int write_console(gzFile gz_file, TCOD_console_t console) {
int x, y;
struct RexPaintLayerChunk xp_layer;
xp_layer.width = TCOD_console_get_width(console);
xp_layer.height = TCOD_console_get_height(console);
if (write_layer(gz_file, &xp_layer)) {
return -1;
}
for (x = 0; x < xp_layer.width; ++x) {
for (y = 0; y < xp_layer.height; ++y) {
struct RexPaintTile tile;
tile.ch = TCOD_console_get_char(console, x, y);
tile.fg = TCOD_console_get_char_foreground(console, x, y);
tile.bg = TCOD_console_get_char_background(console, x, y);
if (write_tile(gz_file, &tile)) {
return -1;
}
}
}
return 0;
}
bool TCOD_console_save_xp(
TCOD_console_t con, const char *filename, int compress_level) {
struct RexPaintHeader xp_header;
gzFile gz_file = gzopen(filename, "wb");
if (!gz_file) { return false; }
gzsetparams(gz_file, compress_level, Z_DEFAULT_STRATEGY);
xp_header.version = -1;
xp_header.layer_count = 1;
if (write_header(gz_file, &xp_header) || write_console(gz_file, con)) {
gzclose(gz_file);
return false;
}
if (gzclose(gz_file)) { return false; }
return true;
}
bool TCOD_console_list_save_xp(
TCOD_list_t console_list, const char *filename, int compress_level) {
int i;
struct RexPaintHeader xp_header;
gzFile gz_file = gzopen(filename, "wb");
if (!gz_file) { return false; }
gzsetparams(gz_file, compress_level, Z_DEFAULT_STRATEGY);
xp_header.version = -1;
xp_header.layer_count = TCOD_list_size(console_list);
if (write_header(gz_file, &xp_header)) {
gzclose(gz_file);
return false;
}
for (i = 0; i < xp_header.layer_count; ++i){
if (write_console(gz_file, TCOD_list_get(console_list, i))) {
gzclose(gz_file);
return false;
}
}
if (gzclose(gz_file)) { return false; }
return true;
}
#endif