NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / win / share / bmptiles.c
blobd17b379409b671b3f7a8480fb10153ffffc7cc79
1 /* aNetHack 0.0.1 bmptiles.c $ANH-Date: 1457207054 2016/03/05 19:44:14 $ $ANH-Branch: chasonr $:$ANH-Revision: 1.0 $ */
2 /* Copyright (c) Ray Chason, 2016. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 #include "config.h"
6 #include "integer.h"
7 #include "tileset.h"
9 /* First BMP file header */
10 struct BitmapHeader {
11 char magic[2];
12 uint32 bmp_size;
13 uint32 img_offset;
16 /* Color model information for larger BMP headers */
17 struct CIE_XYZ {
18 uint32 ciexyzX;
19 uint32 ciexyzY;
20 uint32 ciexyzZ;
23 struct CIE_XYZTriple {
24 struct CIE_XYZ ciexyzRed;
25 struct CIE_XYZ ciexyzGreen;
26 struct CIE_XYZ ciexyzBlue;
29 /* Second BMP file header */
30 /* This one can vary in size; contents can vary according to the size */
31 struct BitmapInfoHeader {
32 uint32 Size; /* 12 40 52 56 108 124 64 */
33 int32 Width; /* 12 40 52 56 108 124 64 */
34 int32 Height; /* 12 40 52 56 108 124 64 */
35 uint16 NumPlanes; /* 12 40 52 56 108 124 64 */
36 uint16 BitsPerPixel; /* 12 40 52 56 108 124 64 */
37 uint32 Compression; /* 40 52 56 108 124 64 */
38 uint32 ImageDataSize; /* 40 52 56 108 124 64 */
39 int32 XResolution; /* 40 52 56 108 124 64 */
40 int32 YResolution; /* 40 52 56 108 124 64 */
41 uint32 ColorsUsed; /* 40 52 56 108 124 64 */
42 uint32 ColorsImportant; /* 40 52 56 108 124 64 */
43 uint32 RedMask; /* 52 56 108 124 */
44 uint32 GreenMask; /* 52 56 108 124 */
45 uint32 BlueMask; /* 52 56 108 124 */
46 uint32 AlphaMask; /* 56 108 124 */
47 uint32 CSType; /* 108 124 */
48 struct CIE_XYZTriple Endpoints; /* 108 124 */
49 uint32 GammaRed; /* 108 124 */
50 uint32 GammaGreen; /* 108 124 */
51 uint32 GammaBlue; /* 108 124 */
52 uint32 Intent; /* 124 */
53 uint32 ProfileData; /* 124 */
54 uint32 ProfileSize; /* 124 */
56 /* Compression */
57 #define BI_RGB 0
58 #define BI_RLE8 1
59 #define BI_RLE4 2
60 #define BI_BITFIELDS 3
61 #define BI_JPEG 4
62 #define BI_PNG 5
64 static uint16 FDECL(read_u16, (const unsigned char buf[2]));
65 static uint32 FDECL(read_u32, (const unsigned char buf[4]));
66 static int32 FDECL(read_s32, (const unsigned char buf[4]));
67 static struct Pixel FDECL(build_pixel, (const struct BitmapInfoHeader *, uint32));
68 static unsigned char FDECL(pixel_element, (uint32, uint32));
69 static boolean FDECL(read_header, (FILE *, struct BitmapHeader *));
70 static boolean FDECL(read_info_header, (FILE *, struct BitmapInfoHeader *));
71 static boolean FDECL(check_info_header, (const struct BitmapInfoHeader *));
72 static unsigned FDECL(get_palette_size, (const struct BitmapInfoHeader *));
73 static boolean FDECL(read_palette, (FILE *, struct Pixel *, unsigned));
75 /* Read a .BMP file into the image structure */
76 /* Return TRUE if successful, FALSE on any error */
77 boolean
78 read_bmp_tiles(filename, image)
79 const char *filename;
80 struct TileSetImage *image;
82 struct BitmapHeader header1;
83 struct BitmapInfoHeader header2;
84 unsigned palette_size;
85 size_t num_pixels, size;
86 unsigned x, y, y_start, y_end, y_inc;
87 unsigned bytes_per_row;
89 FILE *fp = NULL; /* custodial */
90 unsigned char *row_bytes = NULL; /* custodial */
92 image->width = 0;
93 image->height = 0;
94 image->pixels = NULL; /* custodial, returned */
95 image->indexes = NULL; /* custodial, returned */
96 image->image_desc = NULL; /* custodial, returned */
97 image->tile_width = 0;
98 image->tile_height = 0;
100 fp = fopen(filename, "rb");
101 if (fp == NULL) goto error;
103 /* Read the headers */
104 if (!read_header(fp, &header1)) goto error;
105 if (memcmp(header1.magic, "BM", 2) != 0) goto error;
107 if (!read_info_header(fp, &header2)) goto error;
108 if (!check_info_header(&header2)) goto error;
110 #if 0 /* TODO */
111 if (header2.Compression == BI_PNG) {
112 /* Image data is an embedded PNG bit stream */
113 boolean ok = do_read_png_tiles(fp, image));
114 fclose(fp);
115 return ok;
117 #endif
119 /* header2.Height < 0 means the Y coordinate is reversed; the origin is
120 * top left rather than bottom left */
121 image->width = header2.Width;
122 image->height = labs(header2.Height);
124 /* Allocate pixel area; watch out for overflow */
125 num_pixels = (size_t) image->width * (size_t) image->height;
126 if (num_pixels / image->width != image->height) goto error; /* overflow */
127 size = num_pixels * sizeof(image->pixels[0]);
128 if (size / sizeof(image->pixels[0]) != num_pixels) goto error; /* overflow */
129 image->pixels = (struct Pixel *) alloc(size);
130 if (header2.BitsPerPixel <= 8) {
131 image->indexes = (unsigned char *) alloc(num_pixels);
134 /* Read the palette */
135 palette_size = get_palette_size(&header2);
136 if (!read_palette(fp, image->palette, palette_size)) goto error;
138 /* Read the pixels */
139 fseek(fp, header1.img_offset, SEEK_SET);
140 if (header2.Height < 0) {
141 y_start = 0;
142 y_end = image->height;
143 y_inc = 1;
144 } else {
145 y_start = image->height - 1;
146 y_end = (unsigned) -1;
147 y_inc = -1;
149 if (header2.Compression == BI_RLE4 || header2.Compression == BI_RLE8) {
150 unsigned char *p;
151 p = image->indexes;
152 memset(p, 0, num_pixels);
153 x = 0;
154 y = image->height - 1;
155 while (TRUE) {
156 int b1, b2;
157 b1 = fgetc(fp);
158 if (b1 == EOF) goto error;
159 b2 = fgetc(fp);
160 if (b2 == EOF) goto error;
162 * b1 b2
163 * 0 0 end of line
164 * 0 1 end of bitmap
165 * 0 2 next two bytes are x and y offset
166 * 0 >2 b2 is a count of bytes
167 * >0 any repeat b2, b1 times
169 if (b1 == 0) {
170 if (b2 == 0) {
171 /* end of line */
172 --y;
173 x = 0;
174 } else if (b2 == 1) {
175 /* end of bitmap */
176 break;
177 } else if (b2 == 2) {
178 /* next two bytes are x and y offset */
179 b1 = fgetc(fp);
180 if (b1 == EOF) break;
181 b2 = fgetc(fp);
182 if (b2 == EOF) break;
183 x += b1;
184 y += b2;
185 } else {
186 /* get bytes */
187 int i;
188 if (y < image->height) {
189 p = image->indexes + y * image->width;
190 for (i = 0; i < b2; ++i) {
191 b1 = fgetc(fp);
192 if (b1 == EOF) break;
193 if (header2.BitsPerPixel == 8) {
194 if (x < image->width) {
195 p[x] = b1;
197 ++x;
198 } else {
199 if (x < image->width) {
200 p[x] = b1 >> 4;
202 ++x;
203 if (x < image->width) {
204 p[x] = b1 & 0xF;
206 ++x;
209 if (b2 & 1) {
210 b1 = fgetc(fp);
211 if (b1 == EOF) break;
215 } else {
216 /* repeat b2, b1 times */
217 int i;
218 if (y < image->height) {
219 p = image->indexes + y * image->width;
220 for (i = 0; i < b1; ++i) {
221 if (header2.BitsPerPixel == 8) {
222 if (x < image->width) {
223 p[x] = b2;
225 ++x;
226 } else {
227 if (x < image->width) {
228 p[x] = b2 >> 4;
230 ++x;
231 if (x < image->width) {
232 p[x] = b2 & 0xF;
234 ++x;
240 } else {
241 bytes_per_row = (image->width * header2.BitsPerPixel + 31) / 32 * 4;
242 row_bytes = (unsigned char *) alloc(bytes_per_row);
243 if (header2.Compression == BI_RGB) {
244 switch (header2.BitsPerPixel) {
245 case 16:
246 header2.RedMask = 0x001F;
247 header2.GreenMask = 0x07E0;
248 header2.BlueMask = 0xF800;
249 header2.AlphaMask = 0x0000;
250 break;
252 case 32:
253 header2.RedMask = 0x000000FF;
254 header2.GreenMask = 0x0000FF00;
255 header2.BlueMask = 0x00FF0000;
256 header2.AlphaMask = 0xFF000000;
257 break;
260 for (y = y_start; y != y_end; y += y_inc) {
261 struct Pixel *row = image->pixels + y * image->width;
262 unsigned char *ind = image->indexes + y * image->width;
263 size = fread(row_bytes, 1, bytes_per_row, fp);
264 if (size < bytes_per_row) goto error;
265 switch (header2.BitsPerPixel) {
266 case 1:
267 for (x = 0; x < image->width; ++x) {
268 unsigned byte = x / 8;
269 unsigned shift = x % 8;
270 unsigned color = (row_bytes[byte] >> shift) & 1;
271 ind[x] = color;
273 break;
274 case 4:
275 for (x = 0; x < image->width; ++x) {
276 unsigned byte = x / 2;
277 unsigned shift = (x % 2) * 4;
278 unsigned color = (row_bytes[byte] >> shift) & 1;
279 ind[x] = color;
281 break;
282 case 8:
283 for (x = 0; x < image->width; ++x) {
284 ind[x] = row_bytes[x];
286 break;
287 case 16:
288 for (x = 0; x < image->width; ++x) {
289 uint16 color = read_u16(row_bytes + x * 2);
290 row[x] = build_pixel(&header2, color);
292 break;
293 case 24:
294 for (x = 0; x < image->width; ++x) {
295 row[x].r = row_bytes[x * 3 + 2];
296 row[x].g = row_bytes[x * 3 + 1];
297 row[x].b = row_bytes[x * 3 + 0];
298 row[x].a = 255;
300 break;
301 case 32:
302 for (x = 0; x < image->width; ++x) {
303 uint32 color = read_u32(row_bytes + x * 2);
304 row[x] = build_pixel(&header2, color);
306 break;
309 free(row_bytes);
310 row_bytes = NULL;
313 if (image->indexes != NULL) {
314 size_t i;
315 for (i = 0; i < num_pixels; ++i) {
316 image->pixels[i] = image->palette[image->indexes[i]];
320 fclose(fp);
321 return TRUE;
323 error:
324 if (fp) fclose(fp);
325 free(row_bytes);
326 free(image->pixels);
327 image->pixels = NULL;
328 free(image->indexes);
329 image->indexes = NULL;
330 free(image->image_desc);
331 image->image_desc = NULL;
332 return FALSE;
335 /* Read and decode the first header */
336 static boolean
337 read_header(fp, header)
338 FILE *fp;
339 struct BitmapHeader *header;
341 unsigned char buf[14];
342 size_t size;
344 size = fread(buf, 1, sizeof(buf), fp);
345 if (size < sizeof(buf)) return FALSE;
347 memcpy(header->magic, buf + 0, 2);
348 header->bmp_size = read_u32(buf + 2);
349 /* 6 and 8 are 16 bit integers giving the hotspot of a cursor */
350 header->img_offset = read_u32(buf + 10);
351 return TRUE;
354 /* Read and decode the second header */
355 static boolean
356 read_info_header(fp, header)
357 FILE *fp;
358 struct BitmapInfoHeader *header;
360 unsigned char buf[124]; /* maximum size */
361 size_t size;
362 boolean have_color_mask;
364 memset(header, 0, sizeof(*header));
366 /* Get the header size */
367 size = fread(buf, 1, 4, fp);
368 if (size < 4) return FALSE;
369 header->Size = read_u32(buf + 0);
370 if (header->Size > sizeof(buf)) return FALSE;
372 /* Get the rest of the header */
373 size = fread(buf + 4, 1, header->Size - 4, fp);
374 if (size < header->Size - 4) return FALSE;
376 have_color_mask = FALSE;
377 switch (header->Size) {
378 case 124: /* BITMAPV5INFOHEADER */
379 /* 120 is reserved */
380 header->ProfileSize = read_u32(buf + 116);
381 header->ProfileData = read_u32(buf + 112);
382 header->Intent = read_u32(buf + 108);
383 /* fall through */
385 case 108: /* BITMAPV4INFOHEADER */
386 header->GammaBlue = read_u32(buf + 104);
387 header->GammaGreen = read_u32(buf + 100);
388 header->GammaRed = read_u32(buf + 96);
389 header->Endpoints.ciexyzBlue.ciexyzZ = read_u32(buf + 92);
390 header->Endpoints.ciexyzBlue.ciexyzY = read_u32(buf + 88);
391 header->Endpoints.ciexyzBlue.ciexyzX = read_u32(buf + 84);
392 header->Endpoints.ciexyzGreen.ciexyzZ = read_u32(buf + 80);
393 header->Endpoints.ciexyzGreen.ciexyzY = read_u32(buf + 76);
394 header->Endpoints.ciexyzGreen.ciexyzX = read_u32(buf + 72);
395 header->Endpoints.ciexyzRed.ciexyzZ = read_u32(buf + 68);
396 header->Endpoints.ciexyzRed.ciexyzY = read_u32(buf + 64);
397 header->Endpoints.ciexyzRed.ciexyzX = read_u32(buf + 60);
398 header->CSType = read_u32(buf + 56);
399 /* fall through */
401 case 56: /* BITMAPV3INFOHEADER */
402 header->AlphaMask = read_u32(buf + 52);
403 /* fall through */
405 case 52: /* BITMAPV2INFOHEADER */
406 header->BlueMask = read_u32(buf + 48);
407 header->GreenMask = read_u32(buf + 44);
408 header->RedMask = read_u32(buf + 40);
409 have_color_mask = TRUE;
410 /* fall through */
412 case 40: /* BITMAPINFOHEADER */
413 case 64: /* OS22XBITMAPHEADER */
414 /* The last 24 bytes in OS22XBITMAPHEADER are incompatible with the
415 * later Microsoft versions of the header */
416 header->ColorsImportant = read_u32(buf + 36);
417 header->ColorsUsed = read_u32(buf + 32);
418 header->YResolution = read_s32(buf + 28);
419 header->XResolution = read_s32(buf + 24);
420 header->ImageDataSize = read_u32(buf + 20);
421 header->Compression = read_u32(buf + 16);
422 header->BitsPerPixel = read_u16(buf + 14);
423 header->NumPlanes = read_u16(buf + 12);
424 header->Height = read_s32(buf + 8);
425 header->Width = read_s32(buf + 4);
426 break;
428 case 12: /* BITMAPCOREHEADER */
429 header->BitsPerPixel = read_u16(buf + 10);
430 header->NumPlanes = read_u16(buf + 8);
431 header->Height = read_u16(buf + 6);
432 header->Width = read_u16(buf + 4);
433 break;
435 default:
436 return FALSE;
439 /* For BI_BITFIELDS, the next three 32 bit words are the color masks */
440 if (header->Compression == BI_BITFIELDS && !have_color_mask) {
441 size = fread(buf, 1, 12, fp);
442 if (size < 12) return FALSE;
443 header->RedMask = read_u32(buf + 0);
444 header->GreenMask = read_u32(buf + 4);
445 header->BlueMask = read_u32(buf + 8);
448 return TRUE;
451 /* Check the second header for consistency and unsupported features */
452 static boolean
453 check_info_header(header)
454 const struct BitmapInfoHeader *header;
456 if (header->NumPlanes != 1) return FALSE;
457 switch (header->BitsPerPixel) {
458 #if 0 /* TODO */
459 case 0:
460 if (header->Compression != BI_PNG) return FALSE;
461 /* JPEG not supported */
462 break;
463 #endif
465 case 1:
466 case 24:
467 if (header->Compression != BI_RGB) return FALSE;
468 break;
470 case 4:
471 if (header->Compression != BI_RGB
472 && header->Compression != BI_RLE4) return FALSE;
473 break;
475 case 8:
476 if (header->Compression != BI_RGB
477 && header->Compression != BI_RLE8) return FALSE;
478 break;
480 case 16:
481 case 32:
482 if (header->Compression != BI_RGB
483 && header->Compression != BI_BITFIELDS) return FALSE;
484 /* Any of the color masks could conceivably be zero; the bitmap, though
485 * limited, would still be meaningful */
486 if (header->Compression == BI_BITFIELDS
487 && header->RedMask == 0
488 && header->GreenMask == 0
489 && header->BlueMask == 0) return FALSE;
490 break;
492 default:
493 return FALSE;
496 if (header->Height < 0 && header->Compression != BI_RGB
497 && header->Compression != BI_BITFIELDS) return FALSE;
499 return TRUE;
502 /* Return the number of palette entries to read from the file */
503 static unsigned
504 get_palette_size(header)
505 const struct BitmapInfoHeader *header;
507 switch (header->BitsPerPixel) {
508 case 1:
509 return 2;
511 case 4:
512 return header->ColorsUsed ? header->ColorsUsed : 16;
514 case 8:
515 return header->ColorsUsed ? header->ColorsUsed : 256;
517 default:
518 return 0;
523 * Read the palette from the file
524 * palette_size is the number of entries to read, but no more than 256 will
525 * be written into the palette array
526 * Return TRUE if successful, FALSE on any error
528 static boolean
529 read_palette(fp, palette, palette_size)
530 FILE *fp;
531 struct Pixel *palette;
532 unsigned palette_size;
534 unsigned i;
535 unsigned char buf[4];
536 unsigned read_size;
538 read_size = (palette_size < 256) ? palette_size : 256;
539 for (i = 0; i < read_size; ++i) {
540 size_t size = fread(buf, 1, sizeof(buf), fp);
541 if (size < sizeof(buf)) return FALSE;
542 palette[i].b = buf[0];
543 palette[i].g = buf[1];
544 palette[i].r = buf[2];
545 palette[i].a = 255;
547 for (; i < 256; ++i) {
548 palette[i].b = 0;
549 palette[i].g = 0;
550 palette[i].r = 0;
551 palette[i].a = 255;
553 fseek(fp, 4 * (palette_size - read_size), SEEK_CUR);
554 return TRUE;
557 /* Decode an unsigned 16 bit quantity */
558 static uint16
559 read_u16(buf)
560 const unsigned char buf[2];
562 return ((uint16)buf[0] << 0)
563 | ((uint16)buf[1] << 8);
566 /* Decode an unsigned 32 bit quantity */
567 static uint32
568 read_u32(buf)
569 const unsigned char buf[4];
571 return ((uint32)buf[0] << 0)
572 | ((uint32)buf[1] << 8)
573 | ((uint32)buf[2] << 16)
574 | ((uint32)buf[3] << 24);
577 /* Decode a signed 32 bit quantity */
578 static int32
579 read_s32(buf)
580 const unsigned char buf[4];
582 return (int32)((read_u32(buf) ^ 0x80000000) - 0x80000000);
585 /* Build a pixel structure, given the mask words in the second header and
586 * a packed 16 or 32 bit pixel */
587 static struct Pixel
588 build_pixel(header, color)
589 const struct BitmapInfoHeader *header;
590 uint32 color;
592 struct Pixel pixel;
594 pixel.r = pixel_element(header->RedMask, color);
595 pixel.g = pixel_element(header->GreenMask, color);
596 pixel.b = pixel_element(header->BlueMask, color);
597 pixel.a = header->AlphaMask ? pixel_element(header->AlphaMask, color) : 255;
598 return pixel;
601 /* Extract one element (red, green, blue or alpha) from a pixel */
602 static unsigned char
603 pixel_element(mask, color)
604 uint32 mask;
605 uint32 color;
607 uint32 bits, shift;
609 if (mask == 0) return 0;
610 bits = 0xFFFF; /* 0xFF, 0xF, 0x3, 0x1 */
611 shift = 16; /* 8, 4, 2, 1 */
612 while (bits != 0) {
613 if ((mask & bits) == 0) {
614 mask >>= shift;
615 color >>= shift;
617 shift /= 2;
618 bits >>= shift;
620 color &= mask;
621 return color * 255 / mask;