1 /*---------------------------------------------------------------------*
2
3 Project: bitmap reader
4 File: bmp.c
5
6 Copyright 1998, 1999 Nintendo. All rights reserved.
7
8 These coded instructions, statements and computer programs contain
9 proprietary information of Nintendo of America Inc. and/or Nintendo
10 Company Ltd., and are protected by Federal copyright law. They may
11 not be disclosed to third parties or copied or duplicated in any form,
12 in whole or in part, without the prior written consent of Nintendo.
13
14 Change History:
15
16 $Log: bmp.c,v $
17 Revision 1.3 2007/05/23 08:37:47 urata
18 Fixed biSizeImage of bmp header information.
19
20 Revision 1.2 2006/02/20 04:13:13 mitu
21 changed include path from dolphin/ to revolution/.
22
23 Revision 1.1 2005/12/16 08:34:26 urata
24 Initial checkin.
25
26
27 1 1/15/00 3:04a Hashida
28 Initial revision
29
30 $NoKeywords: $
31
32 -----------------------------------------------------------------------*/
33
34
35 #include <revolution.h>
36 #include <assert.h>
37 #include "bmp.h"
38
39
40 #define CLAMP(x,l,h) ((x > h) ? h : ((x < l) ? l : x))
41 #define TENT(a, b, c) (0.25 * (a) + 0.5 * (b) + 0.25 * (c))
42
43 // for endianness
44 #define REV16(x) ((u16)( ( (x) >> 8 ) + ( ((x) & 0xff) << 8 ) ))
45 #define REV32(x) ((u32)( ( ((x) & 0xff000000) >> 24) \
46 + ( ((x) & 0x00ff0000) >> 8 ) \
47 + ( ((x) & 0x0000ff00) << 8 ) \
48 + ( ((x) & 0x000000ff) << 24 ) ))
49
50 // decode a tga file into a 'DecodedFile' structure
51
openBmp(bmpInfo_s * bi,u8 * header)52 BOOL openBmp(bmpInfo_s* bi, u8* header)
53 {
54 u8* bInfoHeader;
55
56 assert( header != NULL );
57
58 // fill bmpInfo
59 assert(*header == 'B');
60 assert(*(header + 1) == 'M');
61
62 bi->biSizeImage = REV32(*(u32*)(header + 0x02));
63 bi->bfOffBits = REV32(*(u32*)(header + 0x0a));
64
65 bInfoHeader = header + 0x0e;
66
67 bi->width = REV32(*(u32*)(bInfoHeader + 0x04));
68 bi->height = REV32(*(u32*)(bInfoHeader + 0x08));
69 bi->biBitCount = REV16(*(u16*)(bInfoHeader + 0x0e));
70 bi->biCompression = REV32(*(u32*)(bInfoHeader + 0x10));
71
72 bi->paletteOff = 0x0e + REV32(*(u32*)(bInfoHeader));
73
74 if (bi->biBitCount == 24)
75 {
76 // there should be no rgbquad
77 assert(bi->bfOffBits == bi->paletteOff);
78 }
79 else
80 {
81 assert(bi->bfOffBits ==
82 bi->paletteOff + 2^bi->biBitCount * sizeof(rgbQuad_s));
83 }
84
85 return TRUE;
86 }
87
88 #ifdef XFB_SF
bmpToYCbCr(bmpInfo_s * bi,u8 * rawData,u8 * dest1,u8 * dest2)89 BOOL bmpToYCbCr(bmpInfo_s* bi, u8* rawData, u8* dest1, u8* dest2)
90 #else
91 BOOL bmpToYCbCr(bmpInfo_s* bi, u8* rawData, u8* dest)
92 #endif
93 {
94 u8 r, g, b;
95 u32 row, col;
96 double Y;
97 double Cb_pp, Cb_p, Cb;
98 double Cr_pp, Cr_p, Cr;
99 #ifdef XFB_SF
100 u8* dest;
101 #endif
102 rgbQuad_s* palette;
103 u32 paletteNum;
104 u32 bytesPerLine;
105 u8* imageData;
106 u8* imageDataStart;
107 u8* destStart;
108
109 palette = (rgbQuad_s*)(rawData + bi->paletteOff);
110 imageData = rawData + bi->bfOffBits;
111
112 bytesPerLine = (bi->width * bi->biBitCount + 7) / 8;
113 bytesPerLine = ((bytesPerLine + 3) / 4) * 4;
114
115 // we start from the last line because BMP stores its image upside down
116 imageData += bytesPerLine * (bi->height - 1);
117
118 for(row = 0; row < bi->height; row++)
119 {
120 #ifdef XFB_SF
121 dest = ((row & 0x1) == 0)? dest1:dest2;
122 #endif
123 destStart = dest;
124 imageDataStart = imageData;
125
126 for(col = 0; col < bi->width; col++)
127 {
128 switch(bi->biBitCount)
129 {
130 case 1: // monochrome
131 paletteNum = (u32)( ((*imageData) >> (7 - col % 8)) & 1 );
132 r = palette[paletteNum].red;
133 g = palette[paletteNum].green;
134 b = palette[paletteNum].blue;
135 break;
136
137 case 4: // 16 colors
138 paletteNum = (u32)(((*imageData) >> (4 - (col % 2)*4)) & 0x0f);
139 r = palette[paletteNum].red;
140 g = palette[paletteNum].green;
141 b = palette[paletteNum].blue;
142 break;
143
144 case 8: // 256 colors
145 paletteNum = (u32)*imageData;
146 r = palette[paletteNum].red;
147 g = palette[paletteNum].green;
148 b = palette[paletteNum].blue;
149 break;
150
151 case 24: // true color
152 // be careful about the order
153 b = *imageData;
154 g = *(imageData + 1);
155 r = *(imageData + 2);
156 break;
157
158 default:
159 OSReport("biBitCount %d is not supported\n", bi->biBitCount);
160 OSHalt("");
161 break;
162 } // end switch(bi->biBitCount)
163
164 Y = 0.257 * r + 0.504 * g + 0.098 * b + 16.0 + 0.5;
165 Cb = -0.148 * r - 0.291 * g + 0.439 * b + 128.0 + 0.5;
166 Cr = 0.439 * r - 0.368 * g - 0.071 * b + 128.0 + 0.5;
167
168 Y = CLAMP(Y , 16, 235);
169 Cb = CLAMP(Cb, 16, 240);
170 Cr = CLAMP(Cr, 16, 240);
171
172 *dest = (u8)Y;
173 if (col & 1)
174 {
175 // col is odd
176 *(dest - 1) = (u8)TENT(Cb_pp, Cb_p, Cb);
177 *(dest + 1) = (u8)TENT(Cr_pp, Cr_p, Cr);
178 }
179
180 // in case of col == 0, Cb_p doesn't have a valid value
181 // use Cb instead
182 Cb_pp = (col == 0)? Cb : Cb_p;
183 Cb_p = Cb;
184 Cr_pp = (col == 0)? Cr : Cr_p;
185 Cr_p = Cr;
186
187 if (bi->biBitCount == 1)
188 {
189 if (col % 8 == 7)
190 imageData++;
191 }
192 else if (bi->biBitCount == 4)
193 {
194 if (col % 2 == 1)
195 imageData++;
196 }
197 else
198 imageData += bi->biBitCount / 8;
199
200 dest += 2; // 2 bytes per pixel for 422YCbCr
201
202 } // end 'col' for loop
203
204 // if width is odd, add one pixel because 422YCbCr doesn't
205 // allow odd number for width
206 if (col % 2 == 1)
207 {
208 *dest = (u8)Y;
209 // col is odd (Cb = Cb_p, Cr = Cr_p)
210 *(dest - 1) = (u8)TENT(Cb_pp, Cb_p, Cb);
211 *(dest + 1) = (u8)TENT(Cr_pp, Cr_p, Cr);
212 dest += 2;
213
214 col++;
215 }
216
217 for( ; col < (bi->width + 15) / 16 * 16; col += 2)
218 {
219 // fill rest by black so that the next line is
220 // aligned by 32bytes
221 *dest++ = 16;
222 *dest++ = 128;
223 *dest++ = 16;
224 *dest++ = 128;
225 }
226
227 dest = destStart + (bi->width + 15) / 16 * 16 * 2;
228 imageData = imageDataStart - bytesPerLine;
229
230 #ifdef XFB_SF
231 if ( (row & 0x1) == 0 )
232 dest1 = dest;
233 else
234 dest2 = dest;
235 #endif
236 } // end 'row' for loop
237
238 // if height is odd, add a black line on the bottom
239 if (row % 2 == 1)
240 {
241 for(col = 0; col < (bi->width + 15) / 16 * 16; col += 2)
242 {
243 *dest++ = 16;
244 *dest++ = 128;
245 *dest++ = 16;
246 *dest++ = 128;
247 }
248 }
249
250 return TRUE;
251 }
252
253