www.delorie.com/djgpp/doc/ug/graphics/intro.html   search  
Guide: Graphics fundamentals

In order to make a program that displays graphical images, you must switch the video hardware into one of the many possible graphics resolutions. In these modes the screen image is created from a grid of tiny dots called pixels, each of which can be set to a different color. You can construct complicated shapes by combining many of these dots into a suitable pattern, kind of like having a piece of graph paper where each square can be colored differently. In the most common PC video modes a pixel occupies exactly one byte of memory, allowing it to take on any of 256 possible different colors, but modern graphics cards also support resolutions with more colors, for example hicolor modes that use 16 bit pixels (65536 different colors), and truecolor modes with 24 bit pixels (up to 16777216 possible colors).

There are many libraries that can make djgpp graphics programming significantly easier, such as Allegro, GRX, and Jlib, but this file will not attempt to describe their use because that is already covered in the documentation of the respective packages. This material is intended for people who want to write their own graphics code "from the ground up", without using any third-party libraries. It does not assume any previous experience of PC graphics programming, but does require you to have some understanding of DPMI memory mapping and the basics of how to access conventional memory (this material is covered in the preceding (not yet written!) chapter).

A graphics screen consists of an array of pixels called a "framebuffer". By convention a framebuffer is indexed with the origin (zero) at the top left corner, the X axis increasing to the right, and the Y axis increasing as you move down the screen. This fits in with the layout of a C array, so you could declare your screen array as a simple 2d array, for example in a 320x200 resolution you might have:

   unsigned char screen_image[200][320];

Note that the Y dimension comes before the X value: this might seem counterintuitive, but is necessary in order for the memory layout to be correct.

After this declaration you can access the pixel at location (x,y) using normal C array syntax, for example to draw a pixel onto the framebuffer you would write:

   screen_image[y][x] = color;

This looks very simple, but in many situations it is better to treat the framebuffer as a one-dimensional C array and compute the pixel offset yourself (this would be needed if your program is going to run in more than one possible resolution, as the width of the screen and hence the dimensions of the array will not be known at compile time). To use this system you would rewrite the framebuffer declaration as:

   unsigned char screen_image[320*200];

and draw a pixel with the code:

   screen_image[y*320+x] = color;

So far these framebuffers have just been normal arrays in memory, so no matter what you draw onto them the results will never be shown on the screen. But you will be glad to hear that the graphics hardware uses the exact same format to store the image which it displays on your monitor, so you can just copy the picture from this memory framebuffer into the special area of memory that is used by the VGA card, and it will be displayed for all to see! Writing directly to the video memory is complicated by the fact that it is located outside your normal address space, so special techniques are needed to access it, and for this reason people often find it more convenient to prepare an entire frame of graphics in a memory buffer (as described above) and only copy it across to the video memory once the entire image is complete, but the principles remain the same.

  webmaster     delorie software   privacy  
  Copyright 2019   by root     Updated Apr 23 2019