Add BMP and GIF support

This commit is contained in:
Ray Chason
2026-08-24 12:02:35 -04:00
committed by Ray Chason
parent 97a6c131a9
commit cc47605531
6 changed files with 396 additions and 148 deletions
+14 -5
View File
@@ -9,6 +9,9 @@ struct Pixel {
unsigned char r, g, b, a;
};
/* To let the tileset interface split the tiles into separate images, use
* these functions */
struct TileImage {
/* Image data */
unsigned width, height;
@@ -22,12 +25,8 @@ void set_tile_type(boolean true_color);
void free_tiles(void);
const struct TileImage *get_tile(unsigned tile_index);
/* For resizing tiles */
struct TileImage *stretch_tile(const struct TileImage *, unsigned,
unsigned);
void free_tile(struct TileImage *);
/* To read the tileset as a single image, use these functions */
/* Used internally by the tile set code */
struct TileSetImage {
/* Image data */
unsigned width, height;
@@ -42,6 +41,16 @@ struct TileSetImage {
unsigned tile_width, tile_height;
};
boolean read_tile_image(struct TileSetImage *image,
const char *filename, boolean true_color);
void free_tile_image(struct TileSetImage *image);
/* For resizing tiles */
struct TileImage *stretch_tile(const struct TileImage *, unsigned,
unsigned);
void free_tile(struct TileImage *);
/* Used internally by the tile set code */
boolean read_bmp_tiles(const char *filename, struct TileSetImage *image);
boolean read_gif_tiles(const char *filename, struct TileSetImage *image);
boolean read_png_tiles(const char *filename, struct TileSetImage *image);
+1
View File
@@ -390,6 +390,7 @@ extern void nh_XtPopup(Widget, int, Widget);
extern void nh_XtPopdown(Widget);
extern void win_X11_init(int);
extern void find_scrollbars(Widget, Widget, Widget *, Widget *);
extern Boolean nhApproxColor(Screen *, Colormap, char *, XColor *);
/* ### winmesg.c ### */
extern void set_message_slider(struct xwindow *);
+14 -2
View File
@@ -259,11 +259,14 @@ WINCURSESOBJ ?= $(TARGETPFX)cursmain.o $(TARGETPFX)curswins.o \
WINX11SRC ?= ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \
../win/X11/winmap.c ../win/X11/winmenu.c ../win/X11/winmesg.c \
../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \
../win/X11/winval.c ../win/X11/winlabel.c $(GENTILECFILE)
../win/X11/winval.c ../win/X11/winlabel.c \
../win/share/tileset.c ../win/share/bmptiles.c ../win/share/giftiles.c \
$(GENTILECFILE)
WINX11OBJ ?= $(TARGETPFX)Window.o $(TARGETPFX)dialogs.o $(TARGETPFX)winX.o \
$(TARGETPFX)winmap.o $(TARGETPFX)winmenu.o $(TARGETPFX)winmesg.o \
$(TARGETPFX)winmisc.o $(TARGETPFX)winstat.o $(TARGETPFX)wintext.o \
$(TARGETPFX)winval.o $(TARGETPFX)winlabel.o
$(TARGETPFX)winval.o $(TARGETPFX)winlabel.o \
$(TARGETPFX)tileset.o $(TARGETPFX)bmptiles.o $(TARGETPFX)giftiles.o
#
# Files for a Qt 3 interface (renamed since nethack 3.6.x)
#
@@ -1101,6 +1104,15 @@ $(TARGETPFX)wintext.o: ../win/X11/wintext.c $(HACK_H) ../include/winX.h \
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/wintext.c
$(TARGETPFX)winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winval.c
$(TARGETPFX)tileset.o: ../win/share/tileset.c $(CONFIG_H) \
../include/objclass.h ../include/flag.h ../include/tileset.h
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/share/tileset.c
$(TARGETPFX)bmptiles.o: ../win/share/bmptiles.c $(CONFIG_H) \
../include/objclass.h ../include/tileset.h
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/share/bmptiles.c
$(TARGETPFX)giftiles.o: ../win/share/giftiles.c $(CONFIG_H) \
../include/objclass.h ../include/tileset.h
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/share/giftiles.c
$(TARGETPFX)wc_chainin.o: ../win/chain/wc_chainin.c $(HACK_H)
$(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/chain/wc_chainin.c
$(TARGETPFX)wc_chainout.o: ../win/chain/wc_chainout.c $(HACK_H)
+1 -2
View File
@@ -129,7 +129,6 @@ static XtSignalId X11_sig_id;
#endif
static void init_menu_nhcolors(struct xwindow *);
static Boolean nhApproxColor(Screen *, Colormap, char *, XColor *);
static Boolean nhCvtStringToPixel(Display *, XrmValuePtr, Cardinal *,
XrmValuePtr, XrmValuePtr, XtPointer *);
static void get_window_frame_extents(Widget, long *, long *, long *, long *);
@@ -460,7 +459,7 @@ static XtConvertArgRec const nhcolorConvertArgs[] = {
* The approximate color found is returned in color as well.
* Return True if something close was found.
*/
static Boolean
Boolean
nhApproxColor(
Screen *screen, /* screen to use */
Colormap colormap, /* the colormap to use */
+282 -85
View File
@@ -39,6 +39,7 @@
#include "hack.h"
#include "dlb.h"
#include "winX.h"
#include "tileset.h"
#ifdef USE_XPM
#include <X11/xpm.h>
@@ -82,6 +83,9 @@ static XFontStruct *X11_get_map_font_struct(struct xwindow *wp);
#endif
static void get_text_gc(struct xwindow *, Font);
static boolean init_tiles(struct xwindow *);
static unsigned long color_to_rgb(unsigned, unsigned, unsigned,
const Visual *);
static unsigned long shift_color(unsigned color, unsigned long mask);
static void set_button_values(Widget, int, int, unsigned);
static void map_check_size_change(struct xwindow *);
static void map_update(struct xwindow *, int, int, int, int, boolean);
@@ -92,6 +96,13 @@ static void map_all_unexplored(struct map_info_t *);
static void get_char_info(struct xwindow *);
static void display_cursor(struct xwindow *);
static boolean read_any_tiles(const char *tile_file);
#ifdef USE_XPM
static boolean read_xpm_tiles(const char *tile_file);
#else
static boolean read_binary_tiles(const char *tile_file);
#endif
/* Global functions ======================================================= */
void
@@ -315,22 +326,6 @@ post_process_tiles(void)
static boolean
init_tiles(struct xwindow *wp)
{
#ifdef USE_XPM
XpmAttributes attributes;
int errorcode;
#else
FILE *fp = (FILE *) 0;
x11_header header;
unsigned char *cp, *colormap = (unsigned char *) 0;
unsigned char *tb, *tile_bytes = (unsigned char *) 0;
int size;
XColor *colors = (XColor *) 0;
unsigned i;
int x, y;
int bitmap_pad;
int ddepth;
#endif
char buf[BUFSZ];
Display *dpy = XtDisplay(toplevel);
Screen *screen = DefaultScreenOfDisplay(dpy);
struct map_info_t *map_info = (struct map_info_t *) 0;
@@ -339,53 +334,285 @@ init_tiles(struct xwindow *wp)
boolean result = TRUE;
XGCValues values;
XtGCMask mask;
const char *tile_file;
/* already have tile information */
if (tile_pixmap != None)
goto tiledone;
/* honor the user's tile file setting */
if (iflags.wc_tile_file != NULL && iflags.wc_tile_file[0] != '\0') {
tile_file = iflags.wc_tile_file;
} else {
tile_file = appResources.tile_file;
}
map_info = wp->map_information;
tile_info = &map_info->tile_map;
(void) memset((genericptr_t) tile_info, 0,
sizeof (struct tile_map_info_t));
/* no tile file name, no tile information */
if (!appResources.tile_file[0]) {
if (!tile_file[0]) {
result = FALSE;
goto tiledone;
}
result = read_any_tiles(tile_file);
if (!result) {
#ifdef USE_XPM
result = read_xpm_tiles(tile_file);
#else
result = read_binary_tiles(tile_file);
#endif
}
if (!result)
goto tiledone;
/* fake an inverted tile by drawing a border around the edges */
#ifdef USE_WHITE
/* use white or black as the border */
mask = GCFunction | GCForeground | GCGraphicsExposures;
values.graphics_exposures = False;
values.foreground = WhitePixelOfScreen(screen);
values.function = GXcopy;
tile_info->white_gc = XtGetGC(wp->w, mask, &values);
values.graphics_exposures = False;
values.foreground = BlackPixelOfScreen(screen);
values.function = GXcopy;
tile_info->black_gc = XtGetGC(wp->w, mask, &values);
#else
/*
* Use xor so we don't have to check for special colors. Xor white
* against the upper left pixel of the corridor so that we have a
* white rectangle when in a corridor.
*/
mask = GCFunction | GCForeground | GCGraphicsExposures;
values.graphics_exposures = False;
values.foreground =
WhitePixelOfScreen(screen)
^ XGetPixel(tile_image, 0,
tile_height * T_corr);
values.function = GXxor;
tile_info->white_gc = XtGetGC(wp->w, mask, &values);
mask = GCFunction | GCGraphicsExposures;
values.function = GXCopy;
values.graphics_exposures = False;
tile_info->black_gc = XtGetGC(wp->w, mask, &values);
#endif /* USE_WHITE */
tiledone:
if (result) { /* succeeded */
tile_info->square_height = tile_height;
tile_info->square_width = tile_width;
tile_info->square_ascent = 0;
tile_info->square_lbearing = 0;
tile_info->image_width = image_width;
tile_info->image_height = image_height;
}
return result;
}
static boolean
read_any_tiles(const char *tile_file)
{
Display *dpy = XtDisplay(toplevel);
int ddepth = DefaultDepth(dpy, DefaultScreen(dpy));
/* Read the image */
struct TileSetImage image;
boolean result = read_tile_image(&image, tile_file, ddepth >= 15);
if (!result) {
/* Format not recognized */
return FALSE;
}
/* Set the tile dimensions */
unsigned image_width = image.width;
unsigned image_height = image.height;
tile_width = (iflags.wc_tile_width != 0)
? iflags.wc_tile_width
: (int) image.tile_width;
tile_height = (iflags.wc_tile_height != 0)
? iflags.wc_tile_height
: (int) image.tile_height;
/* Set the tile count */
int tile_cols = image.width / tile_width;
int tile_rows = image.height / tile_height;
tile_count = tile_cols * tile_rows;
/* Double the size if requested */
if (appResources.double_tile_size) {
tile_width *= 2;
tile_height *= 2;
image_height *= 2;
image_width *= 2;
}
/* calculate bitmap_pad */
int bitmap_pad;
if (ddepth > 16)
bitmap_pad = 32;
else if (ddepth > 8)
bitmap_pad = 16;
else
bitmap_pad = 8;
/* Convert to XImage */
Screen *screen = DefaultScreenOfDisplay(dpy);
Visual *visual = DefaultVisualOfScreen(screen);
tile_image = XCreateImage(
dpy, visual,
ddepth, /* depth */
ZPixmap, /* format */
0, /* offset */
(char *) 0, /* data */
image_width, /* width */
image_height, /* height */
bitmap_pad, /* bit pad */
0); /* bytes_per_line */
if (tile_image == NULL) {
X11_raw_print("Failed to allocate XImage");
goto tile_error;
}
/* now we know the physical memory requirements, we can allocate space */
tile_image->data =
(char *) alloc((unsigned) tile_image->bytes_per_line * image_height);
unsigned char *tile_bytes = image.indexes;
XColor colors[256];
if (tile_bytes != NULL) { /* tileset uses a palette */
size_t size = (size_t) image.width * (size_t) image.height;
unsigned num_colors = 0;
for (unsigned j = 0; j < size; ++j) {
num_colors = max(num_colors, tile_bytes[j] + 1U);
}
for (unsigned i = 0; i < num_colors; i++) {
struct Pixel *cp = &image.palette[i];
colors[i].red = cp->r * 256;
colors[i].green = cp->g * 256;
colors[i].blue = cp->b * 256;
colors[i].flags = 0;
colors[i].pixel = 0;
if (!XAllocColor(dpy, DefaultColormapOfScreen(screen), &colors[i])
&& !nhApproxColor(screen, DefaultColormapOfScreen(screen),
(char *) 0, &colors[i])) {
char buf[BUFSZ];
Snprintf(buf, sizeof (buf), "%dth of %u color allocation failed", i,
num_colors);
X11_raw_print(buf);
goto tile_error;
}
}
}
/* Convert the pixels */
unsigned char *tb = image.indexes;
struct Pixel *cp = image.pixels;
for (unsigned y = 0; y < image.height; y++) {
for (unsigned x = 0; x < image.width; x++) {
unsigned long pixel;
if (tb == NULL) {
pixel = color_to_rgb(cp->r, cp->g, cp->b, visual);
++cp;
} else {
pixel = colors[*tb++].pixel;
}
if (appResources.double_tile_size) {
XPutPixel(tile_image, x * 2 + 0, y * 2 + 0, pixel);
XPutPixel(tile_image, x * 2 + 1, y * 2 + 0, pixel);
XPutPixel(tile_image, x * 2 + 0, y * 2 + 1, pixel);
XPutPixel(tile_image, x * 2 + 1, y * 2 + 1, pixel);
} else {
XPutPixel(tile_image, x, y, pixel);
}
}
}
free_tile_image(&image);
return TRUE;
tile_error:
free_tile_image(&image);
return FALSE;
}
static unsigned long
color_to_rgb(unsigned red, unsigned green, unsigned blue, const Visual *visual)
{
return shift_color(red, visual->red_mask )
| shift_color(green, visual->green_mask)
| shift_color(blue, visual->blue_mask );
}
static unsigned long
shift_color(unsigned color, unsigned long mask)
{
unsigned long mask1;
unsigned long color1;
/* Shift color to match mask */
mask1 = mask;
color1 = color;
while (mask1 > 0xFF) {
mask1 >>= 1;
color1 <<= 1;
}
while (mask1 < 0x80) {
mask1 <<= 1;
color1 >>= 1;
}
return mask & color1;
}
#ifdef USE_XPM
static boolean
read_xpm_tiles(const char *tile_file)
{
XpmAttributes attributes;
int errorcode;
char buf[BUFSZ];
Display *dpy = XtDisplay(toplevel);
unsigned int image_height = 0, image_width = 0;
attributes.valuemask = XpmCloseness;
attributes.closeness = 25000;
errorcode = XpmReadFileToImage(dpy, appResources.tile_file, &tile_image,
errorcode = XpmReadFileToImage(dpy, tile_file, &tile_image,
0, &attributes);
if (errorcode == XpmColorFailed) {
Sprintf(buf, "Insufficient colors available to load %s.",
appResources.tile_file);
tile_file);
X11_raw_print(buf);
X11_raw_print("Try closing other colorful applications and restart.");
X11_raw_print("Attempting to load with inferior colors.");
attributes.closeness = 50000;
errorcode = XpmReadFileToImage(dpy, appResources.tile_file,
errorcode = XpmReadFileToImage(dpy, tile_file,
&tile_image, 0, &attributes);
}
if (errorcode != XpmSuccess) {
if (errorcode == XpmColorFailed) {
Sprintf(buf, "Insufficient colors available to load %s.",
appResources.tile_file);
tile_file);
X11_raw_print(buf);
} else {
Sprintf(buf, "Failed to load %s: %s", appResources.tile_file,
Sprintf(buf, "Failed to load %s: %s", tile_file,
XpmGetErrorString(errorcode));
X11_raw_print(buf);
}
result = FALSE;
X11_raw_print("Switching to text-based mode.");
goto tiledone;
return FALSE;
}
/* assume a fixed number of tiles per row */
@@ -393,12 +620,11 @@ init_tiles(struct xwindow *wp)
|| tile_image->width <= TILES_PER_ROW) {
Sprintf(buf,
"%s is not a multiple of %d (number of tiles/row) pixels wide",
appResources.tile_file, TILES_PER_ROW);
tile_file, TILES_PER_ROW);
X11_raw_print(buf);
XDestroyImage(tile_image);
tile_image = 0;
result = FALSE;
goto tiledone;
return FALSE;
}
/* infer tile dimensions from image size and TILES_PER_ROW */
@@ -411,25 +637,47 @@ init_tiles(struct xwindow *wp)
}
tile_width = image_width / TILES_PER_ROW;
tile_height = image_height / (tile_count / TILES_PER_ROW);
return TRUE;
}
#else /* !USE_XPM */
static boolean
read_binary_tiles(const char *tile_file)
{
FILE *fp = (FILE *) 0;
x11_header header;
unsigned char *cp, *colormap = (unsigned char *) 0;
unsigned char *tb, *tile_bytes = (unsigned char *) 0;
int size;
XColor *colors = (XColor *) 0;
unsigned i;
int x, y;
int bitmap_pad;
int ddepth;
char buf[BUFSZ];
Display *dpy = XtDisplay(toplevel);
Screen *screen = DefaultScreenOfDisplay(dpy);
unsigned int image_height = 0, image_width = 0;
boolean result = FALSE;
/* any less than 16 colours makes tiles useless */
ddepth = DefaultDepthOfScreen(screen);
if (ddepth < 4) {
X11_raw_print("need a screen depth of at least 4");
result = FALSE;
goto tiledone;
}
fp = fopen_datafile(appResources.tile_file, RDBMODE, FALSE);
fp = fopen_datafile(tile_file, RDBMODE, FALSE);
if (!fp) {
X11_raw_print("can't open tile file");
result = FALSE;
goto tiledone;
}
if ((int) fread((char *) &header, sizeof(header), 1, fp) != 1) {
X11_raw_print("read of header failed");
result = FALSE;
goto tiledone;
}
@@ -437,7 +685,6 @@ init_tiles(struct xwindow *wp)
Sprintf(buf, "Wrong tile file version, expected 2, got %lu",
header.version);
X11_raw_print(buf);
result = FALSE;
goto tiledone;
}
#ifdef VERBOSE
@@ -453,7 +700,6 @@ ntiles %ld\n",
colormap = (unsigned char *) alloc((unsigned) size);
if ((int) fread((char *) colormap, 1, size, fp) != size) {
X11_raw_print("read of colormap failed");
result = FALSE;
goto tiledone;
}
@@ -472,7 +718,6 @@ ntiles %ld\n",
Sprintf(buf, "%dth out of %ld color allocation failed", i,
header.ncolors);
X11_raw_print(buf);
result = FALSE;
goto tiledone;
}
}
@@ -490,7 +735,6 @@ ntiles %ld\n",
if ((int) fread((char *) tile_bytes, size, tile_count, fp)
!= tile_count) {
X11_raw_print("read of tile bytes failed");
result = FALSE;
goto tiledone;
}
@@ -498,7 +742,6 @@ ntiles %ld\n",
Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu",
total_tiles_used, header.ntiles);
X11_raw_print(buf);
result = FALSE;
goto tiledone;
}
@@ -534,7 +777,6 @@ ntiles %ld\n",
if (!tile_image) {
impossible("init_tiles: insufficient memory to create image");
X11_raw_print("Resorting to text map.");
result = FALSE;
goto tiledone;
}
@@ -566,47 +808,10 @@ ntiles %ld\n",
for (x = 0; x < (int) image_width; x++, tb++)
XPutPixel(tile_image, x, y, colors[*tb].pixel);
}
#endif /* ?USE_XPM */
/* fake an inverted tile by drawing a border around the edges */
#ifdef USE_WHITE
/* use white or black as the border */
mask = GCFunction | GCForeground | GCGraphicsExposures;
values.graphics_exposures = False;
values.foreground = WhitePixelOfScreen(screen);
values.function = GXcopy;
tile_info->white_gc = XtGetGC(wp->w, mask, &values);
values.graphics_exposures = False;
values.foreground = BlackPixelOfScreen(screen);
values.function = GXcopy;
tile_info->black_gc = XtGetGC(wp->w, mask, &values);
#else
/*
* Use xor so we don't have to check for special colors. Xor white
* against the upper left pixel of the corridor so that we have a
* white rectangle when in a corridor.
*/
mask = GCFunction | GCForeground | GCGraphicsExposures;
values.graphics_exposures = False;
values.foreground =
WhitePixelOfScreen(screen)
^ XGetPixel(tile_image, 0,
#if 0
tile_height * glyph2tile[cmap_to_glyph(S_corr)]);
#else
tile_height * T_corr);
#endif
values.function = GXxor;
tile_info->white_gc = XtGetGC(wp->w, mask, &values);
mask = GCFunction | GCGraphicsExposures;
values.function = GXCopy;
values.graphics_exposures = False;
tile_info->black_gc = XtGetGC(wp->w, mask, &values);
#endif /* USE_WHITE */
result = TRUE;
tiledone:
#ifndef USE_XPM
if (fp)
(void) fclose(fp);
if (colormap)
@@ -615,20 +820,12 @@ ntiles %ld\n",
free((genericptr_t) tile_bytes);
if (colors)
free((genericptr_t) colors);
#endif
if (result) { /* succeeded */
tile_info->square_height = tile_height;
tile_info->square_width = tile_width;
tile_info->square_ascent = 0;
tile_info->square_lbearing = 0;
tile_info->image_width = image_width;
tile_info->image_height = image_height;
}
return result;
}
#endif /* ?USE_XPM */
/*
* Make sure the map's cursor is always visible.
*/
+84 -54
View File
@@ -10,10 +10,15 @@
#include "flag.h"
#include "tileset.h"
/* Define this for systems that use the tile-splitting functions */
#if defined(MSDOS)
#define USE_TILE_SPLITTING
#endif
static void get_tile_map(const char *);
#ifdef USE_TILE_SPLITTING
static unsigned gcd(unsigned, unsigned);
static void split_tiles(const struct TileSetImage *);
static void free_image(struct TileSetImage *);
static struct TileImage *tiles;
static unsigned num_tiles;
@@ -25,25 +30,57 @@ static struct Pixel palette[256];
boolean
read_tiles(const char *filename, boolean true_color)
{
static const unsigned char png_sig[] = {
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
};
struct TileSetImage image;
FILE *fp;
char header[16];
boolean ok;
if (tiles != NULL)
return TRUE;
if (!read_tile_image(&image, filename, true_color)) {
return FALSE;
}
/* Save the palette if present */
have_palette = image.indexes != NULL;
memcpy(palette, image.palette, sizeof(palette));
/* Set the tile dimensions if the user has not done so */
if (iflags.wc_tile_width == 0) {
iflags.wc_tile_width = image.tile_width;
}
if (iflags.wc_tile_height == 0) {
iflags.wc_tile_height = image.tile_height;
}
/* Split the image into tiles */
split_tiles(&image);
free_tile_image(&image);
return TRUE;
}
#endif /* USE_TILE_SPLITTING */
boolean
read_tile_image(struct TileSetImage *image, const char *filename, boolean true_color)
{
static const unsigned char png_sig[] = {
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
};
FILE *fp;
char header[16];
boolean ok;
/* Fill the image structure with known values */
image.width = 0;
image.height = 0;
image.pixels = NULL; /* custodial */
image.indexes = NULL; /* custodial */
image.image_desc = NULL; /* custodial */
image.tile_width = 0;
image.tile_height = 0;
image->width = 0;
image->height = 0;
image->pixels = NULL; /* custodial, returned */
image->indexes = NULL; /* custodial, returned */
image->image_desc = NULL; /* custodial, returned */
image->tile_width = 0;
image->tile_height = 0;
if (filename == NULL || filename[0] == '\0') {
filename = "nhtiles.bmp";
}
/* Identify the image type */
fp = fopen(filename, "rb");
@@ -55,12 +92,12 @@ read_tiles(const char *filename, boolean true_color)
/* Call the loader appropriate for the image */
if (memcmp(header, "BM", 2) == 0) {
ok = read_bmp_tiles(filename, &image);
ok = read_bmp_tiles(filename, image);
} else if (memcmp(header, "GIF87a", 6) == 0
|| memcmp(header, "GIF89a", 6) == 0) {
ok = read_gif_tiles(filename, &image);
ok = read_gif_tiles(filename, image);
} else if (memcmp(header, png_sig, sizeof(png_sig)) == 0) {
ok = read_png_tiles(filename, &image);
ok = read_png_tiles(filename, image);
} else {
ok = FALSE;
}
@@ -69,44 +106,30 @@ read_tiles(const char *filename, boolean true_color)
/* Reject if the interface cannot handle direct color and the image does
not use a palette */
if (!true_color && image.indexes == NULL)
if (!true_color && image->indexes == NULL)
goto error;
/* Save the palette if present */
have_palette = image.indexes != NULL;
memcpy(palette, image.palette, sizeof(palette));
/* Parse the tile map */
get_tile_map(image->image_desc);
/* Set defaults for tile metadata */
if (image.tile_width == 0) {
image.tile_width = image.width / 40;
if (image->tile_width == 0) {
image->tile_width = image->width / 40;
}
if (image.tile_height == 0) {
image.tile_height = image.tile_width;
}
/* Set the tile dimensions if the user has not done so */
if (iflags.wc_tile_width == 0) {
iflags.wc_tile_width = image.tile_width;
}
if (iflags.wc_tile_height == 0) {
iflags.wc_tile_height = image.tile_height;
if (image->tile_height == 0) {
image->tile_height = image->tile_width;
}
/* Parse the tile map */
get_tile_map(image.image_desc);
/* Split the image into tiles */
split_tiles(&image);
free_image(&image);
return TRUE;
error:
if (fp)
fclose(fp);
free_image(&image);
free_tile_image(image);
return FALSE;
}
#ifdef USE_TILE_SPLITTING
/* Free tile memory not required by the chosen display mode */
void
set_tile_type(boolean true_color)
@@ -134,6 +157,7 @@ get_palette(void)
{
return have_palette ? palette : NULL;
}
#endif /* USE_TILE_SPLITTING */
/* TODO: derive tile_map from image_desc */
static void
@@ -142,6 +166,7 @@ get_tile_map(const char *image_desc UNUSED)
return;
}
#ifdef USE_TILE_SPLITTING
void
free_tiles(void)
{
@@ -161,9 +186,10 @@ free_tiles(void)
if (blank_tile.indexes)
free((genericptr_t) blank_tile.indexes), blank_tile.indexes = NULL;
}
#endif /* USE_TILE_SPLITTING */
static void
free_image(struct TileSetImage *image)
void
free_tile_image(struct TileSetImage *image)
{
if (image->pixels)
free((genericptr_t) image->pixels), image->pixels = NULL;
@@ -173,6 +199,7 @@ free_image(struct TileSetImage *image)
free((genericptr_t) image->image_desc), image->image_desc = NULL;
}
#ifdef USE_TILE_SPLITTING
const struct TileImage *
get_tile(unsigned tile_index)
{
@@ -292,10 +319,10 @@ split_tiles(const struct TileSetImage *image)
unsigned x1, y1, y2;
/* Get the number of tiles */
tile_rows = image->height / iflags.wc_tile_height;
tile_cols = image->width / iflags.wc_tile_width;
tile_rows = image->height / image->tile_height;
tile_cols = image->width / image->tile_width;
num_tiles = tile_rows * tile_cols;
tile_size = (size_t) iflags.wc_tile_height * (size_t) iflags.wc_tile_width;
tile_size = (size_t) image->tile_height * (size_t) image->tile_width;
/* Allocate the tile array */
tiles = (struct TileImage *) alloc(num_tiles * sizeof(tiles[0]));
@@ -306,31 +333,31 @@ split_tiles(const struct TileSetImage *image)
for (x1 = 0; x1 < tile_cols; ++x1) {
struct TileImage *tile = &tiles[y1 * tile_cols + x1];
tile->width = iflags.wc_tile_width;
tile->height = iflags.wc_tile_height;
tile->width = image->tile_width;
tile->height = image->tile_height;
tile->pixels = (struct Pixel *)
alloc(tile_size * sizeof (struct Pixel));
if (image->indexes != NULL) {
tile->indexes = (unsigned char *) alloc(tile_size);
}
for (y2 = 0; y2 < (unsigned) iflags.wc_tile_height; ++y2) {
unsigned y = y1 * iflags.wc_tile_height + y2;
unsigned x = x1 * iflags.wc_tile_width;
for (y2 = 0; y2 < (unsigned) image->tile_height; ++y2) {
unsigned y = y1 * image->tile_height + y2;
unsigned x = x1 * image->tile_width;
i = y * image->width;
j = y2 * tile->width;
memcpy(tile->pixels + j, image->pixels + i + x,
sizeof(tile->pixels[0]) * iflags.wc_tile_width);
sizeof(tile->pixels[0]) * image->tile_width);
if (image->indexes != NULL) {
memcpy(tile->indexes + j, image->indexes + i + x,
iflags.wc_tile_width);
image->tile_width);
}
}
}
}
/* Create a blank tile for use when the tile index is invalid */
blank_tile.width = iflags.wc_tile_width;
blank_tile.height = iflags.wc_tile_height;
blank_tile.width = image->tile_width;
blank_tile.height = image->tile_height;
blank_tile.pixels = (struct Pixel *)
alloc(tile_size * sizeof (struct Pixel));
for (i = 0; i < tile_size; ++i) {
@@ -344,12 +371,15 @@ split_tiles(const struct TileSetImage *image)
memset(blank_tile.indexes, 0, tile_size);
}
}
#endif /* USE_TILE_SPLITTING */
#ifndef USE_PNG
boolean
read_png_tiles(const char *filename UNUSED, struct TileSetImage *image UNUSED)
{
/* stub */
return FALSE;
}
#endif /* !USE_PNG */
#endif /* TILES_IN_GLYPHMAP */