DGC Game Devlog #1: Prologue

So, a couple of months ago, some of us came up with an "ingenious" idea. We're a bunch of DOS gaming nerds, sure, but most of us also have a programming background and DOS Game Club was actually founded by a bunch of people hanging out in a game development related IRC channel. What would be more appropriate than to use this dual footing we have to actually make a DOS game of our own?

There have been a few games published by DGC members over the last couple years, most recently voxel and Tijn's SlipSpeed, which is actually already a DOS game. But the idea for the DGC game would be to get more of our regulars to participate in the creation.

We brainstormed for a bit and came up with a few things we want to achieve. First of all, we want it to run smoothly on proper 90s hardware. The hardware we're aiming for at the moment is a mid range 486 machine, but the idea is to make it at least playable on a 386 as well.

Another thing we wanted from the beginning was an appropriate genre for a DOS game, and potentially one that has fallen a bit out of favour now. We quickly settled on a Cinematic Platformer, like Prince of Persia, Flashback or Another World. The fact that this genre is a bit vaguely defined actually gives us a bit of extra freedom while still sticking to a well known genre.

With some additional brainstorming, we decided it would be a tech noir story, a former space station cop, now private investigator doing PI stuff on a space station. There are a few more ideas for the story line, but I guess we'll share more details about that as we progress and this devlog is supposed to highlight more of the development aspects and less the content of the actual game - in the end a cinematic platformer will rely heavily on its story, so we'll try to keep this spoiler free.

This devlog will also highlight many of the technological decisions we'll be making (or have already made) and look somewhat into the details of DOS PC hardware, where I think it could be appropriate for a more technically interested audience.

Video Mode Shenanigans

I already mentioned that the game will have to run on a mid-range 486, but what exactly does that mean? One of the most interesting choices is of course the kind of graphics adapter this will be aimed at and on the 486 there's really a lot to choose from. Back in the day I have seen all kinds of graphics cards on 486s, some people still had their EGA cards they had taken over from their 386, others were running some sort of Super VGA on a 32 Bit VLB or PCI card.

The SVGA landscape is very heterogeneous so targeting those would be painful - it would require writing different graphics drivers for many card models or resorting to something like UniVBE. Those options are not very appealing and since the game is supposed to also run (albeit maybe with some reduced details and/or frame rate) on a 386, this option is off the table.

EGA and CGA would be really exotic on a 486 and even most 386 got upgraded to VGA sooner or later if they hadn't been sold with one in the first place. So, plain old standard VGA it is. This gives us a couple of options in terms of graphics modes, but for DOS games, the old BIOS mode 13h and the non-standard (but still supported on every VGA card) mode X, later popularized by Michael Abrash, are really the only sensible options.

Mode 13h, is a mode that IBM included in the original BIOS for the IBM PS/2 series, which introduced the VGA. To change the graphics mode through the BIOS (which was really the way IBM engineers intended all programmers to do it), one has to call a function in the BIOS (through means we may take a look at in a later log, since it's a fundamental piece of architecture of a DOS PC).

This function takes one parameter, the video mode you'd want to switch to. There are several modes available, accumulated over the years since the original IBM PC 5150 and for backwards compatibility, they are all still supported even on a modern PC (even though there might be some BIOS emulation involved nowadays). This mode number you'd pass for this mode is 13 hex (i.e. decimal 19, but it's more common to refer to it in hex).

In this mode, we get 320x200 pixels at 256 colors and it is probably by far the most common video mode you'd see in any game made between 1990 and 1995. It would be the perfect mode if it didn't have two major drawbacks:

First of all, and more noticeable to players is that pixels are not actually square in this mode. As you may have noticed, this mode has an aspect ratio of 8:5 pixels while PC monitors at the time had an aspect ratio of 4:3. So the picture would usually be stretched to fill the entire screen, which made all pixels slightly elongated. This is mostly a graphics design problem, where you have to make sure everything looks good after stretching. It can be a bit inconvenient to work with that on a modern screen, though on a high DPI screen on one of our development PCs it would be hardly a problem for graphics artists. But it also means all drawing code needs to take this into account and for example a circle drawing algorithm would not have to draw a circle but an ellipse which would then be stretched by the screen to look like a circle again. That's not pleasant at all.

Another downside of this mode is that it severely limits the amount of video memory a program can access in this mode. For certain reasons (which again, we might investigate in a later blog) in this mode we could only access 65536 bytes of video memory, just enough to hold a single screenful of pixels (each pixel takes up one byte in memory, so 320x200 pixels means 64000 bytes). Every fully compatible VGA card has 256K of video RAM though, so by using mode 13h we'd be wasting 3/4 of video memory.

That too, would be too big of a problem if that didn't prevent us from doing one important thing: Double Buffering. Double buffering is a method in which the screen shows one frame while we are working on preparing the next frame in a section of video memory that is not visible at the moment, where it doesn't interfere with the current frame.

If we were to prepare the screen to be displayed in the same section of memory that is currently being displayed, we'd have to make sure that we only update video memory whenever we're between two frames, and that's a very short amount of time: 1.55ms to be precise (again, for reasons that would make this article way too long, which is already is, haha).

1.55ms is so little time, in fact, that on a system with a 16 bit system bus (like every 386 and the majority of 486s), it is technically impossible to rewrite the whole screen buffer in that short amount of time: The AT bus is clocked at 8 MHz and it takes 4 clock cycles to perform one write operation. Each write operation can transfer 2 bytes to the video card, so there's a theoretical limit of about 12400 bytes we can transfer during this blanking interval. Not even enough to update 1/50 of the screen, and that's only for the fastest VGA cards available that could max out the bus. On a VLB or PCI system that situation can be substantially better, VLB can transfer up to 133MB/s on a 33MHz bus: enough for more than three full updates of the screen in the blanking period. But do we really only want to allow users of high end 486 machines to enjoy the game without video tearing?

Well, certainly not! It's bad enough that the game will run significantly slower on a 386 or lower end 486, but adding tearing on top of that is unacceptable. So, our options would be to either not update the whole screen each frame, which has been done by many games. Command Keen doe allow scrolling, but that's done using some hardware tricks that basically allow the game to only update the outer edges of the screen and use scrolling functionality of the VGA to scroll around the otherwise unchanged contents of most of the remaining screen. Only the edges and moving things ("sprites") needed a redraw each frame. But this prevents many cool graphics effects, like parallax scrolling or many animated objects on screen - clearly not a solution for us.

Mode X to the Rescue!

Now with all these issues it was clear that mode 13h was not for us. Luckily, over the years, a couple of smart people figured out how to use the entirety of the VGA's memory in 256 color mode while at the same time increasing the resolution to 320x240, which solved the issue of non-square pixels.

There seem to be a couple of reasons IBM decided to include a 320x200 pixel mode in the BIOS: First of all it fits nicely into the 65536 bytes that are "visible" to the CPU and thus easily accessible to any program. But it's also the resolution of the CGA, so programmers were probably already familiar with the resolution and it was relatively easy to rewrite CGA and EGA programs to make use of the added color capabilities. 320x240 would have been much better, mostly due to the square pixels, but it just wouldn't fit into the 65536 bytes window accessible by the CPU.

In other graphics modes, especially 640x480 at 16 colors, each byte the CPU could see was actually representing 4 bytes of actual graphics memory and which of those four bytes a program accessed was relatively complicated to change. In 320x200 mode this four times multiplexing is disabled, whence the limitation to 1/4 of the available memory.

But people soon began to realize that you could tweak mode 13h to re-enable this multiplexing behaviour, thus giving access to the entire 256K of video memory. With that done, it was also possible to change the resolution to 320x240 (which uses the same fundamental timing as 640x480, only that the VGA doubles each pixel both vertically and horizontally). Since 640x480 was guaranteed to be supported by every VGA monitor out there, 320x240 is also guaranteed to work on every VGA system.

The timing for 320x240 is a bit different from 320x200, which means the screen refresh rate is reduced from 70Hz to 60Hz. Also writing to video memory in this mode is more complicated (due to the multiplexing described earlier), but can also be a lot faster in certain situations than the old school mode 13h.

All in all, mode X has a lot of advantages, and a few, relatively minor disadvantages.

Other Hardware Considerations

Since the video and CPU questions are solved, there are a few other things we need to think about. Most importantly of course, what sound and music options are available to us?

It's almost guaranteed that a 486 gaming machine has either a Sound Blaster of some. The Sound Blaster was also very popular in the 386's days and it is also Adlib compatible. So aiming primarily at Adlib sound with Sound Blaster sound effects is a pretty safe bet to give players at least music, if not music and sound. We'll see how it goes, maybe we'll be able to support additional methods of sounds and music playback, it'd certainly be interesting to add MIDI support for all those Roland MIDI cards out there and somewhat popular among the wealthier gamers of the time.

Another thing I'd really like to do is add Gravis Ultra Sound and SoundBlaster AWE support. Obviously each additional method requires some extra work by the music composer and we'll see how far we can push him. But first we'll focus on Adlib music + SoundBlaster effects. Adding additional PC speaker sounds is going to be much easier, so that would be a good failsafe option for older machines.

Other than that, we're currently aiming to have the game runnable with 4MB of main memory and it's certainly going to be a game you'd have to install on your hard drive, as we clearly expect it to be at least a couple of megabytes in total. Since we're aiming at 386 and 486 machines, it makes sense to also make this a 32 bit game, which makes accessing memory beyond 640K a whole lot easier and has some other advantages.

Also, I think keyboard input will be the absolute minimum, but for platformers, joystick support also seems mandatory.

Development Environment

One of the ideas of this project is to use the most modern tools we have available for development. Some people develop games for old hardware on hardware that is at least era appropriate for their target. While that is certainly a cool thing to do and sounds like a very rewarding (albeit maybe a bit frustrating at times) experience, we decided to go the other route.

We're a mixed team of people, not all of us have actual retro hardware to work on. Also, using better tools (hopefully) means we can use more processing power of modern computers to pre-process data for the actual game and also keep the time needed to make actual development tools as short as possible. I have, for example, just finished a tool that converts tilemaps for the level and sprite sheets for game objects into data formats that we can use in the final game. This tool is not even 400 lines of Python code and was written over the course of a couple of afternoons.

If we had decided to do all development on actual DOS machines (or DOS tools in DOSBox), the same amount of time would probably have gotten us to a point where we could start thinking about making a level editor or similar. Instead we have all the tooling available already and can get started on the actual game code.

So, for the most part, development will happen on modern Linux systems (the entire build system is currently based around that and I don't think we'll change that), using DOSbox for testing, DJGPP as our C and C++ compiler (most of the game code will probably be written in modern C++) and all kinds of other tools like Aseprite and Tiled.

Current Status

As mentioned in the last section, we do already have some of the tooling needed to make the game. Some of the game engine code is written, too, though at the moment with a strong focus on hackability and not at all on speed. Currently just rendering a single tilemap layer at 30FPS requires DOSbox setting equivalent to a mid-range Pentium. But we do have enough experience with the old hardware's limitations to know what is possible later on and we're hiding all the slow parts behind high level abstractions - this way it'll be possible to re-implement the rendering pipeline using better methods for mode X without (hopefully) having to rewrite a lot of game code.

Rendering a tilemap (of one of my older, non-DOS games, for testing) in DOSBox: Tools and basic rendering code seem to work.

What's next?

Development continues, but this is a hobby project with a couple of people working on it on as much of their spare time as they can afford. It's also a rather big project, so don't expect the game to be done anytime soon.

Meanwhile we'll keep posting updates about interesting things happening in the project, certainly shorter than this one which is really supposed to give an overview over the last couple of months of development.

Each future post will likely pick one technical aspect of the game and discuss it a bit more in-depth, just like the video mode question in this one.

11 May 2020

Leave a Reply