Be the first to know and get exclusive access to offers by signing up for our mailing list(s).

Subscribe

We ❤️ Open Source

A community education resource

7 min read

Intro to DOS graphics: A simple way to draw with pixels

One neat trick that's easy in DOS but surprisingly tricky in Linux.

I like programming! It’s something I do for fun: To experiment, to tinker, or to explore new ideas. While I enjoy the many powerful tools available on Linux that make it easy to write new programs, I also appreciate the simplicity of writing programs for DOS.

If you don’t know, DOS was the Disk Operating System for PCs in the 1980s and early 1990s. I was in my teens during that time, and that’s where I explored programming. The DOS command line wasn’t very powerful, but if you knew a little about programming, you could create your own tools so you could do more work from the command line. And that’s exactly what I did.

I also loved the many DOS applications that let me do all kinds of work, like writing class papers in a word processor, or analyzing my physics lab data in a spreadsheet when I was an undergraduate student. But it was the ability to easily create new programs that really drew me to DOS programming.

I’d like to share one neat thing you can do with DOS programming that is easy to do in DOS but hard to do in Linux.

Read more: FreeDOS 1.4 is the retrocomputing system you’ve been waiting for

Displaying graphics

If you want to write a Linux program to display something in graphics mode, like a program that draws a picture inside a window, you need to load a lot of supporting libraries. For example, to write a program in GNOME, you need to initialize the toolkit, then define a new window, then set the title, size, and position. To draw within this window also requires defining a canvas and connecting to it so the program can add other elements.

In DOS programming, all programs start in console mode by default. A program can enter a graphics mode using a function, like Open Watcom’s _setvideomode, and specify a resolution, such as _VRES16COLOR for 640×480 at 16 colors. That’s it! Just one function to start displaying graphics in DOS.

#include <stdio.h>
#include <graph.h> /* graphics */

int main()
{
    if (_setvideomode(_VRES16COLOR) == 0) { /* 640x480 */
        puts("cannot set video mode");
        return 1;
    }

    /* add other stuff here */

    _setvideomode(_DEFAULTMODE);
    return 0;
}

This simplicity makes it very easy to experiment. Let’s explore one way to use graphics mode by drawing a special kind of triangle.

Read more: 5 FreeDOS editors I love

Painting with pixels

Sierpinski’s Triangle is a fractal image that you can generate by drawing a series of random pixels to the screen. The rules are simple: Define three corners of the triangle. Start at any random point on the screen. Then iterate by drawing a new dot or pixel halfway between the current dot and a random corner of the triangle. You’ll see Sierpinski’s Triangle emerge from this random collection of points.

The _setpixel function in Open Watcom paints a single pixel to the screen, at whatever x,y coordinate you give it. Coordinates start from zero. That means in _VRES16COLOR mode, the x coordinates range from 0 to 639, and y coordinates are from 0 to 479. You can set the pixel’s color with _setcolor. The _VRES16COLOR mode has 16 colors, so color numbers are between 0 (black) and 15 (bright white).

Let’s use these two functions to draw a pixel at a random coordinate on the screen, in a random color:

#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */

#include <conio.h> /* kbhit, getch */
#include <graph.h> /* graphics */

int main()
{
    short x,y;

    /* set video mode */

    if (_setvideomode(_VRES16COLOR) == 0) { /* 640x480 */
        puts("cannot set video mode");
        return 1;
    }

    /* random x,y */

    srand(time(NULL));

    x = rand() % 640; /* 0 .. 639 */
    y = rand() % 480; /* 0 .. 479 */

    _setcolor(rand() % 16); /* 0 .. 15 */
    _setpixel(x,y);

    if (getch() == 0) { getch(); }

    /* done */

    _setvideomode(_DEFAULTMODE);
    return 0;
}

DOS doesn’t support a kernel-level random number generator; Linux has a getrandom system call, but DOS programs need to use the rand standard library function to generate pseudo-random numbers between 0 and some large maximum value. Seed the random number generator with srand with a number, such as the current time with the time function.

After that, the program uses _setcolor to pick a random color from 0 to 15, then _setpixel to draw a dot at a random coordinate on the screen.

QEMU console with green pixel
See the bright green dot in the upper right?

The program also waits for the user to press a key before it exits. The getch function gets a single keystroke and returns its value; since DOS keyboards also have extended keys like F1, Home, End, and other keys, getch will return zero if the user pressed an extended key. In that case, the program needs to call getch one more time to get the extended value. That’s why the program calls getch twice if the first function was zero.

Read more: How to write your first FreeDOS program

Random pixels to draw a triangle

That’s not a very interesting program, but it’s a good start. Let’s add to the program by defining the corners of a triangle on the screen, at 320,0 (centered at the top of the screen) and 50,479 and 590,479 (at the bottom of the screen). To make it easier to refer to these later, we’ll define them in an array of three values, where each value is an x,y coordinate:

    struct { short x; short y; } corner[3] = {
        {320,0}, {50,479}, {590,479} };

We’ll draw the first pixel in black, at a random coordinate on the screen, and each successive pixel in a color from 1 (dark blue) to 15 (bright white). Each time the program draws a pixel, it places it halfway between that dot and a random corner of the triangle.

#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */

#include <conio.h> /* kbhit, getch */
#include <graph.h> /* graphics */

int main()
{
    struct { short x; short y; } corner[3] = {
        {320,0}, {50,479}, {590,479} };
    short x,y;
    short c;
    int n, key;

    /* set video mode */

    if (_setvideomode(_VRES16COLOR) == 0) { /* 640x480 */
        puts("cannot set video mode");
        return 1;
    }

    /* random start x,y */

    srand(time(NULL));

    x = rand() % 640; /* 0 .. 639 */
    y = rand() % 480; /* 0 .. 479 */

    /* iterate */

    c = 0;

    do {
        _setcolor(c);
        _setpixel(x,y);

        /* next value halfway between x,y and any corner */

        n = rand() % 3; /* 0 .. 2 */
        x = (x + corner[n].x) / 2;
        y = (y + corner[n].y) / 2;

        if (++c > 15) { c = 1; } /* rotate color */

        if (kbhit()) {
            key = getch();
            if (key == 0) { getch(); } /* ext key */
        }
    } while ((key != 27) && (key != 'q') && (key != 'Q'));

    /* done */

    _setvideomode(_DEFAULTMODE);
    return 0;
}

This new version of the program adds the kbhit function, which returns a true value if the user has pressed a key. If so, then the program uses getch to read the keystroke. The program continues in an infinite loop until the user presses the Q key or the Esc key. The Esc key has the value 27.

Drawing Sierpinski’s Triangle in DOS graphics screen capture using QEMU
Drawing Sierpinski’s Triangle in DOS graphics

Explore DOS programming with FreeDOS

If you want to explore DOS programming, I encourage you to download and install FreeDOS. The FreeDOS 1.4 distribution includes lots of programming tools, provided on the Bonus CD, so you can create your own DOS programs. For example, I used the Open Watcom C compiler to write this program.

I like writing programs like this in FreeDOS because using graphics mode is so easy in DOS. Whenever I need to write a program to visualize something, I usually do it in graphics mode on DOS. With just one function call to set up graphics mode, it’s hard to beat the simplicity to make a quick prototype.

More from We Love Open Source

About the Author

Jim Hall is an open source software advocate and developer, best known for usability testing in GNOME and as the founder + project coordinator of FreeDOS. At work, Jim is CEO of Hallmentum, an IT executive consulting company that provides hands-on IT Leadership training, workshops, and coaching.

Read Jim's Full Bio

The opinions expressed on this website are those of each author, not of the author's employer or All Things Open/We Love Open Source.

Want to contribute your open source content?

Contribute to We ❤️ Open Source

Help educate our community by contributing a blog post, tutorial, or how-to.

We're hosting two world-class events in 2026!

Join us for All Things AI, March 23-24 and for All Things Open, October 19-20.

Open Source Meetups

We host some of the most active open source meetups in the U.S. Get more info and RSVP to an upcoming event.