Correct color rendering of retroconsoles in emulators





Almost all gaming retro-consoles generate colors in some of the RGB coding options.



But these pixel colors are often designed for screens that are completely different from those on which emulators usually work. In this article I will talk about the importance of color emulation, I will give some code examples and screenshots.



The most common type of displays today are LCD panels. They are known for having very poor black levels. The differences between TN, PVA, and IPS do not affect this too much.



Some fans play on CRT monitors, and OLED screens are gaining in popularity, especially on phones and tablets. But in this article we will mainly consider LCD screens, although this technique is important for displays of any type.



Color accuracy



The first important detail: most computers operate in 24-bit color mode, providing 8-bit color detail for the red, green, and blue channels. But in most older gaming systems, colors are not set with such precision.



For example, Sega Genesis encodes 9-bit colors, which gives 3 bits per channel.



The most naive solution would be to put 3 bits in the highest 3 bits of the output, and leave the lower 5 bits blank, but the white color becomes a little gray.



Example:



  000 000 000 -> 000'00000 000'00000 000'00000
 111 111 111 -> 111'00000 111'00000 111'00000 






If you fill them with units, then black becomes too light.



Example:



  000 000 000 -> 000'11111 000'11111 000'11111
 111 111 111 -> 111'11111 111'11111 111'11111 






The solution is to repeat the original bits so that they fill all the output bits.



Example:



  000 -> 000 000 00 ...
 010 -> 010 010 01 ...
 011 -> 011 011 01 ...
 111 -> 111 111 11 ... 


In the form of code:



  uint8 red = r << 5 |  r << 2 |  r >> 1
 // rrr00000 |  000rrr00 |  000000rr -> rrrrrrrr 


Screen emulation



Gaming retro systems were not designed to work on modern LCD computer monitors. Typically, home consoles were designed for CRT screens, and portable consoles used much older and less accurate LCD panels.



In this article, we will not consider screen artifacts, such as screen curvature, scan lines, chromatic aberration, interframe blending, aperture grids, etc.: for now, we will focus only on the colors of individual pixels.



PC monitors



Monitors have a fairly wide range of colors, because only some of them are professionally calibrated to standards like SRGB, but in general, the best we can do is try to emulate colors as if we are using a correctly calibrated SRGB monitor.



CRT Emulation: Super Nintendo



The main difference between CRT screens and LCD monitors of computers is the significantly reduced black levels, which can only be slightly compensated by the gamma correction curve:



  // SNES colors are in RGB555 format, so there are 32 levels for each channel
 static const uint8 gammaRamp [32] = {
   0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
   0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
   0x88,0x90,0x98,0xa0,0xa8,0xb0,0xb8,0xc0
   0xc8,0xd0,0xd8,0xe0,0xe8,0xf0,0xf8,0xff
 }; 


This table is borrowed from Overload of Super Sleuth / Kindred. It obscures the lower half of the color palette, leaving the upper part unchanged.



This has an amazing effect on the image during emulation: the original is shown on the top, the image with the applied gamma correction is shown below:











LCD Emulation: Game Boy Advance



Game Boy Advance had one of the worst LCD screens with completely faded colors. The cunning developers realized that by significantly exaggerating the colors, one can get more pleasant results on real equipment.



Of course, if you use these colors on a standard LCD monitor, the result will be a colorful nightmare. Fortunately, we can compensate for this by creating fairly natural colors:



  double lcdGamma = 4.0, outGamma = 2.2;
 double lb = pow (B / 31.0, lcdGamma);
 double lg = pow (G / 31.0, lcdGamma);
 double lr = pow (R / 31.0, lcdGamma);
 r = pow ((0 * lb + 50 * log + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255/280);
 g = pow ((30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255/280);
 b = pow ((220 * lb + 10 * log + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255/280); 


This piece of code is written by Talarubi.



A much more striking contrast compared to a CRT is the original on top, the color-corrected version below:











LCD Emulation: Game Boy Color



The Game Boy Color screen was surprisingly better at reproducing color, and only a slight color blur can be present in the final picture.



The following algorithm is quite popular in Game Boy Color emulators:



  R = (r * 26 + g * 4 + b * 2);
 G = (g * 24 + b * 8);
 B = (r * 6 + g * 4 + b * 22);
 R = min (960, R) >> 2;
 G = min (960, G) >> 2;
 B = min (960, B) >> 2; 


Unfortunately, I do not know who wrote the algorithm. If you know, then let me know so that I can indicate authorship!



As before, the original on the left, the version with color correction - on the right:







This example was specially chosen: although the original looks more lively and preferable, if you look closely, you can notice the chess pattern around the character, which is lighter than the background.



Most likely, it was an oversight on the part of the developers, because on a real Game

Boy Color shades of white are blurred and two different shades of color merge with each other almost flawlessly.



Finally



There are many more systems that still lack good color emulation filters.

They are very difficult to configure. Of the most important examples, you can point out WonderSwan and Neo Geo Pocket, which at the time of writing did not have good filters for approximating colors.



Portable consoles are still more complicated because they often lack backlight (and sometimes front light!) And there are ways to change the contrast, so there is no true color value for a specific RGB value.



A particularly interesting borderline case is WonderSwan Color, which has a programmable flag to increase the contrast of the displayed image.

We do not yet know how to reliably emulate such behavior, and it is unclear whether we can do it at all.



Color emulation is an area that needs more attention, so if you are a specialist in mathematics and color analysis, then your help would be very useful for the emulation scene!



All Articles