Dec 072017
EGA/VGA graphic library with fully commented ASM source. Image loads, stencils, transparent text, etc. Interfaced to MSC (all models).
File RTGRAF.ZIP from The Programmer’s Corner in
Category Assembly Language
EGA/VGA graphic library with fully commented ASM source. Image loads, stencils, transparent text, etc. Interfaced to MSC (all models).
File Name File Size Zip Size Zip Type
FONTS.ZIP 66904 64961 deflated
MAP.ZIP 78269 77092 deflated
RTGRAF.DOC 32421 9505 deflated
RTGRAF.H 3134 828 deflated
RTGRAF.OBJ 3720 2413 deflated
SOURCE.ZIP 33315 31361 deflated
SUITE.ZIP 62402 61376 deflated
TPCREAD.ME 199 165 deflated

Download File RTGRAF.ZIP Here

Contents of the RTGRAF.DOC file

RTGRAF (Rel 1.0) User's Manual


EGA/VGA Video Routines with Source

Rip Toren
POB 674
Columbia, MD


July 1, 1990 Page 1

RTGRAF (Rel 1.0) User's Manual

For the past 4 years, I have been downloading every EGA demo
program in hopes of locating an EGA video package that was small
useful and reasonably priced! I have followed up leads to many
people, and purposed company names, but all leads came to dead

Finally I came across the beginning of a game called 'SNARFS'.
Included in the package was the source of a basic (limited)
graphic package. I contacted the author, and was given
permission to make my own enhancements, but he did not have the
time (or inclination) to pursue them for me.

Having written assembly for a number of mainframe systems, as
well as the 6502, Z80 & 68000; I decided that I would have to
overcome my aversion to Intel assembler and set out on this

The objectives (requirements) for this project were:

1) Small & fast.
2) Commented assembly source.
3) EGA/VGA modes 640x350, 640x480, and SVGA 800x600.
4) Work in both large and small memory models.
5) Work in as many Graphic Modes as possible.

The functions supported would be:

1) Draw a 16 color pixmap image on the screen.
2) Use application supplied drawing modes.
3) Save a video image from the screen to a memory block.
(You can then save it to disc.)
4) Be able to use a bitmap to mask an image to an
irregular shape other than rectangles (hex grids for
5) Loadable text fonts that are transparent (no
6) Line draw between any two points.
7) Area fills with color.

In order to start the project, I bought about $100 worth of books
on Intel assembler and EGA/VGA video programming. Of these, one
stands out as being of the greatest help. It is such a good book
that the project would not have succeeded without it. This book
is Advanced Programmer's Guide to the EGA/VGA by George Sutty and
Steve Blair(1).


1(APGEGA/VGA) Advanced Programmer's guide to the EGA/VGA.
Authors George Sutty & Steve Blair. Publisher BRADY 1988, a
division of Simon & Schuster. ISBN 0-13-729030-X

July 1, 1990 Page 2

RTGRAF (Rel 1.0) User's Manual

This book (APGEGA/VGA) is much more than just a listing of
control registers and value that can be passed. The book goes
into great detail about uses, techniques, the 'why' as well as
the 'how'. Over 100 programming examples abound in each of 'C',
Pascal, and assembler. The source code for these examples is
also included on a PC disk for immediate use and experimentation.

While other books will tell you how to set a video plane and
write a bit, APGEGA/VGA gives you that, plus explores the
problems of bit alignments when the source and destinations have
different alignments within a byte. Techniques of accessing the
video memory in different modes are explored to see which method
works best in what situation.

As a result of the examples in APGEGA/VGA, I have included one of
the modules from this book directly into this library (with the
publishers permission). This module goes beyond the original
requirements, but is possibly quite useful. The only changes
made were to the parameter stack placements to port them from a
small memory model to a large memory model. No other
embellishments were done, since anyone really interested in the
topic should actually have the book right there on your desk.

WARNING! The APGEGA/VGA routine assumes that there are 640 pixels
across the screen. If your board supports 800x600 in the EGA
planar method, you will not be able to use this routines, since
it is hardwired for a width of 640 pixels.

The rest of the code started out from the video routines in
SNARFS, but have been modified to such a great extent that they
probably are unrecognizable as such. There are a number of
vestigial routines that I never really tried or really looked at.
These are concerned mostly with sound and clocks. The text and
hardware identification routines are completely of my own

As my first Intel assembly project, I think it went together
rather well. BUt I am sure that there will be those who are more
experienced in Intel assembly that will find flaws in technique
(or heaven forbid; implementation); I would like to here from you
with suggested improvements.

July 1, 1990 Page 3

RTGRAF (Rel 1.0) User's Manual

Registration, or What I expect from You
Registration, or What I expect from You

There are no registration requirements (for public domain
software) that come with this package. I have written it so that
people who have wanted to do public-domain graphics programs can
do just that without having to pay astronomical licencing fees.
I have heard of one popular package that wants $24,000 and the
right to market anything you develop.

Since this package contains a module from APGEGA/VGA, it may not
be used in any commercial venture without written permission from
myself, AND the publishers / authors of APGEGA/VGA. Please
include a copy of the response from Simon & Schuster (the parent
company of Brady) with your request.

What I would ask of you is that you send me a copy (5 1/4 low or
What I would ask of you is that you send me a copy (5 1/4 low or
high density) of anything that you develop and release using this
high density) of anything that you develop and release using this

I would like to continue to develop the package, as well as
support routines and libraries. Items such as font editors, more
advanced pixmap editors, windowing packages / libraries fall into
this category. Enhancements to the code, such as more efficient
implementations, additional functions, bug fixes are also
requested. Of course, final products that may float about the
networks are also requested.

In the end, the only way I will ever know that what I have done
over the last year is of any use is if I here from you. Once I
upload this package, I will never know. A simple post card or
letter would be appreciated.

Requests for special functions for your unique projects will
generally not be accepted. This work was done in my spare time
(when the kids let me have the machine), with no deadline
pressures. The reason I am publishing the source is so that you
may have a running start in developing your own code.


There is no warranty on this software for any function, purpose,
or correctness. You get what you pay for. But then how many
people that charge for their product give you source code and a
warranty that means anything?


This package writes graphic images to the video memory in the
manner of the classic EGA planar video memory with 4 color
planes. Each scan line is expected to be a multiple of 8 bits
wide. This approach works for both the EGA as well as the VGA in

July 1, 1990 Page 4

RTGRAF (Rel 1.0) User's Manual

640x480 modes. On the ATI VGAwonder (my development board), this
also works in 800x600 mode.

This is a 'down-and-dirty' package. By that, I mean that there is
only minimal error checking, if any. As an example, if you ask
that the video mode be set to 3, that is what I will do; even
though it is not a graphic mode. Coordinates are not bounds
checked to insure that they are within the screen. I expect your
application to do some of the work. Pointers to pixmaps are
expected to be in the correct format. The only checks I make are
that areas to be read or written do not have zero (0) width or
height (this can be an insidious bug).

This philosophy gives two benefits. The first is small code size
and fast execution. The second, is that you are not bound to my
concepts of what are correct calls. If you want to write to
memory off the visual page, go right ahead.

Now back to the 800x600 mode for a moment. While many
manufacturers implement the 800x600 in 16 color code the same as
the EGA in hardware, they generally each have a different mode
number for it. That being the case, RTGRAF will assume that any
video mode greater than 18 is for the 800x600 and set global
variables thusly.

Here is a list of different manufacturers and what I can glean
they use for the mode number for 800x600x16.

ATI VgaWonder 0x54
Orchid ProDesigner VGA 0x29
Orchid ProDesigner Plus "
Genoa 5300 "
Genoa 5400 "
STB Extra/EM "
Tseng "
Paradise Plus-16 0x58
Paradise Professional "
Video Seven Fastwrite 0x62
Video Seven VRAM "

I recommend that you check your documentation anyway, just to be

July 1, 1990 Page 5

RTGRAF (Rel 1.0) User's Manual


This single object module is designed to support all memory
models, as long as the arguments are passed correctly. A
compiler that claims ANSI compatibility to function prototying
should coerce the pointers and calls correctly based upon the
prototypes supplied in RTGRAF.h.

All functions are FAR calls, and all pointers are FAR pointers!
Images being read or written or limited to (64k - a-little-bit).
This is generally what you can place into a 'malloc'ed area, (not

void far hardware_check(void);

This function looks at the equipment flags and a couple of
bios functions in an attempt to determine the video adaptor
installed (CGA/EGA/VGA). It sets the appropriate external
integers to values consistent with the mode selected. See
RTGRAF.h for values.

void far setmode (int mode);

This function blindly attempts to set the video mode that
you pass. If the hardware_check has not been run, it will be
prior to setting the video mode. This function then sets the
external integers to inform you of the number of scan lines
visible on the screen, available in video memory, and the
size of a scan line in bytes. After this call your
application may modify these. The only ones that RTGRAF uses
are the number of bytes per scanline and the number of line
on the screen.

void far pix_set (int x, int y, int color);

This writes a single pixel at the supplied position (x,y) in
the supplied color (0-15).

int far pix_read (int x, int y);

This function simply returns the color at the specified
video memory coordinates (X/Y).

void far clearscreen (int color);

Simply clears the visual screen to the supplied color. The
size of the screen is computed by multiplying the external
integers 'bytes_per_line' by 'scan_deep'.

July 1, 1990 Page 6

RTGRAF (Rel 1.0) User's Manual

void far eread
(int x, int y,
int width, int height,
unsigned char far *pixmap);

This function will move a copy of the video image from the
video memory to the buffer pointer to by the 'pixmap'. The
size of this buffer should be:

((((pix_width-1)/8 )+1 ) * height * 4 ) + 4
^ ^ ^ ^
bytes wide scan lines color bits size data

If the buffer is mis-sized, you will generally get very poor
results, but 'eread' won't know that!

void far egaplot
(int x, int y,
unsigned char far *pixmap,
int rule);

This function plots the pixmap stored in 'picture' into the
video memory at the supplied coordinates (x,y). The rule
describes how the existing memory image is combined with the
new image. Possible rules are:

0 = write unmodified (force).
1 = Image ANDed with existing
2 = Image ORed with existing
3 = Image XORed with existing

(see APGEGA/VGA page 117 for visual examples of what the
different mode look like when the are used.)

Writing the image does not clip, nor check that wrap-around
takes place. The image may even be stored off visual screen
in the scan lines below the screen.

void far egamplot
(int x, int y,
unsigned char far *pixmap,
unsigned char far *bitmask,
int rule);

EGAMPLOT is basically the same function as EGAPLOT, with one
twist. An additional argument of a pointer to a bitmask.
This bitmask should have the same dimensions as the pixmap
(see section on Pixmap Format) minus the width and height
values as the first 4 bytes. If a bit is set in the bitmask,

July 1, 1990 Page 7

RTGRAF (Rel 1.0) User's Manual

the corresponding pixel will be processed into the screen
image. Think of this as a template or stencil that your are
painting through.

This routine is noticeably slower than a straight plot for
large images. This is due to the fact that there is an
additional far pointer, and three segments (image, mask, &
video) must be manipulated with only two segment registers
(DS & ES). The swapping takes time. The graphics bit mask
must also be reset for every byte for each color plane.

int far etext
(int x, int y,
char far *string,
int color,
char far *font);

This function places the supplied string on the screen using
the supplied font in the supplied color. If a character in
the string is not in the font, it is ignored. The x and y
coordinates specify the start of the baseline. See the
section on fonts to see exactly where your text will be put.

The value returned is the x coordinate just following the
last character printed. Use this as a point to start the
next string from.

void far solid_box
(int x0,int y0,
int x1,int y1,
int color);

This function simply fills a solid block in the color given.
No border is drawn. This routine uses a unique approach of
filling the area in 3 vertical strips, rather than in
horizontal scan line from left to right. This is one
technique that was shown in APGEGA/VGA.

void far draw_line
(int x0, int y0,
int x1, int y1,
int color );

This function draws a single pixel line between the two
points specified. The order of the arguments is not
important. The classic 'Bresenham' algorithm is used.

void far bitblt
(int Xsrc, int Ysrc,

July 1, 1990 Page 8

RTGRAF (Rel 1.0) User's Manual

int Xdst, int Ydst,
int width, int depth,
int function);

This function is one taken directly from APGEGA/VGA. It is a
transfer of one rectangular region of the video memory to
another. The parameters give the coordinates of the top left
of the source (Xsrc/Ysrc) and the top left of the
destination (Xdst/Ydst). Then a width in pixels and depth
are supplied. Finally the rule to be used when the block is
redisplayed (merged) with the destination memory. This
routine does not handle overlapping areas, as that was left
as a problem for the student.

!! 'bitblt' does not work for screen widths other than 640
pixels !!

July 1, 1990 Page 9

RTGRAF (Rel 1.0) User's Manual


These values are set by 'hardware_check()'. This is either
called explicitly, or as a result of 'set_mode()'. There are
examples of the uses for these values scattered about in the
sample code.

Externals from RTGRAF


extern int pixels_wide ; // screen width in pixels
extern int scan_deep ; // scan lines on the screen
extern int curr_vid_mode ; // video mode after setmode
extern int curr_vid_mon ; // monitor type
extern int curr_vid_card ; // video card
extern int prior_vid_mode; // old mode prior to
// set_mode
extern int max_scan_deep ; // max scan lines in video
// memory
extern int bytes_per_line; // # of bytes in 1 scan
// line


From the externals above, you can see that the externals as well
as the functions are all declared as 'far' entities. This is
because the package is written (at least now in release 1)
assuming 32-bit ('far') pointers and calls to all data and
routines. This allows the package to be used in both small and
large memory models (as long as you are using an ANSI compliant
compiler such as MSC 5.1 or compatible and include the
prototypes). The include file (RTGRAF.H) with the function
prototypes declares everything this way, so that the compiler can
be sure to pass segments, even in the small model mode.

July 1, 1990 Page 10

RTGRAF (Rel 1.0) User's Manual

Pixmap Format
Pixmap Format

A pixmap differs from a bitmap in that it carries more than one
bit of data for each pixel. With the EGA/VGA, there are 4 color
planes (in the standard modes), so there are 4 bits per pixel.

Given this arrangement, there can be a number of different ways
the bits can be arranged. In the following, the numbers '0', '1',
'2', & '3' represent bits from the respective color planes, while
'.' is a fill byte of 0. The following example will be for a
single scan line of 6 pixels.

1) Each plane is stored separately. In this arrangement
you have 4 bitmaps in a row, each one representing a
different color plane:

| | | | |

The above would represent an area one scanline deep by
8 bit wide. First are the red, then blue, then green,
and finally the intensity.

In this example, we have read only the first 6 pixels,
and then padded to a full byte with 0s for the last two
bits in each plane.

2) Each pixel could be done in 4 consecutive bits. This
arrangement would look like:

| | | |

As you can see, each nibble (half-byte) defines a
single pixel (planes 0-3). In this arrangement, there
are no fill bits, so the storage is smaller.

3) Variations of the ordering of the above. This might
include different ordering of the planes from method #1
or bit ordering of method #2.

For RTGRAF, a pixmap is stored using method #1. Video plane 0 is
stored first, then planes 1,2,&3. This approach requires the
selection of the color plane only 4 times (once per plane per
image). The EGA/VGA supports methods for 'packed-pixel' (method
#2) operations, but the manipulation of the nibbles seemed a bit
complicated for a novice assembly programmer.

The one item that is missing from the above is information that
defines where one plane stops and the next begins. RTGRAF

July 1, 1990 Page 11

RTGRAF (Rel 1.0) User's Manual

appends two 16-bit integers (Intel format) to the front of the
pixmap that are the width and height of the pixmap in pixels.
The resulting structure looks like this:

struct Pixmap {
short width;
short height;
u_char plane0[bytewide];
u_char plabe1[bytewide];
u_char plane2[bytewide];
u_char plane3[bytewide];

Since memory accesses are done in a minimum of bytes, each plane
is stored in a number of bytes that will hold the width, with
some possible padding on the end of the last byte. Therefore,
'bytewide' is (((pixel_width-1)/8)+1) bytes.

In researching this project, I contacted Microsoft in an attempt
to determine what format was used to store the results of
'_getimage()'. I was told that the format was proprietary.
Through empirical testing and analysis, I found that if I
accessed the image in a manner of method #2, and rearranged the
bits into method #1, I could display the image.

When a bitmask is used to stencil an image onto the screen, some
design decisions had to be made. One approach would be to store
the mask with the image (sort of as a fifth plane). The drawback
to this is that the image would always be masked, and would
require that it be designed as such. It also would not allow
dynamic changes to the bitmask in an easy fashion. The second
approach is a separate bitmap, but that wastes space, and only
one color plane would be selected as the mask.

In the end, I decided to use a separate bitmask, that does not
have the dimensional information (width & height). The width and
height are taken from the pixmap.

July 1, 1990 Page 12

RTGRAF (Rel 1.0) User's Manual

FONT file format
FONT file format

A word about graphic text is in order at this point. To us,
certain symbols have defined meanings, the value 0x0d is a
'carriage return' . But what a does is really just a
convention. In fact, the fonts used here are simply a set of bit
images arranged in a sequence for easy access. If you want to
terminate the current line, move down the screen and return to
the beginning of that next line, you will have to do that

The 'etext' routine displays character fonts on the screen in a
user supplied color. Only those pixels that are set in the
glyphs (characters) bitmap are set. This approach leaves any
background image intact around the characters. If you want a
background color, your application can put an appropriate solid
block there first.

The fonts are stored with a header of 6 bytes, followed by an
appropriate number of glyph bitmaps (there is no padding between
entries). The font header is structured as follows:

struct font_header {
char bytes_wide; //# of BYTES in a scan line
char scan_deep; //# of scan lines in box
char baseline; //scanline for bottom of 'M'
char pix_wide; //PIXEL width of box
char first_char; //number of 1st character
char last_char; //number of last character

From the above, you can see that the font is defined in terms of
a bounding box that will hold the extremes of the largest
characters in the font. The size of this box is defined by
'pix_wide' x 'scan_deep'. Within that box is a 'baseline' upon
which all characters rest. Decenders below the line (i.e.
y,j,g,) are below this baseline. The 'pix_wide' value determines
the number of pixels to the right to position the next character.
This value should include and inter-character spacing.

The extent of the character set is determined by the range from
'first_char' to 'last_char' inclusive. This may be [32...127] for
ASCII printables, or [1..255] for a PC set with graphic

The 'byte_wide' value is usually 1 or 2 for the number of bytes
that are needed to hold a single scan line. Any pad bits on the
right end of the last byte should be set to 0, but this is not
strictly needed.

July 1, 1990 Page 13

RTGRAF (Rel 1.0) User's Manual

The character structure is then repeated once for every character
in the range defined by 'first_char' to 'last_char'. The first
structure is the glyph for 'first_char'. The structure looks
like this:

struct glyph {
char pix_wide;
char bits [bytes_wide] [scan_deep];

The above structure defines a bit mask with one extra leading
byte. The 'pix_wide' above is for future work where the width of
each character can be set separately for proportional spacing.

Here is a layout for a single character:

v |-> Pad (hex)
Bytes_wide = 2 0000100000000000 = 08 00
Scan_deep = 10 0001110000000000 = 1C 00
Baseline = 8 0011011000000000 = 35 00
pix_wide = 11 0110001100000000 = 63 00
1111111110000000 = FF 80
1100000110000000 = C1 80
1100000110000000 = C1 80
Baseline > 1100000110000000 = C1 80
0000000000000000 = 00 00
0000000000000000 = 00 00

The in-memory layout (in hex) looks like:

0b 0800 1C00 3500 6300 FF80 C180 C180 C180 0000 0000
| \-----------------------v-----------------------/
pix_wide bit map of glyph

Included in this package is a program to convert a style of font
called a VFONT into my own format. Two version are available,
one converts to a binary file that can be loaded at run-time,
while the second produces output to stdout that can be captured
and used for an include file.

July 1, 1990 Page 14

 December 7, 2017  Add comments

Leave a Reply