1 /* aNetHack 0.0.1 tileset.c $ANH-Date: 1457207053 2016/03/05 19:44:13 $ $ANH-Branch: chasonr $:$ANH-Revision: 1.0 $ */
2 /* Copyright (c) Ray Chason, 2016. */
3 /* aNetHack may be freely redistributed. See license for details. */
8 static void FDECL(get_tile_map
, (const char *));
9 static void FDECL(split_tiles
, (const struct TileSetImage
*));
10 static void FDECL(free_image
, (struct TileSetImage
*));
12 static struct TileImage
*tiles
;
13 static unsigned num_tiles
;
14 static struct TileImage blank_tile
; /* for graceful undefined tile handling */
16 static boolean have_palette
;
17 static struct Pixel palette
[256];
20 read_tiles(filename
, true_color
)
24 static const unsigned char png_sig
[] = {
25 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
27 struct TileSetImage image
;
28 FILE *fp
= NULL
; /* custodial */
32 /* Fill the image structure with known values */
35 image
.pixels
= NULL
; /* custodial */
36 image
.indexes
= NULL
; /* custodial */
37 image
.image_desc
= NULL
; /* custodial */
39 image
.tile_height
= 0;
41 /* Identify the image type */
42 fp
= fopen(filename
, "rb");
43 if (fp
== NULL
) goto error
;
44 memset(header
, 0, sizeof(header
));
45 fread(header
, 1, sizeof(header
), fp
);
48 /* Call the loader appropriate for the image */
49 if (memcmp(header
, "BM", 2) == 0) {
50 ok
= read_bmp_tiles(filename
, &image
);
51 } else if (memcmp(header
, "GIF87a", 6) == 0
52 || memcmp(header
, "GIF89a", 6) == 0) {
53 ok
= read_gif_tiles(filename
, &image
);
54 } else if (memcmp(header
, png_sig
, sizeof(png_sig
)) == 0) {
55 ok
= read_png_tiles(filename
, &image
);
61 /* Reject if the interface cannot handle direct color and the image does
63 if (!true_color
&& image
.indexes
== NULL
) goto error
;
65 /* Save the palette if present */
66 have_palette
= image
.indexes
!= NULL
;
67 memcpy(palette
, image
.palette
, sizeof(palette
));
69 /* Set defaults for tile metadata */
70 if (image
.tile_width
== 0) {
71 image
.tile_width
= image
.width
/ 40;
73 if (image
.tile_height
== 0) {
74 image
.tile_height
= image
.tile_width
;
76 /* Set the tile dimensions if the user has not done so */
77 if (iflags
.wc_tile_width
== 0) {
78 iflags
.wc_tile_width
= image
.tile_width
;
80 if (iflags
.wc_tile_height
== 0) {
81 iflags
.wc_tile_height
= image
.tile_height
;
84 /* Parse the tile map */
85 get_tile_map(image
.image_desc
);
87 /* Split the image into tiles */
103 return have_palette
? palette
: NULL
;
106 /* TODO: derive tile_map from image_desc */
108 get_tile_map(image_desc
)
109 const char *image_desc
;
119 for (i
= 0; i
< num_tiles
; ++i
) {
120 free(tiles
[i
].pixels
);
121 free(tiles
[i
].indexes
);
128 free(blank_tile
.pixels
);
129 blank_tile
.pixels
= NULL
;
130 free(blank_tile
.indexes
);
131 blank_tile
.indexes
= NULL
;
136 struct TileSetImage
*image
;
139 image
->pixels
= NULL
;
140 free(image
->indexes
);
141 image
->indexes
= NULL
;
142 free(image
->image_desc
);
143 image
->image_desc
= NULL
;
146 const struct TileImage
*
150 if (tile_index
>= num_tiles
) {
153 return &tiles
[tile_index
];
159 const struct TileSetImage
*image
;
161 unsigned tile_rows
, tile_cols
;
162 size_t tile_size
, i
, j
;
163 unsigned x1
, y1
, x2
, y2
;
165 /* Get the number of tiles */
166 tile_rows
= image
->height
/ iflags
.wc_tile_height
;
167 tile_cols
= image
->width
/ iflags
.wc_tile_width
;
168 num_tiles
= tile_rows
* tile_cols
;
169 tile_size
= (size_t) iflags
.wc_tile_height
* (size_t) iflags
.wc_tile_width
;
171 /* Allocate the tile array */
172 tiles
= (struct TileImage
*) alloc(num_tiles
* sizeof(tiles
[0]));
173 memset(tiles
, 0, num_tiles
* sizeof(tiles
[0]));
175 /* Copy the pixels into the tile structures */
176 for (y1
= 0; y1
< tile_rows
; ++y1
) {
177 for (x1
= 0; x1
< tile_cols
; ++x1
) {
178 struct TileImage
*tile
= &tiles
[y1
* tile_cols
+ x1
];
179 tile
->width
= iflags
.wc_tile_width
;
180 tile
->height
= iflags
.wc_tile_height
;
181 tile
->pixels
= (struct Pixel
*)
182 alloc(tile_size
* sizeof(struct Pixel
));
183 if (image
->indexes
!= NULL
) {
184 tile
->indexes
= (unsigned char *) alloc(tile_size
);
186 for (y2
= 0; y2
< iflags
.wc_tile_height
; ++y2
) {
187 for (x2
= 0; x2
< iflags
.wc_tile_width
; ++x2
) {
188 unsigned x
= x1
* iflags
.wc_tile_width
+ x2
;
189 unsigned y
= y1
* iflags
.wc_tile_height
+ y2
;
190 i
= y
* image
->width
+ x
;
191 j
= y2
* tile
->width
+ x2
;
192 tile
->pixels
[j
] = image
->pixels
[i
];
193 if (image
->indexes
!= NULL
) {
194 tile
->indexes
[j
] = image
->indexes
[i
];
201 /* Create a blank tile for use when the tile index is invalid */
202 blank_tile
.width
= iflags
.wc_tile_width
;
203 blank_tile
.height
= iflags
.wc_tile_height
;
204 blank_tile
.pixels
= (struct Pixel
*)
205 alloc(tile_size
* sizeof(struct Pixel
));
206 for (i
= 0; i
< tile_size
; ++i
) {
207 blank_tile
.pixels
[i
].r
= 0;
208 blank_tile
.pixels
[i
].g
= 0;
209 blank_tile
.pixels
[i
].b
= 0;
210 blank_tile
.pixels
[i
].a
= 255;
212 if (image
->indexes
) {
213 blank_tile
.indexes
= (unsigned char *) alloc(tile_size
);
214 memset(blank_tile
.indexes
, 0, tile_size
);
219 read_png_tiles(filename
, image
)
220 const char *filename
;
221 struct TileSetImage
*image
;