• 内容
• 评论
• 相关

## 15-Bit BGR Format

The Super Nintendo / Super Famicom stores it’s palette in 512 bytes in a 15-bit BGR format. Each BGR word is 2 bytes, thus it is 512 bytes for 256 colors (256 x 2). The format for each BGR word looks like this:

```
10BBBBBGG GGGRRRRR

```

Bit 15 is unused and should be set to 0. Each color value can range from 0 - 31. So a R, G, B value of 31, 31, 31 represents white. As you can see this is quite different from the usual 24-bit RGB where the colors range from 0 - 255.

## Converting a 24-Bit RGB Color to a 15-Bit BGR Color

In order to convert a 24-bit RGB value into the 15-Bit BGR format, the 8-bit color value of the 24-Bit RGB color must be scaled down to 5-bits. Then the 3 color values must be packed into 2 bytes. This can be achieved by the following formula:

```
12345R = R / 8 (ie: 17 / 8 = 2)
G = G / 8 (ie: 16 / 8 = 2)
B = B / 8 (ie: 14 / 8 = 1)
=========
Color = B x 1024 + G x 32 + R

```

The following example show how to convert white (255,255,255) to the 15-bit format:

```
12345R = 255 / 8 = 31
G = 255 / 8 = 31
B = 255 / 8 = 31
================
Color = 31 x 1024 + 31 x 32 + 31 = 32767

```

So white as a 15-bit BGR color is 32767 or

 1 0x7FFF

in hex. And to clear up any confusion, YES, this value will be stored in LSB order (otherwise known as ‘bits reversed’). So you will see this as

 1 FF 7F

in the hex editor.

```
12345c = color;
int r = (c &amp; 0xF80000) &gt;&gt; 19;
int g = (c &amp; 0x00F800) &gt;&gt;  6;
int b = (c &amp; 0x0000F8) &lt;&lt;  7;
return b | g | r;

```

## Converting a 15-Bit BGR Color to a 24-Bit Color

To convert a 15-BGR value into 24-RGB values, is simply the reverse operation. The formula is:

```
123R = ((color       ) % 32) * 8
G = ((color /   32) % 32) * 8
B = ((color / 1024) % 32) * 8

```

The following example shows how to convert white (32767) to it’s respective RGB values:

```
1234567Color = 32767
R = (Color          % 32) x 8
R = (32767          % 32) x 8 = 31 x 8 = 248
G = ((color /   32) % 32) x 8
G = ((32767 /   32) % 32) x 8 = (1023 % 32) x 8 = 32 x 8 = 248
B = ((color / 1024) % 32) x 8
B = ((32767 / 1024) % 32) x 8 = (31 % 32) x 8 = 32 x 8 = 248

```

Since we are using powers of 2 we can use a bitmask of (color & 0x1F) instead of (color mod 32) incase you are using a older compiler that doesn’t optimize mod division by a constant. Also, it may be easier to think in hex instead of decimal:

```
123456789Color = 32767
R = (Color &amp; 31) * 8
= (32767 &amp; 31) * 8
= (0x7FFF &amp; 0x1F) &lt;&lt; 3
= 0x1F &lt;&lt; 3
= 0xF8
= 248

Similarly for green and blue ...

```

So the final output is (248, 248, 248). Uh-oh, 24-bit RGB white is (255, 255, 255) not (248, 248, 248). Apparently, what happened is there was a precision loss during the conversion. Think about it, if you convert a 24-bit value into a 15-bit you would have loss some precision. The three least significant bits are lost in each component. Thus, the extra precision that 24-bit color provides is lost and is unrecoverable.

So you won’t get precision but you can stretch the range rather easily after the conversion (_ensure_ that you use unsigned integer math for this):

A naïve approach would be to do a multiplication and division scaling:

```
123 R = (255*R)/31;
G = (255*G)/31;
B = (255*B)/31;

```

A faster approach is:

```
123R = R + R / 32
G = G + G / 32
B = B + B / 32

```

This seems strange at first glance, but what happens is that you replicate the top three bits of each component into the bottom three bits (which, as stated above, are empty after conversion). This, if you think long enough about it, has the effect of stretching the color values into the full (0,0,0) -> (255,255,255) range.

E.g. If red is close to 0, those three bits will also tend to be be 0 so you won’t lose the blackest black. If red is close to 248 (the maximum after conversion) those bits will all be 1’s, so you get full red. Between the extremes, it works out so you gradually get the required boost up to the real maximum (255).

0条评论