I always found retro games very interesting. Since I grew up playing browser games and most of them were emulated I think it played a big role in defining this interest in me.
Anyways, So among all the other platforms DOS (Disk Based Operating System) is one of my favorite. I have recently installed FreeDOS and plan to program on it as hobby.
Today, I will explain how you can draw pixels on screen using C as the programming language, FreeDOS as the operating system and Doing by directly writing to VGA (Video Graphics Array).
Some Info About VGA
VGA (Video Graphics Array) is a video display controller that was first introduced in IBM PS/2 line computers.
Generally,
The 3h mode also known as Text Mode can be used to print text and is used in Terminal and CLI applications/games to display text.
The 13h mode also known as Graphics Mode can be used to plot pixels, draw shapes and images on screen. It is used by 2D/3D games.
This blog post will mostly focus on VGA mode 13h.
Drawing A Single Pixel
To draw a single pixel we will first create a new C source file pixel.c (you can name it whatever you want).
Before we can draw anything we need to switch our video mode from Text Mode to Graphics Mode.
We do the following:
#include <dos.h>
#include <bios.h>
int main() {
// Define a REGS union
union REGS regs;
regs.h.ah = 0; // Set AH to 0x0 because we want to set video mode
regs.h.al = 0x13; // Set AL to 0x13 because we want Graphics Mode
int86(0x10, ®s, ®s); // Call Intrrupt 10h
return 0;
}
Here we first include two headers dos.h and bios.h. These are needed to get the REGS union and int86() function. You can also inline assembly but I choose to code this way.
Now we are in Graphics Mode. We can now draw pixel on screen of a specific color.
We can do it like this:
#include <dos.h>
#include <bios.h>
int main() {
union REGS regs;
unsigned char far* vga = (unsigned char far*)0xA0000000;
unsigned short offset = 0;
int x = 0;
int y = 0;
int color = 0x0C;
regs.h.ah = 0;
regs.h.al = 0x13;
int86(0x10, ®s, ®s);
offset = y * 320 + x;
vga[offset] = color; // Set pixel at offset with a specific color
return 0;
}
Here we first declare a pointer that stores the VGA address. This address is 0xB000 for Text Mode and 0xA000 for Graphics Mode.
For DOS we need to declare it as a far pointer and asign memory address 0xA0000000. (if we wanted Text Mode it would be 0xB0000000)
We also declare an offset variable since the VGA buffer is a 1D array unlike computer screens that are 2D. We can calculate offset from x and y by doing:
offset = y * MAX_WIDTH + x
In VGA 13h mode screen resolution can range from 320x200 to 640x480. So I did:
offset = y * 320 + x
I also declared a color variable.
Below is the VGA pallette with HEX code:
This means that we want to draw a pixel with a Bright Red color.
If we now compile the code as is there would be a bright red pixel drawn on screen.
I am using the OpenWatcom compiler to compile my code for FreeDOS.
What's that? You can't switch back to your Terminal?? :(
Don't worry you can switch back to Text Mode before terminating the program.
We can do this:
#include <dos.h>
#include <bios.h>
#include <conio.h>
int main() {
union REGS regs;
unsigned char far* vga = (unsigned char far*)0xA0000000;
unsigned short offset = 0;
int x = 0;
int y = 0;
int color = 0x0C;
regs.h.ah = 0;
regs.h.al = 0x13;
int86(0x10, ®s, ®s);
offset = y * 320 + x;
vga[offset] = color;
// Wait for an input
getch();
// Switch back to Text Mode and terminate
regs.h.ah = 0;
regs.h.al = 0x03;
int86(0x10, ®s, ®s);
return 0;
}
Here we use getch() provided by conio.h to read for an input. So if any key is pressed we immediately switch back to VGA 3h Text Mode.
Filling The Entire Screen With Random Colored Pixels
With the knowledge of how to draw a single pixel we can now do a for loop and loop over the entire screen filling it with random colors!
We do that like this:
#include <dos.h>
#include <bios.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
int random_range(int min, int max) {
return rand() % (max - min + 1) + min;
}
int main() {
union REGS regs;
unsigned char far* vga = (unsigned char far*)0xA0000000;
unsigned short offset = 0;
int x = 0;
int y = 0;
// Seed rand() with time
srand(time(NULL));
regs.h.ah = 0;
regs.h.al = 0x13;
int86(0x10, ®s, ®s);
for (x = 0; x < 320; x++) {
for (y = 0; y < 200; y++) {
offset = y * 320 + x;
vga[offset] = random_range(0, 0x0F); // Assign a random color ranging from 0x0 to 0x0F
}
}
getch();
regs.h.ah = 0;
regs.h.al = 0x03;
int86(0x10, ®s, ®s);
return 0;
}
Here we define a new function random_range for generating random integer values in a set range.
We first seed rand() using time provided by time.h. Then we do two for loops one for x and one for y.
This will start form (0, 0) and end at (320, 200) which is our screen resolution.
Then we calculate the offset and set the current pixel with a random color ranging from 0x0 to 0x0F.
Compiling and running the code gives us a screen filled with random colored pixels.
Conclusion
That's it! Now you can create cool games or graphical applications for DOS :D
I also posted this blog on my newly created personal website: https://nabir14.github.io/website



Top comments (0)