From: Ray Chason Date: Sun, 26 Jan 2020 00:02:18 +0000 (-0500) Subject: Add set_tile_type, stretch_tile and free_tile X-Git-Tag: NetHack-3.7.0_WIP~15 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b2c8d916f68f3d2d3e6125950d30106313885602;p=nethack Add set_tile_type, stretch_tile and free_tile set_tile_type frees tileset memory not in use for the current tile type (paletted or full color). stretch_tile and free_tile support resizing tiles at run time. --- diff --git a/include/tileset.h b/include/tileset.h index 2ab145e66..9f6e86b5b 100644 --- a/include/tileset.h +++ b/include/tileset.h @@ -18,9 +18,15 @@ struct TileImage { boolean FDECL(read_tiles, (const char *filename, BOOLEAN_P true_color)); const struct Pixel *NDECL(get_palette); +boolean FDECL(set_tile_type, (BOOLEAN_P true_color)); void NDECL(free_tiles); const struct TileImage *FDECL(get_tile, (unsigned tile_index)); +/* For resizing tiles */ +struct TileImage *FDECL(stretch_tile, (const struct TileImage *, + unsigned, unsigned)); +void FDECL(free_tile, (struct TileImage *)); + /* Used internally by the tile set code */ struct TileSetImage { /* Image data */ diff --git a/win/share/tileset.c b/win/share/tileset.c index d37b91281..e9b448ab0 100644 --- a/win/share/tileset.c +++ b/win/share/tileset.c @@ -6,6 +6,7 @@ #include "tileset.h" static void FDECL(get_tile_map, (const char *)); +static unsigned FDECL(gcd, (unsigned, unsigned)); static void FDECL(split_tiles, (const struct TileSetImage *)); static void FDECL(free_image, (struct TileSetImage *)); @@ -100,6 +101,29 @@ error: return FALSE; } +/* Free tile memory not required by the chosen display mode */ +boolean +set_tile_type(true_color) +boolean true_color; +{ + unsigned i; + + if (tiles) { + if (true_color) { + for (i = 0; i < num_tiles; ++i) { + free((genericptr_t) tiles[i].indexes); + tiles[i].indexes = NULL; + } + have_palette = FALSE; + } else { + for (i = 0; i < num_tiles; ++i) { + free((genericptr_t) tiles[i].pixels); + tiles[i].pixels = NULL; + } + } + } +} + const struct Pixel * get_palette() { @@ -155,6 +179,112 @@ unsigned tile_index; return &tiles[tile_index]; } +/* Note that any tile returned by this function must be freed */ +struct TileImage * +stretch_tile(inp_tile, out_width, out_height) +const struct TileImage *inp_tile; +unsigned out_width, out_height; +{ + unsigned x_scale_inp, x_scale_out, y_scale_inp, y_scale_out; + unsigned divisor; + unsigned size; + struct TileImage *out_tile; + unsigned x_inp, y_inp, x2, y2, x_out, y_out; + unsigned pos; + + /* Derive the scale factors */ + divisor = gcd(out_width, inp_tile->width); + x_scale_inp = inp_tile->width / divisor; + x_scale_out = out_width / divisor; + divisor = gcd(out_height, inp_tile->height); + y_scale_inp = inp_tile->height / divisor; + y_scale_out = out_height / divisor; + + /* Derive the stretched tile */ + out_tile = (struct TileImage *) alloc(sizeof(struct TileImage)); + out_tile->width = out_width; + out_tile->height = out_height; + size = out_width * out_height; + if (inp_tile->pixels != NULL) { + out_tile->pixels = (struct Pixel *) alloc(size * sizeof(struct Pixel)); + divisor = x_scale_inp * y_scale_inp; + for (y_out = 0; y_out < out_height; ++y_out) { + for (x_out = 0; x_out < out_width; ++x_out) { + unsigned r, g, b, a; + + /* Derive output pixels by blending input pixels */ + r = 0; + g = 0; + b = 0; + a = 0; + for (y2 = 0; y2 < y_scale_inp; ++y2) { + y_inp = (y_out * y_scale_inp + y2) / y_scale_out; + for (x2 = 0; x2 < x_scale_inp; ++x2) { + x_inp = (x_out * x_scale_inp + x2) / x_scale_out; + pos = y_inp * inp_tile->width + x_inp; + r += inp_tile->pixels[pos].r; + g += inp_tile->pixels[pos].g; + b += inp_tile->pixels[pos].b; + a += inp_tile->pixels[pos].a; + } + } + + pos = y_out * out_width + x_out; + out_tile->pixels[pos].r = r / divisor; + out_tile->pixels[pos].g = g / divisor; + out_tile->pixels[pos].b = b / divisor; + out_tile->pixels[pos].a = a / divisor; + } + } + } else { + out_tile->pixels = NULL; + } + + /* If the output device uses a palette, we can't blend; just pick + a subset of the pixels */ + if (inp_tile->indexes != NULL) { + out_tile->indexes = (unsigned char *) alloc(size); + for (y_out = 0; y_out < out_height; ++y_out) { + for (x_out = 0; x_out < out_width; ++x_out) { + pos = y_out * out_width + x_out; + x_inp = x_out * x_scale_inp / x_scale_out; + y_inp = y_out * y_scale_inp / y_scale_out; + out_tile->indexes[pos] = + inp_tile->indexes[y_inp * inp_tile->width + x_inp]; + } + } + } else { + out_tile->indexes = NULL; + } + return out_tile; +} + +/* Free a tile returned by stretch_tile */ +/* Do NOT use this with tiles returned by get_tile */ +void +free_tile(tile) +struct TileImage *tile; +{ + if (tile != NULL) { + free(tile->indexes); + free(tile->pixels); + free(tile); + } +} + +/* Return the greatest common divisor */ +static unsigned +gcd(a, b) +unsigned a, b; +{ + while (TRUE) { + if (b == 0) return a; + a %= b; + if (a == 0) return b; + b %= a; + } +} + static void split_tiles(image) const struct TileSetImage *image;