Simple drawing of a heart in graphics mode

Draw a heart for Valentine’s Day

0

The heart is an enduring symbol of Valentine’s Day, and what better way to celebrate this Valentine’s Day than to draw a heart for the one you love. When I was in grade school, years ago, we would draw hearts by scribing the top half of two circles, then drawing a triangle below them. Today, we can use the same method by writing a short program in C.

Use graphics mode

It’s very easy to draw in graphics mode from a FreeDOS program, so I wrote this “heart” program using OpenWatcom C on FreeDOS. Use the _setvideomode() function to put the DOS display into graphics mode. This takes a single argument that defines the resolution you want to use. For example, _MRES16COLOR will use 320×200 graphics resolution at 16 colors.

  if (_setvideomode(_MRES16COLOR) == 0) {       /* 320x200 @ 16 color */
    puts("cannot set video mode");
    return 1;
  }

To erase the screen using a color, such as a dark gray, you can draw a rectangle from the upper-left corner to the bottom-right of the display. Coordinates in graphics mode start at 0,0 in the upper-left, and the bottom-right corner of a graphics display at 320×200 is 319,199.

  _setcolor(8);                        /* gray */
  _rectangle(_GFILLINTERIOR, 0, 0, 319, 199);

Draw two ovals

We can simulate a heart by drawing two ovals or ellipses that each take up half the screen. The OpenWatcom C compiler on DOS provides an _ellipse() function that does exactly this, using either _GFILLINTERIOR to create a filled ellipse or _GBORDER to just draw the outline. In our drawing, we can draw each ellipse to be half the width and half the height, which means the first ellipse starts at 0,0 and ends at 159,99. The second ellipse starts at 0,159 and ends at 319,99.

  _setcolor(12);                       /* br red */
  _ellipse(_GBORDER, 0, 0, 159, 99);
  _ellipse(_GBORDER, 160, 0, 319, 99);

Draw a triangle

The bottom of the heart drawing can be the outline of a triangle that approximately cuts the ovals in half. I wanted to start the triangle at the point just when the ovals start to curve inward at the bottom. Through some experimenting, I discovered that starting my triangle at 0,56 would neatly meet the bottom curve of the ellipse.

Using the OpenWatcom C compiler on DOS, you can use the _moveto() function to set an initial x,y coordinate and then draw a line to a second coordinate with the _lineto() function. This allows us to draw a simple triangle with these statements:

  _setcolor(7);                        /* white */

  _moveto(0, 56);
  _lineto(159, 199);
  _lineto(319, 56);

The result is an outline drawing of a heart:

Outline drawing of a heart in simple graphics mode

Putting it all together

To finish drawing the “Valentine” heart, we need to make a few changes: Let’s draw the ovals with _GFILLINTERIOR so they are both solid red. We’ll also use a routine to draw a series of solid lines to fill in the triangle.

Finding the slope of the triangle’s border line is easy: the rise (difference in y values) divided by the run (difference in x values) is 0.89375. To start the upper-left edge of the triangle at 0,56 means the function to define the triangle’s border line is y = 56 + 0.89375 x. We can use the same y value on the right as on the left, which will save a step in drawing the triangle. Effectively, this draws the triangle from both sides at the same time.

#include <stdio.h>
#include <conio.h>                     /* getch */
#include <graph.h>                     /* OpenWatcom on FreeDOS */

int
main()
{
  int x, y;

  if (_setvideomode(_MRES16COLOR) == 0) {       /* 320x200 @ 16 color */
    puts("cannot set video mode");
    return 1;
  }

  /* erase screen */

  _setcolor(8);                        /* gray */
  _rectangle(_GFILLINTERIOR, 0, 0, 319, 199);

  /* draw two ellipses that touch each other */

  _setcolor(12);                       /* br red */
  _ellipse(_GFILLINTERIOR, 0, 0, 159, 99);
  _ellipse(_GFILLINTERIOR, 160, 0, 319, 99);

  /* erase bottom half */

  _setcolor(8);                        /* gray */
  _rectangle(_GFILLINTERIOR, 0, 56, 319, 199);

  /* draw bottom triangle */

  _setcolor(12);                       /* br red */

  for (x = 0; x < 160; x++) {
    y = 56 + (0.89375 * x);

    _moveto(x, 56);
    _lineto(x, y);

    _moveto(319 - x, 56);
    _lineto(319 - x, y);
  }

  /* done */

  getch();

  _setvideomode(_DEFAULTMODE);
  return 0;
}
Simple drawing of a heart in graphics mode

It’s not a perfect heart drawing, but it looks good enough to me. After drawing the heart, the program uses the getch() function to wait for a keypress before resetting the video mode back to text and then exiting. Happy Valentine’s Day!

Leave a Reply