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