Merge branch 'x11-bmp-gif' of https://github.com/chasonr/NetHack into NetHack-5.0
This commit is contained in:
+14
-5
@@ -9,6 +9,9 @@ struct Pixel {
|
|||||||
unsigned char r, g, b, a;
|
unsigned char r, g, b, a;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* To let the tileset interface split the tiles into separate images, use
|
||||||
|
* these functions */
|
||||||
|
|
||||||
struct TileImage {
|
struct TileImage {
|
||||||
/* Image data */
|
/* Image data */
|
||||||
unsigned width, height;
|
unsigned width, height;
|
||||||
@@ -22,12 +25,8 @@ void set_tile_type(boolean true_color);
|
|||||||
void free_tiles(void);
|
void free_tiles(void);
|
||||||
const struct TileImage *get_tile(unsigned tile_index);
|
const struct TileImage *get_tile(unsigned tile_index);
|
||||||
|
|
||||||
/* For resizing tiles */
|
/* To read the tileset as a single image, use these functions */
|
||||||
struct TileImage *stretch_tile(const struct TileImage *, unsigned,
|
|
||||||
unsigned);
|
|
||||||
void free_tile(struct TileImage *);
|
|
||||||
|
|
||||||
/* Used internally by the tile set code */
|
|
||||||
struct TileSetImage {
|
struct TileSetImage {
|
||||||
/* Image data */
|
/* Image data */
|
||||||
unsigned width, height;
|
unsigned width, height;
|
||||||
@@ -42,6 +41,16 @@ struct TileSetImage {
|
|||||||
unsigned tile_width, tile_height;
|
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_bmp_tiles(const char *filename, struct TileSetImage *image);
|
||||||
boolean read_gif_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);
|
boolean read_png_tiles(const char *filename, struct TileSetImage *image);
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ extern void nh_XtPopup(Widget, int, Widget);
|
|||||||
extern void nh_XtPopdown(Widget);
|
extern void nh_XtPopdown(Widget);
|
||||||
extern void win_X11_init(int);
|
extern void win_X11_init(int);
|
||||||
extern void find_scrollbars(Widget, Widget, Widget *, Widget *);
|
extern void find_scrollbars(Widget, Widget, Widget *, Widget *);
|
||||||
|
extern Boolean nhApproxColor(Screen *, Colormap, char *, XColor *);
|
||||||
|
|
||||||
/* ### winmesg.c ### */
|
/* ### winmesg.c ### */
|
||||||
extern void set_message_slider(struct xwindow *);
|
extern void set_message_slider(struct xwindow *);
|
||||||
|
|||||||
+18
-2
@@ -259,11 +259,15 @@ WINCURSESOBJ ?= $(TARGETPFX)cursmain.o $(TARGETPFX)curswins.o \
|
|||||||
WINX11SRC ?= ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \
|
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/winmap.c ../win/X11/winmenu.c ../win/X11/winmesg.c \
|
||||||
../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.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 \
|
||||||
|
../win/share/pngtiles.c $(GENTILECFILE)
|
||||||
WINX11OBJ ?= $(TARGETPFX)Window.o $(TARGETPFX)dialogs.o $(TARGETPFX)winX.o \
|
WINX11OBJ ?= $(TARGETPFX)Window.o $(TARGETPFX)dialogs.o $(TARGETPFX)winX.o \
|
||||||
$(TARGETPFX)winmap.o $(TARGETPFX)winmenu.o $(TARGETPFX)winmesg.o \
|
$(TARGETPFX)winmap.o $(TARGETPFX)winmenu.o $(TARGETPFX)winmesg.o \
|
||||||
$(TARGETPFX)winmisc.o $(TARGETPFX)winstat.o $(TARGETPFX)wintext.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 \
|
||||||
|
$(TARGETPFX)pngtiles.o
|
||||||
#
|
#
|
||||||
# Files for a Qt 3 interface (renamed since nethack 3.6.x)
|
# Files for a Qt 3 interface (renamed since nethack 3.6.x)
|
||||||
#
|
#
|
||||||
@@ -1103,6 +1107,18 @@ $(TARGETPFX)wintext.o: ../win/X11/wintext.c $(HACK_H) ../include/winX.h \
|
|||||||
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/wintext.c
|
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/wintext.c
|
||||||
$(TARGETPFX)winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h
|
$(TARGETPFX)winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h
|
||||||
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winval.c
|
$(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)pngtiles.o: ../win/share/pngtiles.c $(CONFIG_H) \
|
||||||
|
../include/objclass.h ../include/tileset.h
|
||||||
|
$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/share/pngtiles.c
|
||||||
$(TARGETPFX)wc_chainin.o: ../win/chain/wc_chainin.c $(HACK_H)
|
$(TARGETPFX)wc_chainin.o: ../win/chain/wc_chainin.c $(HACK_H)
|
||||||
$(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/chain/wc_chainin.c
|
$(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/chain/wc_chainin.c
|
||||||
$(TARGETPFX)wc_chainout.o: ../win/chain/wc_chainout.c $(HACK_H)
|
$(TARGETPFX)wc_chainout.o: ../win/chain/wc_chainout.c $(HACK_H)
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ endif # MAKEFILE_SRC
|
|||||||
ifdef WANT_WIN_X11
|
ifdef WANT_WIN_X11
|
||||||
USE_XPM=1
|
USE_XPM=1
|
||||||
USE_XFT=1
|
USE_XFT=1
|
||||||
|
USE_PNG=1
|
||||||
WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11
|
WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11
|
||||||
VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm
|
VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm
|
||||||
ifndef CROSSCOMPILE
|
ifndef CROSSCOMPILE
|
||||||
@@ -419,6 +420,10 @@ CFLAGS += -DUSE_XPM
|
|||||||
WINX11LIB += -lXpm
|
WINX11LIB += -lXpm
|
||||||
VARDATND0 += rip.xpm
|
VARDATND0 += rip.xpm
|
||||||
endif
|
endif
|
||||||
|
ifdef USE_PNG
|
||||||
|
CFLAGS += -DUSE_PNG
|
||||||
|
WINX11LIB += -lpng
|
||||||
|
endif
|
||||||
WINLIB += $(WINX11LIB)
|
WINLIB += $(WINX11LIB)
|
||||||
LFLAGS+=-L/opt/X11/lib
|
LFLAGS+=-L/opt/X11/lib
|
||||||
endif # WANT_WIN_X11
|
endif # WANT_WIN_X11
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ endif # WANT_WIN_CHAIN
|
|||||||
ifdef WANT_WIN_X11
|
ifdef WANT_WIN_X11
|
||||||
USE_XFT=1
|
USE_XFT=1
|
||||||
USE_XPM=1
|
USE_XPM=1
|
||||||
|
USE_PNG=1
|
||||||
WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11
|
WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11
|
||||||
VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm
|
VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm
|
||||||
GENTILEOFILE = $(SRCDIR)/tile.o
|
GENTILEOFILE = $(SRCDIR)/tile.o
|
||||||
@@ -298,6 +299,10 @@ CFLAGS += -DUSE_XPM
|
|||||||
WINX11LIB += -lXpm
|
WINX11LIB += -lXpm
|
||||||
VARDATND0 += rip.xpm
|
VARDATND0 += rip.xpm
|
||||||
endif
|
endif
|
||||||
|
ifdef USE_PNG
|
||||||
|
CFLAGS += -DUSE_PNG
|
||||||
|
WINX11LIB += -lpng
|
||||||
|
endif
|
||||||
WINLIB += $(WINX11LIB)
|
WINLIB += $(WINX11LIB)
|
||||||
LFLAGS += -L/opt/X11/lib
|
LFLAGS += -L/opt/X11/lib
|
||||||
endif # WANT_WIN_X11
|
endif # WANT_WIN_X11
|
||||||
|
|||||||
+2
-3
@@ -129,7 +129,6 @@ static XtSignalId X11_sig_id;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void init_menu_nhcolors(struct xwindow *);
|
static void init_menu_nhcolors(struct xwindow *);
|
||||||
static Boolean nhApproxColor(Screen *, Colormap, char *, XColor *);
|
|
||||||
static Boolean nhCvtStringToPixel(Display *, XrmValuePtr, Cardinal *,
|
static Boolean nhCvtStringToPixel(Display *, XrmValuePtr, Cardinal *,
|
||||||
XrmValuePtr, XrmValuePtr, XtPointer *);
|
XrmValuePtr, XrmValuePtr, XtPointer *);
|
||||||
static void get_window_frame_extents(Widget, long *, long *, long *, long *);
|
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.
|
* The approximate color found is returned in color as well.
|
||||||
* Return True if something close was found.
|
* Return True if something close was found.
|
||||||
*/
|
*/
|
||||||
static Boolean
|
Boolean
|
||||||
nhApproxColor(
|
nhApproxColor(
|
||||||
Screen *screen, /* screen to use */
|
Screen *screen, /* screen to use */
|
||||||
Colormap colormap, /* the colormap to use */
|
Colormap colormap, /* the colormap to use */
|
||||||
@@ -2793,7 +2792,7 @@ init_standard_windows(void)
|
|||||||
* Resize to at most full-screen.
|
* Resize to at most full-screen.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
#define TITLEBAR_SPACE 18 /* Leave SOME screen for window decorations */
|
#define TITLEBAR_SPACE 100 /* Leave SOME screen for window decorations and task bar */
|
||||||
|
|
||||||
int screen_width = WidthOfScreen(XtScreen(wp->w));
|
int screen_width = WidthOfScreen(XtScreen(wp->w));
|
||||||
int screen_height = HeightOfScreen(XtScreen(wp->w)) - TITLEBAR_SPACE;
|
int screen_height = HeightOfScreen(XtScreen(wp->w)) - TITLEBAR_SPACE;
|
||||||
|
|||||||
+299
-85
@@ -39,6 +39,7 @@
|
|||||||
#include "hack.h"
|
#include "hack.h"
|
||||||
#include "dlb.h"
|
#include "dlb.h"
|
||||||
#include "winX.h"
|
#include "winX.h"
|
||||||
|
#include "tileset.h"
|
||||||
|
|
||||||
#ifdef USE_XPM
|
#ifdef USE_XPM
|
||||||
#include <X11/xpm.h>
|
#include <X11/xpm.h>
|
||||||
@@ -82,16 +83,27 @@ static XFontStruct *X11_get_map_font_struct(struct xwindow *wp);
|
|||||||
#endif
|
#endif
|
||||||
static void get_text_gc(struct xwindow *, Font);
|
static void get_text_gc(struct xwindow *, Font);
|
||||||
static boolean init_tiles(struct xwindow *);
|
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 set_button_values(Widget, int, int, unsigned);
|
||||||
static void map_check_size_change(struct xwindow *);
|
static void map_check_size_change(struct xwindow *);
|
||||||
static void map_update(struct xwindow *, int, int, int, int, boolean);
|
static void map_update(struct xwindow *, int, int, int, int, boolean);
|
||||||
static void init_text(struct xwindow *);
|
static void init_text(struct xwindow *);
|
||||||
|
static void report_callback(Widget, XtPointer, XtPointer);
|
||||||
static void map_exposed(Widget, XtPointer, XtPointer);
|
static void map_exposed(Widget, XtPointer, XtPointer);
|
||||||
static void set_gc(Widget, Font, const char *, Pixel, GC *, GC *);
|
static void set_gc(Widget, Font, const char *, Pixel, GC *, GC *);
|
||||||
static void map_all_unexplored(struct map_info_t *);
|
static void map_all_unexplored(struct map_info_t *);
|
||||||
static void get_char_info(struct xwindow *);
|
static void get_char_info(struct xwindow *);
|
||||||
static void display_cursor(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 ======================================================= */
|
/* Global functions ======================================================= */
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -315,22 +327,6 @@ post_process_tiles(void)
|
|||||||
static boolean
|
static boolean
|
||||||
init_tiles(struct xwindow *wp)
|
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);
|
Display *dpy = XtDisplay(toplevel);
|
||||||
Screen *screen = DefaultScreenOfDisplay(dpy);
|
Screen *screen = DefaultScreenOfDisplay(dpy);
|
||||||
struct map_info_t *map_info = (struct map_info_t *) 0;
|
struct map_info_t *map_info = (struct map_info_t *) 0;
|
||||||
@@ -339,53 +335,285 @@ init_tiles(struct xwindow *wp)
|
|||||||
boolean result = TRUE;
|
boolean result = TRUE;
|
||||||
XGCValues values;
|
XGCValues values;
|
||||||
XtGCMask mask;
|
XtGCMask mask;
|
||||||
|
const char *tile_file;
|
||||||
|
|
||||||
/* already have tile information */
|
/* already have tile information */
|
||||||
if (tile_pixmap != None)
|
if (tile_pixmap != None)
|
||||||
goto tiledone;
|
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;
|
map_info = wp->map_information;
|
||||||
tile_info = &map_info->tile_map;
|
tile_info = &map_info->tile_map;
|
||||||
(void) memset((genericptr_t) tile_info, 0,
|
(void) memset((genericptr_t) tile_info, 0,
|
||||||
sizeof (struct tile_map_info_t));
|
sizeof (struct tile_map_info_t));
|
||||||
|
|
||||||
/* no tile file name, no tile information */
|
/* no tile file name, no tile information */
|
||||||
if (!appResources.tile_file[0]) {
|
if (!tile_file[0]) {
|
||||||
result = FALSE;
|
result = FALSE;
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = read_any_tiles(tile_file);
|
||||||
|
if (!result) {
|
||||||
#ifdef USE_XPM
|
#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.valuemask = XpmCloseness;
|
||||||
attributes.closeness = 25000;
|
attributes.closeness = 25000;
|
||||||
|
|
||||||
errorcode = XpmReadFileToImage(dpy, appResources.tile_file, &tile_image,
|
errorcode = XpmReadFileToImage(dpy, tile_file, &tile_image,
|
||||||
0, &attributes);
|
0, &attributes);
|
||||||
|
|
||||||
if (errorcode == XpmColorFailed) {
|
if (errorcode == XpmColorFailed) {
|
||||||
Sprintf(buf, "Insufficient colors available to load %s.",
|
Sprintf(buf, "Insufficient colors available to load %s.",
|
||||||
appResources.tile_file);
|
tile_file);
|
||||||
X11_raw_print(buf);
|
X11_raw_print(buf);
|
||||||
X11_raw_print("Try closing other colorful applications and restart.");
|
X11_raw_print("Try closing other colorful applications and restart.");
|
||||||
X11_raw_print("Attempting to load with inferior colors.");
|
X11_raw_print("Attempting to load with inferior colors.");
|
||||||
attributes.closeness = 50000;
|
attributes.closeness = 50000;
|
||||||
errorcode = XpmReadFileToImage(dpy, appResources.tile_file,
|
errorcode = XpmReadFileToImage(dpy, tile_file,
|
||||||
&tile_image, 0, &attributes);
|
&tile_image, 0, &attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorcode != XpmSuccess) {
|
if (errorcode != XpmSuccess) {
|
||||||
if (errorcode == XpmColorFailed) {
|
if (errorcode == XpmColorFailed) {
|
||||||
Sprintf(buf, "Insufficient colors available to load %s.",
|
Sprintf(buf, "Insufficient colors available to load %s.",
|
||||||
appResources.tile_file);
|
tile_file);
|
||||||
X11_raw_print(buf);
|
X11_raw_print(buf);
|
||||||
} else {
|
} else {
|
||||||
Sprintf(buf, "Failed to load %s: %s", appResources.tile_file,
|
Sprintf(buf, "Failed to load %s: %s", tile_file,
|
||||||
XpmGetErrorString(errorcode));
|
XpmGetErrorString(errorcode));
|
||||||
X11_raw_print(buf);
|
X11_raw_print(buf);
|
||||||
}
|
}
|
||||||
result = FALSE;
|
|
||||||
X11_raw_print("Switching to text-based mode.");
|
X11_raw_print("Switching to text-based mode.");
|
||||||
goto tiledone;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assume a fixed number of tiles per row */
|
/* assume a fixed number of tiles per row */
|
||||||
@@ -393,12 +621,11 @@ init_tiles(struct xwindow *wp)
|
|||||||
|| tile_image->width <= TILES_PER_ROW) {
|
|| tile_image->width <= TILES_PER_ROW) {
|
||||||
Sprintf(buf,
|
Sprintf(buf,
|
||||||
"%s is not a multiple of %d (number of tiles/row) pixels wide",
|
"%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);
|
X11_raw_print(buf);
|
||||||
XDestroyImage(tile_image);
|
XDestroyImage(tile_image);
|
||||||
tile_image = 0;
|
tile_image = 0;
|
||||||
result = FALSE;
|
return FALSE;
|
||||||
goto tiledone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* infer tile dimensions from image size and TILES_PER_ROW */
|
/* infer tile dimensions from image size and TILES_PER_ROW */
|
||||||
@@ -411,25 +638,47 @@ init_tiles(struct xwindow *wp)
|
|||||||
}
|
}
|
||||||
tile_width = image_width / TILES_PER_ROW;
|
tile_width = image_width / TILES_PER_ROW;
|
||||||
tile_height = image_height / (tile_count / TILES_PER_ROW);
|
tile_height = image_height / (tile_count / TILES_PER_ROW);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* !USE_XPM */
|
#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 */
|
/* any less than 16 colours makes tiles useless */
|
||||||
ddepth = DefaultDepthOfScreen(screen);
|
ddepth = DefaultDepthOfScreen(screen);
|
||||||
if (ddepth < 4) {
|
if (ddepth < 4) {
|
||||||
X11_raw_print("need a screen depth of at least 4");
|
X11_raw_print("need a screen depth of at least 4");
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen_datafile(appResources.tile_file, RDBMODE, FALSE);
|
fp = fopen_datafile(tile_file, RDBMODE, FALSE);
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
X11_raw_print("can't open tile file");
|
X11_raw_print("can't open tile file");
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int) fread((char *) &header, sizeof(header), 1, fp) != 1) {
|
if ((int) fread((char *) &header, sizeof(header), 1, fp) != 1) {
|
||||||
X11_raw_print("read of header failed");
|
X11_raw_print("read of header failed");
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +686,6 @@ init_tiles(struct xwindow *wp)
|
|||||||
Sprintf(buf, "Wrong tile file version, expected 2, got %lu",
|
Sprintf(buf, "Wrong tile file version, expected 2, got %lu",
|
||||||
header.version);
|
header.version);
|
||||||
X11_raw_print(buf);
|
X11_raw_print(buf);
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
@@ -453,7 +701,6 @@ ntiles %ld\n",
|
|||||||
colormap = (unsigned char *) alloc((unsigned) size);
|
colormap = (unsigned char *) alloc((unsigned) size);
|
||||||
if ((int) fread((char *) colormap, 1, size, fp) != size) {
|
if ((int) fread((char *) colormap, 1, size, fp) != size) {
|
||||||
X11_raw_print("read of colormap failed");
|
X11_raw_print("read of colormap failed");
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +719,6 @@ ntiles %ld\n",
|
|||||||
Sprintf(buf, "%dth out of %ld color allocation failed", i,
|
Sprintf(buf, "%dth out of %ld color allocation failed", i,
|
||||||
header.ncolors);
|
header.ncolors);
|
||||||
X11_raw_print(buf);
|
X11_raw_print(buf);
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -490,7 +736,6 @@ ntiles %ld\n",
|
|||||||
if ((int) fread((char *) tile_bytes, size, tile_count, fp)
|
if ((int) fread((char *) tile_bytes, size, tile_count, fp)
|
||||||
!= tile_count) {
|
!= tile_count) {
|
||||||
X11_raw_print("read of tile bytes failed");
|
X11_raw_print("read of tile bytes failed");
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,7 +743,6 @@ ntiles %ld\n",
|
|||||||
Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu",
|
Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu",
|
||||||
total_tiles_used, header.ntiles);
|
total_tiles_used, header.ntiles);
|
||||||
X11_raw_print(buf);
|
X11_raw_print(buf);
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,7 +778,6 @@ ntiles %ld\n",
|
|||||||
if (!tile_image) {
|
if (!tile_image) {
|
||||||
impossible("init_tiles: insufficient memory to create image");
|
impossible("init_tiles: insufficient memory to create image");
|
||||||
X11_raw_print("Resorting to text map.");
|
X11_raw_print("Resorting to text map.");
|
||||||
result = FALSE;
|
|
||||||
goto tiledone;
|
goto tiledone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,47 +809,10 @@ ntiles %ld\n",
|
|||||||
for (x = 0; x < (int) image_width; x++, tb++)
|
for (x = 0; x < (int) image_width; x++, tb++)
|
||||||
XPutPixel(tile_image, x, y, colors[*tb].pixel);
|
XPutPixel(tile_image, x, y, colors[*tb].pixel);
|
||||||
}
|
}
|
||||||
#endif /* ?USE_XPM */
|
|
||||||
|
|
||||||
/* fake an inverted tile by drawing a border around the edges */
|
result = TRUE;
|
||||||
#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 */
|
|
||||||
|
|
||||||
tiledone:
|
tiledone:
|
||||||
#ifndef USE_XPM
|
|
||||||
if (fp)
|
if (fp)
|
||||||
(void) fclose(fp);
|
(void) fclose(fp);
|
||||||
if (colormap)
|
if (colormap)
|
||||||
@@ -615,20 +821,12 @@ ntiles %ld\n",
|
|||||||
free((genericptr_t) tile_bytes);
|
free((genericptr_t) tile_bytes);
|
||||||
if (colors)
|
if (colors)
|
||||||
free((genericptr_t) 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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* ?USE_XPM */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure the map's cursor is always visible.
|
* Make sure the map's cursor is always visible.
|
||||||
*/
|
*/
|
||||||
@@ -1223,6 +1421,21 @@ set_button_values(Widget w, int x, int y, unsigned int button)
|
|||||||
click_button = (button == Button1) ? CLICK_1 : CLICK_2;
|
click_button = (button == Button1) ? CLICK_1 : CLICK_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This ensures that the cursor is visible when we first see the map */
|
||||||
|
static void
|
||||||
|
report_callback(Widget w, XtPointer client_data,
|
||||||
|
XtPointer widget_data)
|
||||||
|
{
|
||||||
|
nhUse(w);
|
||||||
|
XawPannerReport *report = (XawPannerReport *) widget_data;
|
||||||
|
if (report->changed & (XawPRSliderWidth | XawPRSliderHeight)) {
|
||||||
|
struct xwindow *wp = (struct xwindow *) client_data;
|
||||||
|
if (wp->map_information != NULL) {
|
||||||
|
check_cursor_visibility(wp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map window expose callback.
|
* Map window expose callback.
|
||||||
*/
|
*/
|
||||||
@@ -1793,6 +2006,7 @@ create_map_window(
|
|||||||
num_args); /* number of values to set */
|
num_args); /* number of values to set */
|
||||||
|
|
||||||
XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0);
|
XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0);
|
||||||
|
XtAddCallback(viewport, XtNreportCallback, report_callback, wp);
|
||||||
|
|
||||||
map_info = wp->map_information =
|
map_info = wp->map_information =
|
||||||
(struct map_info_t *) alloc(sizeof (struct map_info_t));
|
(struct map_info_t *) alloc(sizeof (struct map_info_t));
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#include "tileset.h"
|
||||||
|
|
||||||
|
#ifdef USE_PNG
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
|
boolean
|
||||||
|
read_png_tiles(const char *filename, struct TileSetImage *image)
|
||||||
|
{
|
||||||
|
png_structp read_png_ptr = NULL; /* custodial */
|
||||||
|
png_infop read_info_ptr = NULL; /* custodial */
|
||||||
|
png_infop read_end_info = NULL; /* custodial */
|
||||||
|
|
||||||
|
FILE *fp;
|
||||||
|
unsigned char header[8];
|
||||||
|
size_t size, num_pixels;
|
||||||
|
unsigned x, y;
|
||||||
|
png_bytepp pixels;
|
||||||
|
png_byte color_type;
|
||||||
|
int palette_size = 0;
|
||||||
|
png_textp text_chunks;
|
||||||
|
int num_text_chunks, i;
|
||||||
|
|
||||||
|
image->width = 0;
|
||||||
|
image->height = 0;
|
||||||
|
image->indexes = NULL; /* custodial, returned */
|
||||||
|
image->pixels = NULL; /* custodial, returned */
|
||||||
|
image->image_desc = NULL; /* custodial, returned */
|
||||||
|
image->tile_width = 0;
|
||||||
|
image->tile_height = 0;
|
||||||
|
|
||||||
|
/* Open the file */
|
||||||
|
fp = fopen(filename, "rb");
|
||||||
|
if (fp == NULL) goto error;
|
||||||
|
|
||||||
|
/* Check for PNG format */
|
||||||
|
memset(header, 0, sizeof(header));
|
||||||
|
size = fread(header, 1, sizeof(header), fp);
|
||||||
|
if (size < sizeof(header)) goto error;
|
||||||
|
if (png_sig_cmp(header, 0, sizeof(header)) != 0) goto error;
|
||||||
|
|
||||||
|
/* Create read info structures */
|
||||||
|
read_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
|
||||||
|
NULL, NULL);
|
||||||
|
if (read_png_ptr == NULL) goto error;
|
||||||
|
if (setjmp(png_jmpbuf(read_png_ptr)) != 0) goto error;
|
||||||
|
read_info_ptr = png_create_info_struct(read_png_ptr);
|
||||||
|
read_end_info = png_create_info_struct(read_png_ptr);
|
||||||
|
|
||||||
|
/* Link the file we opened to the read info */
|
||||||
|
png_init_io(read_png_ptr, fp);
|
||||||
|
png_set_sig_bytes(read_png_ptr, sizeof(header));
|
||||||
|
|
||||||
|
/* Read the image */
|
||||||
|
png_read_png(read_png_ptr, read_info_ptr,
|
||||||
|
PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_16, NULL);
|
||||||
|
|
||||||
|
pixels = png_get_rows(read_png_ptr, read_info_ptr);
|
||||||
|
image->width = png_get_image_width(read_png_ptr, read_info_ptr);
|
||||||
|
image->height = png_get_image_height(read_png_ptr, read_info_ptr);
|
||||||
|
color_type = png_get_color_type(read_png_ptr, read_info_ptr);
|
||||||
|
|
||||||
|
/* Read the palette, if there is one */
|
||||||
|
if (color_type & PNG_COLOR_MASK_PALETTE) {
|
||||||
|
png_colorp palette = NULL;
|
||||||
|
png_bytep trans_alpha;
|
||||||
|
int num_trans;
|
||||||
|
|
||||||
|
png_get_PLTE(read_png_ptr, read_info_ptr, &palette, &palette_size);
|
||||||
|
for (i = 0; i < 256; ++i) {
|
||||||
|
image->palette[i].r = palette[i].red;
|
||||||
|
image->palette[i].g = palette[i].green;
|
||||||
|
image->palette[i].b = palette[i].blue;
|
||||||
|
image->palette[i].a = 255;
|
||||||
|
}
|
||||||
|
if (png_get_tRNS(read_png_ptr, read_info_ptr, &trans_alpha, &num_trans,
|
||||||
|
NULL) != 0) {
|
||||||
|
for (i = 0; i < num_trans; ++i) {
|
||||||
|
image->palette[i].a = trans_alpha[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate pixel area; watch out for overflow */
|
||||||
|
num_pixels = (size_t) image->width * (size_t) image->height;
|
||||||
|
if (num_pixels / image->width != image->height) goto error; /* overflow */
|
||||||
|
size = num_pixels * sizeof(image->pixels[0]);
|
||||||
|
if (size / sizeof(image->pixels[0]) != num_pixels) goto error; /* overflow */
|
||||||
|
image->pixels = (struct Pixel *) alloc(size);
|
||||||
|
if (color_type & PNG_COLOR_MASK_PALETTE) {
|
||||||
|
image->indexes = (unsigned char *) alloc(num_pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the pixels */
|
||||||
|
for (y = 0; y < image->height; ++y) {
|
||||||
|
png_bytep png_row = pixels[y];
|
||||||
|
size_t index = y * image->width;
|
||||||
|
for (x = 0; x < image->width; ++x) {
|
||||||
|
if (color_type & PNG_COLOR_MASK_PALETTE) {
|
||||||
|
png_byte b = *png_row++;
|
||||||
|
image->indexes[index] = b;
|
||||||
|
image->pixels[index] = image->palette[b];
|
||||||
|
} else {
|
||||||
|
if (color_type & PNG_COLOR_MASK_COLOR) {
|
||||||
|
image->pixels[index].r = *png_row++;
|
||||||
|
image->pixels[index].g = *png_row++;
|
||||||
|
image->pixels[index].b = *png_row++;
|
||||||
|
} else {
|
||||||
|
image->pixels[index].r = *png_row++;
|
||||||
|
image->pixels[index].g = image->pixels[index].r;
|
||||||
|
image->pixels[index].b = image->pixels[index].r;
|
||||||
|
}
|
||||||
|
if (color_type & PNG_COLOR_MASK_ALPHA) {
|
||||||
|
image->pixels[index].a = *png_row++;
|
||||||
|
} else {
|
||||||
|
image->pixels[index].a = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for the tile information */
|
||||||
|
png_get_text(read_png_ptr, read_info_ptr, &text_chunks, &num_text_chunks);
|
||||||
|
for (i = 0; i < num_text_chunks; ++i) {
|
||||||
|
if (strcmp(text_chunks[i].key, "NH_image_desc") == 0) {
|
||||||
|
image->image_desc = (char *) alloc(text_chunks[i].text_length + 1);
|
||||||
|
memcpy(image->image_desc, text_chunks[i].text, text_chunks[i].text_length);
|
||||||
|
text_chunks[i].text[text_chunks[i].text_length] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
png_destroy_read_struct(&read_png_ptr, &read_info_ptr, &read_end_info);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (read_png_ptr) {
|
||||||
|
png_destroy_read_struct(&read_png_ptr, &read_info_ptr, &read_end_info);
|
||||||
|
}
|
||||||
|
free(image->indexes);
|
||||||
|
image->indexes = NULL;
|
||||||
|
free(image->pixels);
|
||||||
|
image->pixels = NULL;
|
||||||
|
free(image->image_desc);
|
||||||
|
image->image_desc = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+84
-54
@@ -10,10 +10,15 @@
|
|||||||
#include "flag.h"
|
#include "flag.h"
|
||||||
#include "tileset.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 *);
|
static void get_tile_map(const char *);
|
||||||
|
#ifdef USE_TILE_SPLITTING
|
||||||
static unsigned gcd(unsigned, unsigned);
|
static unsigned gcd(unsigned, unsigned);
|
||||||
static void split_tiles(const struct TileSetImage *);
|
static void split_tiles(const struct TileSetImage *);
|
||||||
static void free_image(struct TileSetImage *);
|
|
||||||
|
|
||||||
static struct TileImage *tiles;
|
static struct TileImage *tiles;
|
||||||
static unsigned num_tiles;
|
static unsigned num_tiles;
|
||||||
@@ -25,25 +30,57 @@ static struct Pixel palette[256];
|
|||||||
boolean
|
boolean
|
||||||
read_tiles(const char *filename, boolean true_color)
|
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;
|
struct TileSetImage image;
|
||||||
FILE *fp;
|
|
||||||
char header[16];
|
|
||||||
boolean ok;
|
|
||||||
|
|
||||||
if (tiles != NULL)
|
if (tiles != NULL)
|
||||||
return TRUE;
|
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 */
|
/* Fill the image structure with known values */
|
||||||
image.width = 0;
|
image->width = 0;
|
||||||
image.height = 0;
|
image->height = 0;
|
||||||
image.pixels = NULL; /* custodial */
|
image->pixels = NULL; /* custodial, returned */
|
||||||
image.indexes = NULL; /* custodial */
|
image->indexes = NULL; /* custodial, returned */
|
||||||
image.image_desc = NULL; /* custodial */
|
image->image_desc = NULL; /* custodial, returned */
|
||||||
image.tile_width = 0;
|
image->tile_width = 0;
|
||||||
image.tile_height = 0;
|
image->tile_height = 0;
|
||||||
|
|
||||||
|
if (filename == NULL || filename[0] == '\0') {
|
||||||
|
filename = "nhtiles.bmp";
|
||||||
|
}
|
||||||
|
|
||||||
/* Identify the image type */
|
/* Identify the image type */
|
||||||
fp = fopen(filename, "rb");
|
fp = fopen(filename, "rb");
|
||||||
@@ -55,12 +92,12 @@ read_tiles(const char *filename, boolean true_color)
|
|||||||
|
|
||||||
/* Call the loader appropriate for the image */
|
/* Call the loader appropriate for the image */
|
||||||
if (memcmp(header, "BM", 2) == 0) {
|
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
|
} else if (memcmp(header, "GIF87a", 6) == 0
|
||||||
|| memcmp(header, "GIF89a", 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) {
|
} else if (memcmp(header, png_sig, sizeof(png_sig)) == 0) {
|
||||||
ok = read_png_tiles(filename, &image);
|
ok = read_png_tiles(filename, image);
|
||||||
} else {
|
} else {
|
||||||
ok = FALSE;
|
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
|
/* Reject if the interface cannot handle direct color and the image does
|
||||||
not use a palette */
|
not use a palette */
|
||||||
if (!true_color && image.indexes == NULL)
|
if (!true_color && image->indexes == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Save the palette if present */
|
/* Parse the tile map */
|
||||||
have_palette = image.indexes != NULL;
|
get_tile_map(image->image_desc);
|
||||||
memcpy(palette, image.palette, sizeof(palette));
|
|
||||||
|
|
||||||
/* Set defaults for tile metadata */
|
/* Set defaults for tile metadata */
|
||||||
if (image.tile_width == 0) {
|
if (image->tile_width == 0) {
|
||||||
image.tile_width = image.width / 40;
|
image->tile_width = image->width / 40;
|
||||||
}
|
}
|
||||||
if (image.tile_height == 0) {
|
if (image->tile_height == 0) {
|
||||||
image.tile_height = image.tile_width;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the tile map */
|
|
||||||
get_tile_map(image.image_desc);
|
|
||||||
|
|
||||||
/* Split the image into tiles */
|
|
||||||
split_tiles(&image);
|
|
||||||
|
|
||||||
free_image(&image);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (fp)
|
if (fp)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free_image(&image);
|
free_tile_image(image);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_TILE_SPLITTING
|
||||||
/* Free tile memory not required by the chosen display mode */
|
/* Free tile memory not required by the chosen display mode */
|
||||||
void
|
void
|
||||||
set_tile_type(boolean true_color)
|
set_tile_type(boolean true_color)
|
||||||
@@ -134,6 +157,7 @@ get_palette(void)
|
|||||||
{
|
{
|
||||||
return have_palette ? palette : NULL;
|
return have_palette ? palette : NULL;
|
||||||
}
|
}
|
||||||
|
#endif /* USE_TILE_SPLITTING */
|
||||||
|
|
||||||
/* TODO: derive tile_map from image_desc */
|
/* TODO: derive tile_map from image_desc */
|
||||||
static void
|
static void
|
||||||
@@ -142,6 +166,7 @@ get_tile_map(const char *image_desc UNUSED)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_TILE_SPLITTING
|
||||||
void
|
void
|
||||||
free_tiles(void)
|
free_tiles(void)
|
||||||
{
|
{
|
||||||
@@ -161,9 +186,10 @@ free_tiles(void)
|
|||||||
if (blank_tile.indexes)
|
if (blank_tile.indexes)
|
||||||
free((genericptr_t) blank_tile.indexes), blank_tile.indexes = NULL;
|
free((genericptr_t) blank_tile.indexes), blank_tile.indexes = NULL;
|
||||||
}
|
}
|
||||||
|
#endif /* USE_TILE_SPLITTING */
|
||||||
|
|
||||||
static void
|
void
|
||||||
free_image(struct TileSetImage *image)
|
free_tile_image(struct TileSetImage *image)
|
||||||
{
|
{
|
||||||
if (image->pixels)
|
if (image->pixels)
|
||||||
free((genericptr_t) image->pixels), image->pixels = NULL;
|
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;
|
free((genericptr_t) image->image_desc), image->image_desc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_TILE_SPLITTING
|
||||||
const struct TileImage *
|
const struct TileImage *
|
||||||
get_tile(unsigned tile_index)
|
get_tile(unsigned tile_index)
|
||||||
{
|
{
|
||||||
@@ -292,10 +319,10 @@ split_tiles(const struct TileSetImage *image)
|
|||||||
unsigned x1, y1, y2;
|
unsigned x1, y1, y2;
|
||||||
|
|
||||||
/* Get the number of tiles */
|
/* Get the number of tiles */
|
||||||
tile_rows = image->height / iflags.wc_tile_height;
|
tile_rows = image->height / image->tile_height;
|
||||||
tile_cols = image->width / iflags.wc_tile_width;
|
tile_cols = image->width / image->tile_width;
|
||||||
num_tiles = tile_rows * tile_cols;
|
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 */
|
/* Allocate the tile array */
|
||||||
tiles = (struct TileImage *) alloc(num_tiles * sizeof(tiles[0]));
|
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) {
|
for (x1 = 0; x1 < tile_cols; ++x1) {
|
||||||
struct TileImage *tile = &tiles[y1 * tile_cols + x1];
|
struct TileImage *tile = &tiles[y1 * tile_cols + x1];
|
||||||
|
|
||||||
tile->width = iflags.wc_tile_width;
|
tile->width = image->tile_width;
|
||||||
tile->height = iflags.wc_tile_height;
|
tile->height = image->tile_height;
|
||||||
tile->pixels = (struct Pixel *)
|
tile->pixels = (struct Pixel *)
|
||||||
alloc(tile_size * sizeof (struct Pixel));
|
alloc(tile_size * sizeof (struct Pixel));
|
||||||
if (image->indexes != NULL) {
|
if (image->indexes != NULL) {
|
||||||
tile->indexes = (unsigned char *) alloc(tile_size);
|
tile->indexes = (unsigned char *) alloc(tile_size);
|
||||||
}
|
}
|
||||||
for (y2 = 0; y2 < (unsigned) iflags.wc_tile_height; ++y2) {
|
for (y2 = 0; y2 < (unsigned) image->tile_height; ++y2) {
|
||||||
unsigned y = y1 * iflags.wc_tile_height + y2;
|
unsigned y = y1 * image->tile_height + y2;
|
||||||
unsigned x = x1 * iflags.wc_tile_width;
|
unsigned x = x1 * image->tile_width;
|
||||||
i = y * image->width;
|
i = y * image->width;
|
||||||
j = y2 * tile->width;
|
j = y2 * tile->width;
|
||||||
memcpy(tile->pixels + j, image->pixels + i + x,
|
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) {
|
if (image->indexes != NULL) {
|
||||||
memcpy(tile->indexes + j, image->indexes + i + x,
|
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 */
|
/* Create a blank tile for use when the tile index is invalid */
|
||||||
blank_tile.width = iflags.wc_tile_width;
|
blank_tile.width = image->tile_width;
|
||||||
blank_tile.height = iflags.wc_tile_height;
|
blank_tile.height = image->tile_height;
|
||||||
blank_tile.pixels = (struct Pixel *)
|
blank_tile.pixels = (struct Pixel *)
|
||||||
alloc(tile_size * sizeof (struct Pixel));
|
alloc(tile_size * sizeof (struct Pixel));
|
||||||
for (i = 0; i < tile_size; ++i) {
|
for (i = 0; i < tile_size; ++i) {
|
||||||
@@ -344,12 +371,15 @@ split_tiles(const struct TileSetImage *image)
|
|||||||
memset(blank_tile.indexes, 0, tile_size);
|
memset(blank_tile.indexes, 0, tile_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* USE_TILE_SPLITTING */
|
||||||
|
|
||||||
|
#ifndef USE_PNG
|
||||||
boolean
|
boolean
|
||||||
read_png_tiles(const char *filename UNUSED, struct TileSetImage *image UNUSED)
|
read_png_tiles(const char *filename UNUSED, struct TileSetImage *image UNUSED)
|
||||||
{
|
{
|
||||||
/* stub */
|
/* stub */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
#endif /* !USE_PNG */
|
||||||
|
|
||||||
#endif /* TILES_IN_GLYPHMAP */
|
#endif /* TILES_IN_GLYPHMAP */
|
||||||
|
|||||||
Reference in New Issue
Block a user