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.
This commit is contained in:
committed by
Pasi Kallinen
parent
1870e5a41b
commit
b2c8d916f6
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user