During the Christmas break of 2018 I started working on a cross-platform video library that would work on DOS, Linux, and Web. The idea was really born from tinkering with some old C++ code that found on an old hard drive.
I wrote my first C++ code in 1995 in Borland C++ 3.1 on my old DOS computer. When I was a Junior in High School [ca 1993] I was part of what they call a “coding bootcamp” today. There were 2 Support Engineers from Borland, Tom Orsi and Jeff Peters, and they volunteered to teach a small group of HS students how to program in C. Most, but not all of us, had prior programming experience in another language. My experience was with Microsoft QBasic, Visual Basic for DOS, and Visual Basic 3.0 for Windows.
Over a several week period we participated in simple programming lessons, at the end we would all receive a brand new boxed copy of Borland C++ 4.0 as a pseudo graduation gift. Of all the things that were memorable about that class, it was playing the BETA release of DOOM after hours that I recall the most.
SLV_Programming_C_classThis is one of the lesson plans for the C programming class.
After the C coding class there was a break of several months before Tom Orsi offered to teach us 8086 assembly language programming. This class lasted another several weeks and at the conclusion most of us had a good grasp of the 8086 mnemonics and structure. During C programming class we received a copy of the Turbo C++ 3.0 manual, which is arguably the best teaching manual Borland ever produced. Those manuals had an almost cult-like status within Borland, coveted by many. In comparison, the Borland C++ 4.0 manuals were pretty awful, the layout changed, the content was broken up into numerous volumes, and the “How to program” content was more-or-less removed.
When I was a teen I was interested in graphics programming, like many other of my classmates. I was lucky to receive a VGA card and display for Christmas in 1992, which opened up a whole new world of programming capabilities, not to mention games! Prior to having a VGA display I had an EGA controller with CGA monitor, so I was limited to low resolution graphics and color depths. Combining my desire to write a C++ program, my desire to program graphics, and having a VGA display, I wrote a screensaver in C++ that displayed a BMP file of my company, APSoft. The APSoft name was coined sometime in 1994, but I registered the domain name in July 1995. Below you can see a capture of the screen saver in action:
The screensaver above implemented a BMP file reader and a class interface to VGA mode 11h, the 640×480 2 color mode. I chose this mode because the pixel format is packed as 8 bits per pixel, doesn’t require plane switching, doesn’t require palette modification, and it could directly accept the bitmap data from a BMP file.
class vga_mono { protected: unsigned char far *screen; unsigned char far *sbuffer; unsigned int far *tscreen; unsigned int *tsvscrn; unsigned int max_x; unsigned int max_y; char gr_or_txt; unsigned char temp; unsigned int p_o; unsigned char bit; unsigned int yhash[480]; public: vga_mono(void); char graphmode(void); char textmode(void); void setpixel(int x, int y, char visible); char getpixel(int x, int y); void cls(void); unsigned int maxx(void); unsigned int maxy(void); void tsave(void); void trestore(void); };
The class definition for this early C++ coding demo was very simple and contained only the minimum code required to implement a dot addressable graphics interface.
Fast forward about 25 years and the basic code that underpinned a screensaver demo has become a full fledged cross-platform graphics library. Ironically, VGA mode 11h is not yet supported.
What Is VGALIB?
VGALIB, is intended as a small and easy to use C++ graphics display framework for interfacing to VGA and SDL graphics output. It supports VGA 320×200 256 color mode, 160×100 16 color pseudo-graphics mode on VGA and CGA, and 320×200 256 color mode on SDL. The SDL support came as a necessary part of coding and debugging; I got tired of crashing dosbox and wanted a faster iterative process. Implementing SDL 1 support was easy and dropped right into the VGA 320×200 support since the pixel formats are the same.
Aside from the basic video display support, vgalib implements a canvas class that has all of the basic drawing primitives. The canvas class is used as the off-screen buffer for double buffering of the video display. You can implement multiple canvases and treat them as an image, since a canvas is implemented as a subclass of an image. Images can be copied onto canvases either opaquely or as sprites with a transparent background.
I implemented a full PNG decoder, since libpng was not available for DOS. The outcome is a compact single-class implementation of a PNG decoder. A static method makes it simple to load a PNG into an image without intermediate objects.
Also implemented is a simple text string drawing class. You can write a text string to an image and then blit that image to a canvas.
SDL presently supports user defined palettes, there are several pre-defined palettes you can use: CGA, VGA, and a modified SNES RGB palette. The latter implements an RGB332 direct color palette in the 256 color space, so you can directly convert truecolor images to the 8 bit color space without dithering. I have also implemented a nearest-color algorithm for mapping image palettes to the display palette, the quality is quite good and does a better job than GIMP in my opinion.
The most recent work has been done to refactor the display drivers into a C++ factory model so the code for individual display drivers is separated into dedicated classes. This necessitated using pointers for class references instead of dot notation, which is a little less convenient. You can workaround this by creating an object reference to a pointer dereference, ugly at initialization, but prettier when doing straight code. The refactoring will make it easier to implement the code for CGA, EGA, and Hercules graphics, it also brought 640×480 256 color mode to SDL.
I want to briefly talk about the internal model of vgalib for storing data. Early on it became clear that trying to maintain multiple bit ordering schemes for each supported display mode was going to be difficult. When I was implementing the text mode pseudo-graphics driver I came to the conclusion that code to write to text mode video memory was ugly and slow. By using a linear 8 bit image buffer, then implementing a translation function, the code was much cleaner and faster [the DOS translate functions are optimized with inline assembly language]. When you deal with modes like 13h (320x200x256), the translate is a straight [doubleword] copy, but with text mode it requires a lot of bit fiddling and packing, the function to copy and pack the data is MUCH faster than the code to individually address character cells. Each display driver implements a translate(…) method that converts a linear 8 bit buffer to whatever the destination buffer requires. It may seem wasteful on the surface to implement the screen buffer this way, but double buffering is required for smooth updates anyway, so this is a win. The offscreen buffer is generally built up of multiple components each frame, so the amount of data copying is minimized.
Lastly, let’s talk about the Web support in vgalib. Implementing SDL 1 brought Linux compatibility, but to work with emscripten, a web cross-compiler, I needed to rework the code to implement SDL 2 support. With SDL 2 it’s possible to use the vgalib framework to write C++ programs that run in a web browser with full animated graphics. This approach is MUCH faster and less resource intensive than a JavaScript DOS emulator. The other advantage to emscripten is that it brings a whole API with it that you can leverage to do things like Network I/O and persistent storage. If you grok C++ more than you grok Javascript, and care to make something cross platform compatible, vgalib will tick a bunch of boxes.
Below is an emscripten demo of vgalib doing some simple animation.
The demo below demonstrates the emulated 160×100 16 color text mode. It was written to demonstrate assembling a screen from several individual elements. There is a score bar at the top, a playfield, and a sprite that bounces around the playfield while rotating. This model minimizes the number of data copies by only changing the pieces of data that need updating.
How do I get VGALIB?
You can obtain the current version of VGALIB from my GitHub repository: