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