Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | /** |
2 | * Bitmap Import for Imagination Pilots Entertainment 16-bit games (IPE16) |
||
3 | * - Blown Away - The Interactive Game by Imagination Pilots (BA) |
||
4 | * - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
||
5 | * - Where's Waldo? At the Circus (Waldo1) |
||
6 | * ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
||
7 | * Revision: 2018-02-15 |
||
8 | **/ |
||
9 | |||
10 | #include <stdio.h> |
||
11 | #include <stdint.h> |
||
12 | #include <stdbool.h> |
||
13 | #include <stdlib.h> |
||
14 | #include <string.h> |
||
15 | #include <assert.h> |
||
16 | |||
17 | #include "bitmap.h" |
||
18 | #include "ipe16_bmpimport.h" |
||
19 | |||
20 | Ipe16ColorTableEntry rgbquad_to_ipe16_rgb(RGBQUAD rq) { |
||
21 | Ipe16ColorTableEntry cte; |
||
22 | cte.r = rq.rgbRed; |
||
23 | cte.g = rq.rgbGreen; |
||
24 | cte.b = rq.rgbBlue; |
||
25 | return cte; |
||
26 | } |
||
27 | |||
28 | bool ipe16_bmp_import(FILE* fibBitmap, Ipe16BmpImportData* result) { |
||
29 | BITMAPFILEHEADER bitmapFileHeader; |
||
30 | BITMAPINFOHEADER bitmapInfoHeader; |
||
31 | |||
32 | #define EXIT_ERROR(msg) { sprintf(result->error, msg); return false; } |
||
33 | |||
34 | fseek(fibBitmap, 0, SEEK_SET); |
||
35 | |||
36 | if (!fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fibBitmap) || |
||
37 | (bitmapFileHeader.bfType != BI_SIGNATURE) || |
||
38 | !fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fibBitmap)) { |
||
39 | EXIT_ERROR("Not a bitmap file"); |
||
40 | } |
||
41 | |||
42 | if (bitmapInfoHeader.biCompression != BI_RGB) { |
||
43 | EXIT_ERROR("At the moment, only uncompressed files can be read."); |
||
44 | } |
||
45 | |||
46 | if (bitmapInfoHeader.biBitCount != 8) { |
||
47 | EXIT_ERROR("The color depth has to be 8 bpp."); |
||
48 | } |
||
49 | |||
50 | Ipe16ColorTable* ct = malloc(sizeof(Ipe16ColorTable)); |
||
51 | #define NUM_COLORS 256 |
||
52 | RGBQUAD rgba_colortable[NUM_COLORS]; |
||
53 | if (!fread(&rgba_colortable, sizeof(rgba_colortable), 1, fibBitmap)) { |
||
54 | EXIT_ERROR("Error reading color table."); |
||
55 | } |
||
56 | int i; |
||
57 | for (i=0; i<NUM_COLORS; ++i) { |
||
58 | Ipe16ColorTableEntry x; |
||
59 | x = rgbquad_to_ipe16_rgb(rgba_colortable[i]); |
||
60 | ct->colors[i] = x; |
||
61 | } |
||
62 | |||
63 | fseek(fibBitmap, bitmapFileHeader.bfOffBits, SEEK_SET); |
||
64 | |||
65 | const uint32_t realwidth = bitmapInfoHeader.biWidth; |
||
66 | const uint32_t realheight = abs(bitmapInfoHeader.biHeight); |
||
67 | const size_t bmpDataSize = realwidth*realheight; |
||
68 | unsigned char* bmpData = (unsigned char*)malloc(bmpDataSize); |
||
69 | assert(bmpData != NULL); |
||
70 | const int padded_width = (bitmapInfoHeader.biWidth + 3) & ~0x03; // http://stackoverflow.com/a/2022194/3544341 |
||
71 | unsigned char* bmpLine = (unsigned char*)malloc(padded_width); |
||
72 | assert(bmpLine != NULL); |
||
73 | int h; |
||
74 | for (h=0; h<realheight; ++h) { |
||
75 | if (fread(bmpLine, padded_width, 1, fibBitmap) != 1) { |
||
76 | free(bmpLine); |
||
77 | free(bmpData); |
||
78 | free(ct); |
||
79 | EXIT_ERROR("Error while reading pixel data."); |
||
80 | } |
||
81 | int idx; |
||
82 | if (bitmapInfoHeader.biHeight > 0) { |
||
83 | // "bottom-up" (most usual) |
||
84 | // Convert to "top-down": |
||
85 | idx = (realheight-1)-h; |
||
86 | } else { |
||
87 | // "top-down" |
||
88 | idx = h; |
||
89 | } |
||
90 | assert(idx*realwidth >= 0); |
||
91 | memcpy(bmpData+idx*realwidth, bmpLine, realwidth); |
||
92 | } |
||
93 | free(bmpLine); |
||
94 | |||
95 | result->colorTable = ct; |
||
96 | result->bmpData = bmpData; |
||
97 | result->bmpDataSize = bmpDataSize; |
||
98 | result->width = realwidth; |
||
99 | result->height = realheight; |
||
100 | result->error[0] = 0; |
||
101 | return true; |
||
102 | } |
||
103 | |||
104 | void ipe16_free_bmpimport_result(Ipe16BmpImportData *res) { |
||
105 | if (res->colorTable) free(res->colorTable); |
||
106 | if (res->bmpData) free(res->bmpData); |
||
107 | } |
||
108 |