Drawing Graphics for Monochrome Compatibility
Wednesday, 6th April 2022
I'm no artist. That's one of the reasons why I target my games to a machine with a 4-colour screen. Give me 4 colours and a 16x16 pixel canvas, and I can just about manage to draw a decent sprite. Give me a modern resolution with 16 million colours, and I am quite lost.
As I practice drawing mockups and assets, I am learning a few things, though. One of the lessons learned is what to do and what not to do if you want compatibility with monochrome screens. You see, another reason that I target CGA graphics is that my only vintage PC hardware is a Hewlett Packard 100LX, which features a CGA monochrome LCD screen. I want my games to look as good as possible in colour, while still being playable on that monochrome machine.
While CGALIB supports rendering graphics to both colour and monochrome screens with little effort on the part of the programmer, I am finding that the artist still has to keep monochrome in mind. If you want to see what I mean, take a look at how Ossuary is rendered in monochrome. It's a mess. The stat modifiers are generally unreadable. Some of the sprites, such as apples, are barely visible against the ground. The apples are more ghostlike than the ghosts! The problem is rooted in the way that monochrome graphics are rendered by the CGALIB Graphics Library.
Let's have a quick recap on how the CGA graphics modes work. The two 320x200 modes work by pairing adjacent bits of memory together to make each pixel. A bit holds one of two values: 0 and 1. Pair them together and you get four values: 00, 01, 10 and 11, the binary representations of numbers 0, 1, 2 and 3. The colour modes use these bit pairs as the colours 0, 1, 2 and 3 for each pixel.
The 640x200 mode uses these same bits individually to give twice the resolution, but each pixel therefore only has the colour value 0 or 1. CGALIB treats this mode as if it were still a 320x200 colour mode. So when it plots a pixel in colour 2, for instance, it puts the values 1 and 0 into adjacent bits of memory. In 320x200 mode this binary pattern gives you colour 2 (red or magenta, depending on the palette). In 640x200 mode, you see a pair of pixels: the left one white and the right one black.
In this way CGA can take the same colour assets and display them in colour, or in monochrome as a dithered black and white image. No redrawing in necessary for monochrome, and only a minor change to the code is required to enable monochrome support. At least, that's the theory. In the robots demonstration game, it works quite well. So why doesn't it work as well in Ossuary?
The problem with Ossuary is it chooses dark red as a background colour. In the chosen palette (yellow, dark cyan, dark red, light grey), this dark red is colour value 2, and in monochrome that shows as the dithered white and black mentioned above. This in itself isn't bad, but some of the graphics and text are shown in cyan. Cyan is colour value 1, which in monochrome shows up as a dithered black and white pattern. See the problem? Dithered black and white isn't easily distinguishable from dithered white and black. The cyan apples are barely visible against the red background, and the cyan stat modifiers are unreadable.
So what's the solution? The easiest is to choose colour 0 or 3 as a background, both of which contrast well against the other three colours in the palette. This can be limiting, however: in the Ossuary palette, the dark red is an attractive colour to fill the screen, and neither yellow nor grey would give the same effect.
A more subtle solution is just to ensure that colours 1 and 2 are never used in contrast against one another, or at least not in any place where they need to be seen clearly. In Ossuary, avoiding that cyan text, and any largely cyan sprites, would have made the graphics clearer against the red background. Cyan sprites could be used, if they have a yellow or grey border to separate the cyan from the red.
The Anarchic Kingdom went for the easy method. Colour 0, the "official" background, is set to high intensity white. In colour this contrasts well against the low intensity red, green and brown foreground colours. In monochrome it remains black, and the white and dithered tiles are easily seen against it.
In Barren Planet I use a combination of methods. Most text is colour 3 (white) against colour 0 (dark grey), giving good contrast in both colour and monochrome. Map tiles are predominantly red, but all of the sprites have a grey outline so that even cyan sprites can be clearly seen.
I'm not tempted to redraw the Ossuary assets, as I've moved on to other projects. I plan to revisit the dungeon crawler genre again in the future, so I'll take the lessons learned here to ensure that my next dungeon crawler attempt is more accessible on a variety of displays.