OSDN Git Service

update travis setting
[jnethack/source.git] / win / share / bmptiles.c
1 /* NetHack 3.6    bmptiles.c    $NHDT-Date: 1457207054 2016/03/05 19:44:14 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.0 $ */
2 /* Copyright (c) Ray Chason, 2016. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "config.h"
6 #include "integer.h"
7 #include "tileset.h"
8
9 /* First BMP file header */
10 struct BitmapHeader {
11     char magic[2];
12     uint32 bmp_size;
13     uint32 img_offset;
14 };
15
16 /* Color model information for larger BMP headers */
17 struct CIE_XYZ {
18     uint32 ciexyzX;
19     uint32 ciexyzY;
20     uint32 ciexyzZ;
21 };
22
23 struct CIE_XYZTriple {
24     struct CIE_XYZ ciexyzRed;
25     struct CIE_XYZ ciexyzGreen;
26     struct CIE_XYZ ciexyzBlue;
27 };
28
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 */
55 };
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
63
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));
74
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;
81 {
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;
88
89     FILE *fp = NULL; /* custodial */
90     unsigned char *row_bytes = NULL; /* custodial */
91
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;
99
100     fp = fopen(filename, "rb");
101     if (fp == NULL) goto error;
102
103     /* Read the headers */
104     if (!read_header(fp, &header1)) goto error;
105     if (memcmp(header1.magic, "BM", 2) != 0) goto error;
106
107     if (!read_info_header(fp, &header2)) goto error;
108     if (!check_info_header(&header2)) goto error;
109
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;
116     }
117 #endif
118
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);
123
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);
132     }
133
134     /* Read the palette */
135     palette_size = get_palette_size(&header2);
136     if (!read_palette(fp, image->palette, palette_size)) goto error;
137
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;
148     }
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;
161             /*
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
168              */
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;
196                                 }
197                                 ++x;
198                             } else {
199                                 if (x < image->width) {
200                                     p[x] = b1 >> 4;
201                                 }
202                                 ++x;
203                                 if (x < image->width) {
204                                     p[x] = b1 & 0xF;
205                                 }
206                                 ++x;
207                             }
208                         }
209                         if (b2 & 1) {
210                             b1 = fgetc(fp);
211                             if (b1 == EOF) break;
212                         }
213                     }
214                 }
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;
224                             }
225                             ++x;
226                         } else {
227                             if (x < image->width) {
228                                 p[x] = b2 >> 4;
229                             }
230                             ++x;
231                             if (x < image->width) {
232                                 p[x] = b2 & 0xF;
233                             }
234                             ++x;
235                         }
236                     }
237                 }
238             }
239         }
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;
251
252             case 32:
253                 header2.RedMask   = 0x000000FF;
254                 header2.GreenMask = 0x0000FF00;
255                 header2.BlueMask  = 0x00FF0000;
256                 header2.AlphaMask = 0xFF000000;
257                 break;
258             }
259         }
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;
272                 }
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;
280                 }
281                 break;
282             case 8:
283                 for (x = 0; x < image->width; ++x) {
284                     ind[x] = row_bytes[x];
285                 }
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);
291                 }
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;
299                 }
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);
305                 }
306                 break;
307             }
308         }
309         free(row_bytes);
310         row_bytes = NULL;
311     }
312
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]];
317         }
318     }
319
320     fclose(fp);
321     return TRUE;
322
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;
333 }
334
335 /* Read and decode the first header */
336 static boolean
337 read_header(fp, header)
338 FILE *fp;
339 struct BitmapHeader *header;
340 {
341     unsigned char buf[14];
342     size_t size;
343
344     size = fread(buf, 1, sizeof(buf), fp);
345     if (size < sizeof(buf)) return FALSE;
346
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;
352 }
353
354 /* Read and decode the second header */
355 static boolean
356 read_info_header(fp, header)
357 FILE *fp;
358 struct BitmapInfoHeader *header;
359 {
360     unsigned char buf[124]; /* maximum size */
361     size_t size;
362     boolean have_color_mask;
363
364     memset(header, 0, sizeof(*header));
365
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;
371
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;
375
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 */
384
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 */
400
401     case 56: /* BITMAPV3INFOHEADER */
402         header->AlphaMask = read_u32(buf + 52);
403         /* fall through */
404
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 */
411
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;
427
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;
434
435     default:
436         return FALSE;
437     }
438
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);
446     }
447
448     return TRUE;
449 }
450
451 /* Check the second header for consistency and unsupported features */
452 static boolean
453 check_info_header(header)
454 const struct BitmapInfoHeader *header;
455 {
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
464
465     case 1:
466     case 24:
467         if (header->Compression != BI_RGB) return FALSE;
468         break;
469
470     case 4:
471         if (header->Compression != BI_RGB
472         &&  header->Compression != BI_RLE4) return FALSE;
473         break;
474
475     case 8:
476         if (header->Compression != BI_RGB
477         &&  header->Compression != BI_RLE8) return FALSE;
478         break;
479
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;
491
492     default:
493         return FALSE;
494     }
495
496     if (header->Height < 0 && header->Compression != BI_RGB
497             && header->Compression != BI_BITFIELDS) return FALSE;
498
499     return TRUE;
500 }
501
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;
506 {
507     switch (header->BitsPerPixel) {
508     case 1:
509         return 2;
510
511     case 4:
512         return header->ColorsUsed ? header->ColorsUsed : 16;
513
514     case 8:
515         return header->ColorsUsed ? header->ColorsUsed : 256;
516
517     default:
518         return 0;
519     }
520 }
521
522 /*
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
527  */
528 static boolean
529 read_palette(fp, palette, palette_size)
530 FILE *fp;
531 struct Pixel *palette;
532 unsigned palette_size;
533 {
534     unsigned i;
535     unsigned char buf[4];
536     unsigned read_size;
537
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;
546     }
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;
552     }
553     fseek(fp, 4 * (palette_size - read_size), SEEK_CUR);
554     return TRUE;
555 }
556
557 /* Decode an unsigned 16 bit quantity */
558 static uint16
559 read_u16(buf)
560 const unsigned char buf[2];
561 {
562     return ((uint16)buf[0] << 0)
563          | ((uint16)buf[1] << 8);
564 }
565
566 /* Decode an unsigned 32 bit quantity */
567 static uint32
568 read_u32(buf)
569 const unsigned char buf[4];
570 {
571     return ((uint32)buf[0] <<  0)
572          | ((uint32)buf[1] <<  8)
573          | ((uint32)buf[2] << 16)
574          | ((uint32)buf[3] << 24);
575 }
576
577 /* Decode a signed 32 bit quantity */
578 static int32
579 read_s32(buf)
580 const unsigned char buf[4];
581 {
582     return (int32)((read_u32(buf) ^ 0x80000000) - 0x80000000);
583 }
584
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;
591 {
592     struct Pixel pixel;
593
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;
599 }
600
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;
606 {
607     uint32 bits, shift;
608
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;
616         }
617         shift /= 2;
618         bits >>= shift;
619     }
620     color &= mask;
621     return color * 255 / mask;
622 }