衔着鱼D猫 发表于 2016-9-26 23:10

技术帖:SFC 调色板数据格式

本文由 痕 原创

出处:http://langrisser.xyz/sfc-palette

网上找到的资料。(http://wiki.superfamicom.org/snes/show/Palettes)

这个跟PS版的应该是一样的。

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:0BBBBBGG GGGRRRRRBit 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:R = 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 + RThe following example show how to convert white (255,255,255) to the 15-bit format:R = 255 / 8 = 31
G = 255 / 8 = 31
B = 255 / 8 = 31
================
Color = 31 x 1024 + 31 x 32 + 31 = 32767So white as a 15-bit BGR color is 32767 or0x7FFFin 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 asFF 7Fin the hex editor.c = color;
int r = (c & 0xF80000) >> 19;
int g = (c & 0x00F800) >>6;
int b = (c & 0x0000F8) <<7;
return b | g | r;Converting a 15-Bit BGR Color to a 24-Bit ColorTo convert a 15-BGR value into 24-RGB values, is simply the reverse operation. The formula is:R = ((color       ) % 32) * 8
G = ((color /   32) % 32) * 8
B = ((color / 1024) % 32) * 8The following example shows how to convert white (32767) to it’s respective RGB values:Color = 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 = 248Since 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:Color = 32767
R = (Color & 31) * 8
= (32767 & 31) * 8
= (0x7FFF & 0x1F) << 3
= 0x1F << 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: R = (255*R)/31;
G = (255*G)/31;
B = (255*B)/31;A faster approach is:R = R + R / 32
G = G + G / 32
B = B + B / 32This 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).



Doi_Doi 发表于 2016-9-26 23:55

SFC归到DER
页: [1]
查看完整版本: 技术帖:SFC 调色板数据格式