home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Devil's Doorknob BBS Capture (1996-2003)
/
devilsdoorknobbbscapture1996-2003.iso
/
Dloads
/
PROGRAMM
/
FGL112B.ZIP
/
USER09.DOC
< prev
next >
Wrap
Text File
|
1992-10-05
|
127KB
|
2,861 lines
Chapter 9
Images and
Image Management
136 Fastgraph User's Guide
Overview
Within the context of Fastgraph, an image is a rectangular area of video
memory containing some type of picture. An image might be something as
simple as a pointing hand icon, or as detailed as the dashboard of a sports
car. Fastgraph includes several routines to display, retrieve, and
manipulate images, as well as transfer them between different areas of video
memory. This chapter will discuss these routines in detail. The information
presented here, combined with the video page management techniques described
in the previous chapter, will provide the tools we need for sophisticated
animation techniques.
Mode-Independent Bit-Mapped Images
This section will discuss the image display routines that use the same
bit-mapped image format for all graphics video modes. Another class of
routines, described in the next section, use different formats for different
video modes. While these mode-independent image display routines are more
general, they achieve this generality at the sake of execution speed. This
may especially be a concern if the image is large, or if speed is critical in
an application (as in arcade-style graphics). For many programs, however,
the mode-independent routines provide all the image display capability
needed.
Let's begin with an example of a very simple image. Suppose we need to
display a small triangle whose perimeter is a different color than its
interior. To use this image with Fastgraph, we must inscribe it in a
rectangular area. Hence, the pixel representation of our triangle might
appear as shown below.
. . . . * . . . .
. . . * x * . . .
. . * x x x * . .
. * x x x x x * .
* * * * * * * * *
As shown in this diagram, our triangle is 9 pixels wide at its base and
5 pixels high. The pixels indicated by an asterisk (*) are the triangle's
perimeter, while those indicated by an x represent its interior points. We
need to distinguish between these pixels because they will be different
colors. The pixels shown as periods (.) are not part of the triangle itself.
They are required to make the image rectangular, so from Fastgraph's
perspective they are indeed part of the image.
The Fastgraph routine fg_drawmap is a suitable routine for drawing our
triangle. To use fg_drawmap, we must create separate bit maps for each color
in the image (excluding the points used to fill the rectangular region, which
is considered transparent). In this example, we will thus need two bit
maps -- one for the perimeter points, and one for the interior points. Let's
break the image into these two bit maps.
Chapter 9: Images and Image Management 137
. . . . * . . . . . . . . . . . . .
. . . * . * . . . . . . . x . . . .
. . * . . . * . . . . . x x x . . .
. * . . . . . * . . . x x x x x . .
* * * * * * * * * . . . . . . . . .
perimeter points interior points
The next step is to convert these two bit maps into their binary
representations. Just as there are eight bits in a byte, we will create a
data structure (an array in this case) with each byte holding eight pixels.
Bits that are set (1) indicate the corresponding pixel will appear displayed
in the color associated with that bit map. Bits that are reset (0) leave the
corresponding pixel unchanged. The size of each bit map array must be at
least 10 bytes because each bit map contains five rows with nine pixels in
each row (that is, two bytes are required for each row of the image). Hence,
when we convert these bit maps to their binary representations, and
subsequently to their hexadecimal equivalent, the results will appear as
shown below. The boldface bits represent the actual image; the other bits
are filler bits needed to complete each row of the bit maps after the ninth
pixel. All filler bits must be zero.
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 08 00
0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 14 00
0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 22 00
0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 41 00
1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 FF 80
perimeter bit map
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 00
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 08 00
0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 1C 00
0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 3E 00
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 00
interior bit map
The next question is the order in which the bit maps are stored in the
corresponding data structures. Since our data structure is an array, it is
only necessary to show the relationship of the subscripts to the bit map
structures above. The next diagram shows the subscript order for the case of
a two-column by five-row bit map.
[8] [9]
[6] [7]
[4] [5]
[2] [3]
[0] [1]
138 Fastgraph User's Guide
From this diagram, we see the first element of the array (that is, the
element with subscript [0]) represents the lower left corner of the image.
The subscript progression then continues right until reaching the end of the
first row. It then resumes at the leftmost element of the second row and
continues to the right until the end of that row. It continues in this
manner for all remaining rows.
We are now ready to present an example program to display our triangle.
The program will use the Fastgraph routine fg_drawmap, which expects three
arguments. The first argument is the bit map array (passed by reference),
the second is the width of the bit map in bytes, and the last is the height
of the bit map in pixel rows. The fg_drawmap routine displays the image such
that its lower left corner is at the graphics cursor position on the active
video page. The routine has no effect in text video modes. Additionally,
fg_drawmap displays the image using the current color index, which means we
will need to call fg_drawmap once for each color in the image.
Example 9-1 runs in any 320 by 200 color graphics mode (it could be made
to run in mode 12 too, but that would detract from the purpose of the
example). After establishing the video mode, the program uses fg_rect to
fill the entire screen with a gray rectangle (white in CGA). Next, the
program establishes (156,101) as the graphics cursor position; this causes
the triangle to be centered on the screen. The two calls to fg_drawmap, one
for each of the colors in the image, actually display the triangle. Note
especially how fg_setcolor is used before each call to fg_drawmap to define
the current color index. The result is a triangle with a blue perimeter
(cyan in CGA) and green interior (magenta in CGA).
Example 9-1.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char perimeter[] = {
0xFF,0x80,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00
};
char interior[] = {
0x00,0x00,0x3E,0x00,0x1C,0x00,0x08,0x00,0x00,0x00
};
void main()
{
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
Chapter 9: Images and Image Management 139
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_move(156,101);
fg_setcolor(1);
fg_drawmap(perimeter,2,5);
fg_setcolor(2);
fg_drawmap(interior,2,5);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
The different color bit maps used by fg_drawmap do not all have to be
the same size. In our triangle example, the perimeter is 9 pixels wide by 5
pixels high, but the interior is only 5 pixels wide by 3 pixels high. Hence,
the bit map for the interior pixels only requires one byte for each of its
three rows, so we can store it in a three-byte array. Its structure would
be:
[2] 08
[1] 1C
[0] 3E
Example 9-2 is similar to example 9-1, but it uses a three-byte array
for the interior bit map. Note the second call to fg_move in this example.
It is needed because the bottom row of the smaller interior bit map
corresponds to the second row of the larger perimeter bit map. In other
words, the interior bit map must be displayed one row above the perimeter bit
map.
Example 9-2.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char perimeter[] = {
0xFF,0x80,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00
};
char interior[] = {
0x3E,0x1C,0x08
};
void main()
{
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
140 Fastgraph User's Guide
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_move(156,101);
fg_setcolor(1);
fg_drawmap(perimeter,2,5);
fg_move(156,100);
fg_setcolor(2);
fg_drawmap(interior,1,3);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
In example 9-2, the time required to execute the second call to fg_move
may not be worth the saving of 7 bytes. When array space is critical, or
when the images are larger, the use of smaller bit maps for certain colors
may be more valuable.
Yet another possibility for example 9-2 would be to shift the elements
of the interior bit map two pixels to the left. In this way, the bit map
would be aligned against the left side of the array, just as the perimeter
bit map is. The three values comprising the interior bit map would then
become F8, 70, and 20. We also would need to change the x coordinate in the
second call to fg_move from 156 to 158.
Mode-Specific Bit-Mapped Images
This section will discuss the image display routines that use bit-mapped
image formats that are specific to each text and graphics video mode. The
different image formats closely resemble the structure of video memory in
each mode, so these routines are much faster than displaying mode-independent
bit maps with fg_drawmap. If you use the mode-specific bit maps in a program
that supports several video modes, there will be some additional programming
that is not needed when using mode-independent bit maps. Usually, however,
your efforts will be rewarded with faster graphics.
We'll demonstrate the use of mode-specific bit maps in graphics modes
with the familiar two-color triangle whose pixel representation appears
below.
. . . . * . . . .
. . . * x * . . .
. . * x x x * . .
. * x x x x x * .
* * * * * * * * *
Chapter 9: Images and Image Management 141
As before, our triangle is 9 pixels wide at its base and 5 pixels high.
The pixels indicated by an asterisk (*) are the triangle's perimeter, while
those indicated by an x represent its interior points. We need to
distinguish between these pixels because they will be different colors. The
pixels shown as periods (.) are not part of the triangle itself. They are
required to make the image rectangular, so from Fastgraph's perspective they
are indeed part of the image.
Regular Images
The Fastgraph routine fg_drwimage displays regular mode-specific bit-
mapped images (by regular, we mean an image that is neither clipped nor
rotated). Its arguments are the same as for the fg_drawmap routine, and the
bit map array's subscript order is also the same as for fg_drawmap. The
major difference is the bit map structure -- we combine the information for
all colors into a single bit map, in a way consistent with the structure and
accessibility of video memory for the various modes. As with the other image
display routines, fg_drwimage displays the image on the active video page
with its lower left corner at the graphics cursor position (or the text
cursor position for text modes). We'll now examine the use of fg_drwimage in
several video modes.
CGA four-color graphics modes
In the four-color CGA graphics modes (modes 4 and 5), each pixel can
assume a value between 0 and 3. This means it takes two bits to represent a
pixel, or put another way, each byte of video memory holds four pixels. Our
triangle image is nine pixels wide, so three bytes are needed for each row of
the image. Because the image is five pixels high, we need a bit map array of
at least 15 bytes (five rows times three bytes per row) to hold the image.
The image's binary representation and its hexadecimal equivalent for the
four-color CGA graphics modes are shown below. The binary values in boldface
represent the actual image; the others are the filler bits needed to complete
each row of the bit map after the ninth pixel. We have coded the perimeter
pixels to be color 1 (01 binary) and the interior pixels to be color 2 (10
binary). Any pixel whose value is zero (00 binary) is transparent and will
thus leave the contents of video memory at that position unchanged.
00 00 00 00 01 00 00 00 00 00 00 00 00 40 00
00 00 00 01 10 01 00 00 00 00 00 00 01 90 00
00 00 01 10 10 10 01 00 00 00 00 00 06 A4 00
00 01 10 10 10 10 10 01 00 00 00 00 1A A9 00
01 01 01 01 01 01 01 01 01 00 00 00 55 55 40
Example 9-3 uses this mode-specific bit map to display the triangle in
the standard CGA four-color graphics mode (mode 4). After establishing the
video mode, the program uses fg_rect to fill the entire screen with a white
rectangle. Next, the program establishes (156,101) as the graphics cursor
position; this causes the triangle to be centered on the screen. The call to
142 Fastgraph User's Guide
fg_drwimage produces a triangle with a cyan perimeter (color 1) and a magenta
interior (color 2).
Example 9-3.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char triangle[] = {
0x55,0x55,0x40, 0x1A,0xA9,0x00, 0x06,0xA4,0x00,
0x01,0x90,0x00, 0x00,0x40,0x00
};
void main()
{
int old_mode;
if (fg_testmode(4,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 CGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(4);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_move(156,101);
fg_drwimage(triangle,3,5);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
CGA two-color graphics mode
In the two-color CGA graphics mode (mode 6), each pixel can assume the
values 0 or 1. This means it takes just one bit to represent a pixel, so
each byte of video memory holds eight pixels. Our triangle image is nine
pixels wide, so two bytes are needed for each row of the image. Because the
image is five pixels high, we need a bit map array of at least 10 bytes (five
rows times two bytes per row) to hold the image.
The image's binary representation and its hexadecimal equivalent for the
two-color CGA graphics mode is shown below. The binary values in boldface
represent the actual image; the others are the filler bits needed to complete
each row of the bit map after the ninth pixel. We have coded both the
perimeter pixels and the interior pixels to be color 1. Any pixel whose
value is zero is transparent and will thus leave the contents of video memory
at that position unchanged.
Chapter 9: Images and Image Management 143
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 08 00
0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 1C 00
0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 3E 00
0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 7F 00
1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 FF 80
Example 9-4 uses this mode-specific bit map to display the triangle in
the CGA two-color graphics mode (mode 6). After establishing the video mode,
the program establishes (316,101) as the graphics cursor position; this
causes the triangle to be centered on the screen. The call to fg_drwimage
produces a solid triangle.
Example 9-4.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char triangle[] = {
0xFF,0x80, 0x7F,0x00, 0x3E,0x00,
0x1C,0x00, 0x08,0x00
};
void main()
{
int old_mode;
if (fg_testmode(6,1) == 0) {
printf("This program requires a ");
printf("CGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(6);
fg_move(316,101);
fg_drwimage(triangle,2,5);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Tandy/PCjr 16-color graphics mode
The structure of the mode-specific bit maps for the Tandy/PCjr 16-color
graphics mode (mode 9) is the same as the mode-specific bit map structure for
the native EGA and VGA graphics modes. Please refer to page 144 for a
discussion of EGA and VGA bit maps.
144 Fastgraph User's Guide
Hercules graphics modes
The structure of the mode-specific bit maps for the Hercules graphics
modes (modes 11 and 12) is the same as two of the CGA graphics modes. For
the standard Hercules graphics mode (mode 11), please refer to the discussion
of CGA two-color (mode 6) bit maps on page 142. For the low-resolution
Hercules graphics mode (mode 12), please refer to the discussion of the CGA
four-color (mode 4) bit maps on page 141.
EGA and VGA graphics modes
In the native EGA and VGA graphics modes (modes 13 through 18), each
pixel can assume a value between 0 and 15. This means it takes four bits to
represent a pixel, so each byte of the bit map holds two pixels. Our
triangle image is nine pixels wide, so five bytes are needed for each row of
the image. Because the image is five pixels high, we need a bit map array of
at least 25 bytes (five rows times five bytes per row) to hold the image.
In these modes, it is easy to develop the hexadecimal representation of
a bit map without first producing its binary equivalent. This is because a
pixel value and a hexadecimal digit each occupy four bits. The triangle's
hexadecimal representation for the native EGA and VGA modes is shown below.
The pixels in boldface represent the actual image; the others are the filler
values needed to complete each row of the bit map after the ninth pixel. We
have chosen to display the perimeter pixels in color 1 and the interior
pixels in color 2. Any pixel whose value is zero is transparent and will
thus leave the contents of video memory at that position unchanged.
00 00 10 00 00
00 01 21 00 00
00 12 22 10 00
01 22 22 21 00
11 11 11 11 10
Example 9-5 is similar to example 9-3, but it uses the 320 x 200 EGA
graphics mode (mode 13) and the mode-specific bit map just constructed to
display the triangle. The call to fg_drwimage produces a triangle with a
blue perimeter (color 1) and a green interior (color 2).
Example 9-5.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char triangle[] = {
0x11,0x11,0x11,0x11,0x10,
0x01,0x22,0x22,0x21,0x00,
0x00,0x12,0x22,0x10,0x00,
0x00,0x01,0x21,0x00,0x00,
0x00,0x00,0x10,0x00,0x00
};
Chapter 9: Images and Image Management 145
void main()
{
int old_mode;
if (fg_testmode(13,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 EGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(13);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_move(156,101);
fg_drwimage(triangle,5,5);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
MCGA and VGA 256-color graphics modes
In the MCGA and VGA 256-color graphics modes (modes 19 through 23), each
pixel can assume a value between 0 and 255 (FF hex). This means it takes
eight bits to represent a pixel, or each byte of video memory holds one
pixel. Our triangle image is nine pixels wide, so nine bytes are needed for
each row of the image. Because the image is five pixels high, we need a bit
map array of at least 45 bytes (five rows times nine bytes per row) to hold
the image. Note we will never need any filler bits in the 256-color video
modes.
In the 256-color graphics video modes, it is simple to develop the bit
map for an image because each byte holds exactly one pixel. The triangle's
hexadecimal representation for the 256-color graphics modes is shown below.
As before, we have coded the perimeter pixels to be color 1 (01 hex) and the
interior pixels to be color 2 (02 hex). Any pixel whose value is zero is
transparent and will thus leave the contents of video memory at that position
unchanged.
00 00 00 00 01 00 00 00 00
00 00 00 01 02 01 00 00 00
00 00 01 02 02 02 01 00 00
00 01 02 02 02 02 02 01 00
01 01 01 01 01 01 01 01 01
146 Fastgraph User's Guide
Example 9-6 is also similar to example 9-3, but it uses the MCGA 256-
color graphics mode (mode 19) and the mode-specific bit map just constructed
to display the triangle. The call to fg_drwimage produces a triangle with a
blue perimeter (color 1) and a green interior (color 2).
Example 9-6.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char triangle[] = {
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x00,0x01,0x02,0x02,0x02,0x02,0x02,0x01,0x00,
0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00,
0x00,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00
};
void main()
{
int old_mode;
if (fg_testmode(19,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 MCGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(19);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_move(156,101);
fg_drwimage(triangle,9,5);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Text Modes
You also can use the fg_drwimage routine to display images in text video
modes (modes 0, 1, 2, 3, and 7). As one might expect, the image structure in
the text modes is rather different from the graphics modes. In Chapter 5 we
saw that each character cell on the screen actually consists of a character
and an attribute. The character value determines what character is
displayed, while the attribute value controls the character's appearance.
The structure of the attribute is:
Chapter 9: Images and Image Management 147
bits attribute
0-3 foreground color
4-6 background color
7 blinking
The text mode image structure used with fg_drwimage also consists of a
series of characters and attributes. For example, the following diagram
illustrates the structure of an image that is three characters wide and two
characters high.
char attr char attr char attr
char attr char attr char attr
To illustrate the use of fg_drwimage in a text video mode, we'll display
the phrase "hello there" on two different lines in the center of the screen.
Furthermore, let's assume we would like the first character of each word to
appear in foreground color 1, the second in color 2, and so forth. Our image
will consist of two lines each containing five characters, and each character
requires two bytes of storage (one for the character and another for its
attribute), so we'll need a 20-byte array for holding the image. The array
really doesn't hold a bit map as in the graphics modes, so in the text modes
the first argument passed to fg_drwimage is instead called the image array.
In our example, the structure of the image array is:
'h' 1 'e' 2 'l' 3 'l' 4 'o' 5
't' 1 'h' 2 'e' 3 'r' 4 'e' 5
The subscript order that fg_drwimage uses for text modes is the same as for
the graphics modes. For our five-row by two-column image, this means the
array subscripts would be numbered as follows:
[10] [11] [12] [13] [14] [15] [16] [17] [18] [19]
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
Depending on the character and attribute values in the image array,
fg_drwimage can display new characters and attributes, new characters leaving
the existing attribute unchanged, new attributes leaving the existing
character unchanged, or leave both the existing character and attribute
unchanged in video memory. To keep an existing character or attribute,
simply specify a value of 0 in the corresponding element of the image array.
This capability is analogous to the fact that zero-valued pixels in graphics
mode bit maps leave video memory unchanged.
148 Fastgraph User's Guide
Example 9-7 demonstrates the use of the fg_drwimage routine in the 80-
column color text mode (mode 3). After establishing the video mode and
making the cursor invisible, the program calls fg_drwimage to display the
"hello there" image just discussed (note we pass the dimensions of the image
array as the number of bytes, not the number of characters). The program
waits for a keystroke and then calls fg_drwimage again, passing a different
image array (called "image") of the same size. This array changes the first
letter of both words from lower case to upper case (leaving the attribute
unchanged), and it makes the remaining characters have the same attribute as
the first character. This is done in part by using zero-valued characters
and attributes to leave video memory unchanged. After waiting for another
keystroke, the program exits.
Example 9-7.
#include <fastgraf.h>
void main(void);
char hello[] = {
't',1, 'h',2, 'e',3, 'r',4, 'e',5,
'h',1, 'e',2, 'l',3, 'l',4, 'o',5
};
char image[] = {
'T',0, 0,1, 0,1, 0,1, 0,1,
'H',0, 0,1, 0,1, 0,1, 0,1
};
void main()
{
int old_mode;
old_mode = fg_getmode();
fg_setmode(3);
fg_cursor(0);
fg_locate(12,37);
fg_drwimage(hello,10,2);
fg_waitkey();
fg_drwimage(image,10,2);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Clipped Images
The fg_drwimage routine displays an image without regard to the current
clipping limits. If you want the image to be displayed with respect to the
clipping limits (as established by the most recent call to fg_setclip), you
should use the fg_clpimage routine instead of fg_drwimage. Fg_clpimage takes
the same three arguments as fg_drwimage, and also displays the image such
that its lower left corner is at the graphics cursor position. Unlike
fg_drwimage, the fg_clpimage routine has no effect when used in a text video
Chapter 9: Images and Image Management 149
mode. Refer to pages 149 and 151 for example programs that use fg_clpimage.
Because of the additional overhead involved in checking the clipping limits,
fg_clpimage is not as fast as fg_drwimage.
Reversed Images
The fg_revimage routine displays an image reversed (that is, mirrored
about the y-axis). Fg_revimage takes the same three arguments as
fg_drwimage, and also displays the image such that its lower left corner is
at the graphics cursor position. The fg_revimage routine has no effect when
used in a text video mode. Refer to pages 150 and 151 for example programs
that use fg_revimage.
Reversed Clipped Images
The fg_flpimage routine combines the effects of the fg_revimage and
fg_clpimage routines -- it displays a reversed image with respect to the
current clipping limits. Fg_flpimage takes the same three arguments as
fg_drwimage, and also displays the image such that its lower left corner is
at the graphics cursor position. Like the fg_clpimage routine, fg_flpimage
has no effect when used in a text video mode. Refer to pages 149 and 151 for
example programs that use fg_flpimage.
Some Examples
Example 9-8 illustrates the use of the fg_drwimage, fg_clpimage,
fg_revimage, and fg_flpimage routines in the standard CGA four-color graphics
mode (mode 4). The program uses each of these routines to display a small
white arrow, as shown in the pixel map below.
. . . . . . * . . .
. . . . . . * * . .
* * * * * * * * * .
* * * * * * * * * *
* * * * * * * * * .
. . . . . . * * . .
. . . . . . * . . .
As before, we must first convert this image to a bit map. The image is ten
pixels wide and seven high. In mode 4, each pixel occupies two bits, so we
need a 21-byte array (7 rows by 3 columns) to store the image. Since we want
to make the arrow white, each pixel will be displayed in color 3 (11 binary).
Here is the bit map and its hexadecimal equivalent for the arrow image in
mode 4 (the actual image is in boldface).
00 00 00 00 00 00 11 00 00 00 00 00 00 0C 00
00 00 00 00 00 00 11 11 00 00 00 00 00 0F 00
11 11 11 11 11 11 11 11 11 00 00 00 FF FF C0
11 11 11 11 11 11 11 11 11 11 00 00 FF FF F0
11 11 11 11 11 11 11 11 11 00 00 00 FF FF C0
00 00 00 00 00 00 11 11 00 00 00 00 00 0F 00
00 00 00 00 00 00 11 00 00 00 00 00 00 0C 00
150 Fastgraph User's Guide
After establishing the video mode, the program defines the clipping
region. It then uses fg_drwimage to display the arrow pointing to the right
and fg_clpimage to do the same thing, but with respect to the clipping
limits. Because the left edge of the arrow is displayed at x=10 and the
right clipping limit is at x=15, the call to fg_clpimage only draws the first
six columns of the arrow (that is, it does not draw the arrow head).
Next, example 9-8 uses fg_revimage to display the arrow pointing to the
left. To allow for the filler pixels, we must establish the graphics cursor
position two pixels to the left of the position used by fg_drwimage if we
want the tip of the left-pointing arrow to align with the tail of the right-
pointing arrow. Finally, the program uses fg_flpimage to display an arrow
pointing to the left with regard to the clipping limits. The call to
fg_flpimage displays the arrow head and the first two columns of the arrow
shaft.
Example 9-8.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char arrow[] = {
0x00,0x0C,0x00, 0x00,0x0F,0x00, 0xFF,0xFF,0xC0,
0xFF,0xFF,0xF0, 0xFF,0xFF,0xC0, 0x00,0x0F,0x00,
0x00,0x0C,0x00
};
void main()
{
int old_mode;
if (fg_testmode(4,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 CGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(4);
fg_setclip(0,15,0,199);
fg_move(10,10);
fg_drwimage(arrow,3,7);
fg_move(10,20);
fg_clpimage(arrow,3,7);
fg_move(8,30);
fg_revimage(arrow,3,7);
fg_move(8,40);
fg_flpimage(arrow,3,7);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Chapter 9: Images and Image Management 151
Example 9-9 is the same as example 9-8, but it uses the low resolution
EGA graphics mode (mode 13). If we changed the mode number specified in the
calls to fg_testmode and fg_setmode, the program also would run in any native
EGA or VGA graphics mode, or in the Tandy/PCjr 16-color graphics mode. In
these modes, we store two pixels per byte in the bit map array, so we need a
35-byte array (7 rows by 5 columns) to store the image. Here is the bit
map's hexadecimal equivalent for the arrow image in mode 13, followed by the
program to display it.
00 00 00 F0 00
00 00 00 FF 00
FF FF FF FF F0
FF FF FF FF FF
FF FF FF FF F0
00 00 00 FF 00
00 00 00 F0 00
Example 9-9.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char arrow[] = {
0x00,0x00,0x00,0xF0,0x00,
0x00,0x00,0x00,0xFF,0x00,
0xFF,0xFF,0xFF,0xFF,0xF0,
0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xF0,
0x00,0x00,0x00,0xFF,0x00,
0x00,0x00,0x00,0xF0,0x00
};
void main()
{
int old_mode;
if (fg_testmode(13,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 EGA graphics mode.\n");
exit(1);
}
152 Fastgraph User's Guide
old_mode = fg_getmode();
fg_setmode(13);
fg_setclip(0,15,0,199);
fg_move(10,10);
fg_drwimage(arrow,5,7);
fg_move(10,20);
fg_clpimage(arrow,5,7);
fg_move(8,30);
fg_revimage(arrow,5,7);
fg_move(8,40);
fg_flpimage(arrow,5,7);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Pixel Run Maps
The bit maps used with the fg_drawmap, fg_drwimage, and related routines
can consume array space quite rapidly. This is especially true if the image
is large or contains many colors. For example, a mode-independent bit-mapped
image that occupies the entire screen in a 320 by 200 graphics mode requires
8,000 bytes of space per color. Fastgraph provides another mode-independent
image format called pixel run maps, which are more efficient in terms of
space. In pixel run maps, you store the entire image in a single array.
Pixel run maps are particularly useful for displaying static images such as
backgrounds.
Let's return to our familiar triangle example and show how we could use
a pixel run map to display it.
. . . . * . . . .
. . . * x * . . .
. . * x x x * . .
. * x x x x x * .
* * * * * * * * *
As before, the pixels indicated by an asterisk (*) are the triangle's
perimeter, while those indicated by an x represent its interior points. The
pixels shown as periods (.) are not part of the triangle itself, but they are
part of the pixel run map.
If we start at the lower left corner of the image and proceed to the
right, we could represent the first row of the image as nine pixels of color
"asterisk". Such a group of consecutive identically colored pixels is called
a pixel run, so a single pixel run describes the first row of the image. The
row above this one is a bit more complex. It consists of five pixel runs:
one pixel of color "period", followed by one of color "asterisk", then five
of color "x", one of color "asterisk", and finally one of color "period".
While we could construct separate pixel runs for each row of the image,
notice that three of the five rows in our triangle begin with the same color
pixel as the rightmost pixel in the previous row. Fastgraph's pixel run map
format lets you take advantage of this property by allowing pixel runs to
Chapter 9: Images and Image Management 153
wrap from one row to the next. This means we can represent the pixel run of
color "period" extending from the right side of the second row to the left
side of the third row as a single run of three pixels.
The Fastgraph routine fg_display displays an image stored as a pixel run
map. The fg_display routine expects three arguments. The first is an array
containing the pixel runs (passed by reference), the second is the number of
pixel runs in the array, and the third is the width in pixels of the image.
As with the other image display routines, the fg_display routine displays the
image such that its lower left corner is at the graphics cursor position on
the active video page. The pixel run array is of the following format:
[0] color for run 1
[1] count for run 1
[2] color for run 2
[3] count for run 2
.
.
.
[2n-2] color for run n
[2n-1] count for run n
Each color is a value between 0 and 255 specifying the color index for that
pixel run. Each count is a value between 0 and 255 specifying the length in
pixels of that pixel run. If a run is longer than 255 pixels, it must be
broken into two or more runs. For example, we could represent a pixel run of
length 265 as a run of length 255 followed by a run of length 10 of the same
color. Note also the array space in bytes needed to store a pixel run map is
twice the number of runs.
It requires 16 pixel runs to store our triangle image as a pixel run
map. If we want to display the perimeter pixels in color 1, the interior
pixels in color 2, and the filler area in color 7, the pixel run map would
contain 16 sets of (color,count) pairs: (1,9), (7,1), (1,1), (2,5), (1,1),
(7,3), (1,1), (2,3), (1,1), (7,5), (1,1), (2,1), (1,1), (7,7), (1,1), and
(7,4).
Example 9-10 uses the fg_display routine to display the triangle as a
pixel run map in a 320 by 200 graphics mode. The program displays the
triangle against a background of color 7, so the selection of color 7 for the
filler area was important. If some other color were chosen, the filler area
would not blend in with the background.
Example 9-10.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
154 Fastgraph User's Guide
char triangle[] = {
1,9, 7,1, 1,1, 2,5, 1,1, 7,3, 1,1, 2,3,
1,1, 7,5, 1,1, 2,1, 1,1, 7,7, 1,1, 7,4
};
void main()
{
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_move(156,101);
fg_display(triangle,16,9);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
If you have a pixel run map that only uses the first 16 color indices (0
to 15), you can use Fastgraph's packed pixel run map image format. This
format packs two color values into each color byte and thus needs 25% less
array space to store an image. The Fastgraph routine fg_displayp displays an
image stored as a packed pixel run map. It is the same as the fg_display
routine except for the structure of the pixel run array. Like fg_display,
the pixel run array used with fg_displayp is a list of pixel runs, but two
runs are packed into three bytes. In each such set of three bytes, the high
four bits of the first byte contain the color of the first run, and the low
four bits contain the color of the second run. The second byte contains the
length of the first run, and the third byte contains the length of the second
run.
The following diagram illustrates the format of the pixel run array used
with the fg_displayp routine. The image is assumed to contain n pixel runs,
where n is an even number. If n is odd, the index of the last element is
3n/2 (truncated) instead of 3n/2-1, and the low four bits of the last color
byte (that is, the color for pixel run n+1) are ignored.
7 4 3 0
[0] color for run 1 color for run 2
[1] count for run 1
[2] count for run 2
Chapter 9: Images and Image Management 155
[3] color for run 3 color for run 4
[4] count for run 3
[5] count for run 4
.
.
.
[3n/2-3] color for run n-1 color for run n
[3n/2-2] count for run n-1
[3n/2-1] count for run n
The structure of the packed pixel run array allows for color values to
be between 0 and 15, and pixel run lengths to be between 0 and 255. The
array space in bytes needed to store a packed pixel run map is 1.5 times the
number of runs, compared to twice the number of runs for the standard pixel
run format.
Example 9-11 is the same as example 9-10, but it uses fg_displayp rather
than fg_display to display the image. Note the use of hexadecimal numbers
for defining the packed color values, which of course is not necessary but
certainly easier to read than expressing the quantities as decimal numbers.
Example 9-11.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char triangle[] = {
0x17,9,1, 0x12,1,5, 0x17,1,3, 0x12,1,3,
0x17,1,5, 0x12,1,1, 0x17,1,7, 0x17,1,4
};
void main()
{
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_move(156,101);
156 Fastgraph User's Guide
fg_displayp(triangle,16,9);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Both the fg_display and fg_displayp routines require the pixel run image
to be stored in an array. In examples 9-10 and 9-11, the image is defined
within the program itself. However, if the image is stored in a file, it
must first be read into the pixel run array. Example 9-12 demonstrates this
procedure. The program displays two images stored in files, one in standard
pixel run format and the other in packed pixel run format. Each image is a
picture of the sea floor and some coral, as might be used for the background
in an aquarium. The program runs in a 320 by 200 graphics mode, and the
image fills the entire screen. It is assumed the image files contain the
list of pixel runs as a single byte stream that does not include embedded
characters such as carriage returns or line feeds.
The first image, in standard pixel run format, is in the file coral.spr.
Note the program must open the file for reading in binary mode ("rb" in the
call to fopen). The program reads the file's entire contents into the
pixel_runs array, whose size must be at least as large as the file size.
Because the image is stored in standard pixel run format, the number of pixel
runs is one-half the file size. The program then uses the fg_move routine to
establish the lower left corner of the screen as the graphics cursor position
and then calls fg_display to display the image. As mentioned earlier, the
image fills the entire screen, so its width is 320 pixels.
After waiting for a keystroke, the program similarly displays the second
image. This image is in the file coral.ppr and is stored in packed pixel run
format. Because the image is packed, the number of pixel runs is two-thirds
the file size. The program then clears the previous image from the screen
and calls fg_displayp to display the image. After another keystroke, the
program restores the original video mode and screen attributes and returns to
DOS.
Example 9-12.
#include <fastgraf.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char pixel_runs[20000];
void main()
{
long filelength();
FILE *stream;
int file_size, run_count;
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
Chapter 9: Images and Image Management 157
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
stream = fopen("coral.spr","rb");
file_size = (int)(filelength(fileno(stream)));
fread(pixel_runs,sizeof(char),file_size,stream);
fclose(stream);
run_count = file_size / 2;
fg_move(0,199);
fg_display(pixel_runs,run_count,320);
fg_waitkey();
stream = fopen("coral.ppr","rb");
file_size = (int)(filelength(fileno(stream)));
fread(pixel_runs,sizeof(char),file_size,stream);
fclose(stream);
run_count = file_size / 3 * 2;
fg_erase();
fg_displayp(pixel_runs,run_count,320);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Another Fastgraph routine, fg_dispfile, displays an image directly from
a file. This eliminates the need to read the file contents into an array
before displaying the image, and it also eliminates the need to compute the
number of pixel runs in the image. The fg_dispfile routine can display
images stored in either standard or packed pixel run images. The first of
its three arguments is the name of the file containing the image (it may
include a path name). The file name must be terminated with a null
character, so QuickBASIC, FORTRAN, and Turbo Pascal programmers will need to
store a zero byte as the last character of the file name string. The second
argument is the width in pixels of the image, and the third argument defines
the image format (that is, standard or packed). As with fg_display and
fg_displayp, the fg_dispfile routine displays the image such that its lower
left corner is at the graphics cursor position.
Example 9-13 illustrates how to use the fg_dispfile routine to display
an image stored in a pixel run file. It is functionally identical to example
9-12, but it is much simpler because it uses fg_dispfile instead of fg_display
and fg_displayp to display the images. The value of fg_dispfile's third
argument tells Fastgraph the image format. A value of 0 indicates the file
contains an image in standard pixel run format, while a value of 1 indicates
an image in packed pixel run format. As in example 9-12, the image files are
assumed to contain the list of pixel runs as a single byte stream that does
not include embedded characters such as carriage returns or line feeds.
Example 9-13.
#include <fastgraf.h>
158 Fastgraph User's Guide
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_move(0,199);
fg_dispfile("coral.spr",320,0);
fg_waitkey();
fg_erase();
fg_dispfile("coral.ppr",320,1);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
To display the image, the fg_dispfile routine tries to allocate enough
dynamic memory to read the entire file. If it is unable to do so, it
allocates the available memory and displays the image in more than one pass.
In either case, Fastgraph deallocates the memory after fg_dispfile displays
the image.
The SNAPSHOT utility distributed with Fastgraph is a terminate and stay
resident program (TSR) that can capture graphics mode screen images and save
them in standard pixel run files. Thus, you can easily create files with
SNAPSHOT and display them with the fg_dispfile routine. Another TSR utility,
GrabRGB, is useful for capturing RGB color values from 256-color images.
Appendix A contains complete descriptions of the SNAPSHOT and GrabRGB
utilities.
Display Patterns
Examples 9-11, 9-12, and 9-13 work well in the graphics video modes with
16 or 256 available colors. However, in the four-color CGA graphics modes
the resulting image is not too good because of our limited color choices, and
it would look even worse in the Hercules graphics mode. The Fastgraph
routine fg_pattern allows you to associate a dither pattern (actually, any
pixel sequence) with one of Fastgraph's 256 color indices appearing in a
pixel run map. When displaying a pixel run map (with fg_display,
fg_displayp, or fg_dispfile), Fastgraph will use the pattern associated with
that color index instead of displaying the color itself.
Chapter 9: Images and Image Management 159
The fg_pattern routine requires two integer arguments -- a color index
(between 0 and 255) and the display pattern defined for that color index. A
display pattern's structure resembles the structure of video memory and is
thus dependent on the current video mode. The following sections list the
initial display patterns and explain how to construct new display patterns
for different graphics video modes.
CGA four-color graphics modes
In the four-color CGA graphics modes (modes 4 and 5), the display
pattern is a 16-bit quantity consisting of an 8-bit shift count followed by
an 8-bit pixel pattern. Each pixel assumes a value between 0 and 3, so the
pattern represents four pixels. In even-numbered pixel rows, Fastgraph uses
the pixel pattern itself. In odd-numbered pixel rows, Fastgraph rotates the
original pattern to the left by the number of bits specified by the shift
count.
For example, if we are using the default CGA color palette, we could
create a lighter shade of cyan by alternating cyan pixels (color 1, 01
binary) with white pixels (color 3, 11 binary), as shown below.
01 11 01 11
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 77.
To complete the display pattern, we need to determine the shift count.
If we use a shift count of zero, the resulting display will simply be a
series of cyan and white vertical lines. What we really need is a
checkerboard effect where a white pixel is above and below each cyan pixel,
and vice versa. If we rotate the pattern one pixel (two bits) to the left,
we will achieve the desired effect. That is, a shift count of two produces
the following pixel patterns:
even-numbered rows 01 11 01 11
odd-numbered rows 11 01 11 01
Combining the shift count with the pixel pattern yields the display pattern
0277 hex. The shift count is normally a multiple of two; note that a zero
shift count results in the same pattern being applied to all pixel rows.
For the CGA four-color graphics modes, the fg_setmode routine
establishes the following initial display patterns:
color shift count hexadecimal
index and pattern equivalent
0 0 00000000 0000
1 0 01010101 0055
2 0 10101010 00AA
3 0 11111111 00FF
160 Fastgraph User's Guide
These values are repeated as necessary to define color indices 4 to 255.
That is, colors 4, 8, 12, ... , 252 use the same defaults as color 0. Colors
5, 9, 13, ... , 253 use the same defaults as color 1, and so forth. Also
note that pattern 0000 represents four pixels of color 0, 0055 represents
four pixels of color 1, 00AA represents four pixels of color 2, and 00FF
represents four pixels of color 3.
CGA two-color graphics mode
In the two-color CGA graphics mode (mode 6), the display pattern is also
a 16-bit quantity consisting of an 8-bit shift count followed by an 8-bit
pixel pattern. Each pixel assumes the value 0 or 1, so the pattern
represents eight pixels. In even-numbered pixel rows, Fastgraph uses the
pixel pattern itself. In odd-numbered pixel rows, Fastgraph rotates the
original pattern to the left by the number of bits specified by the shift
count.
For example, we could create a lighter shade of white by alternating
black pixels (color 0) with white pixels (color 1), as shown below.
0 1 0 1 0 1 0 1
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 55.
To complete the display pattern, we need to determine the shift count.
We must rotate the pattern one pixel (one bit) to the left to achieve the
checkerboard effect as in the CGA four color graphics modes. That is, a
shift count of one produces the following pixel patterns:
even-numbered rows 0 1 0 1 0 1 0 1
odd-numbered rows 1 0 1 0 1 0 1 0
Combining the shift count with the pixel pattern yields the display pattern
0155 hex.
For the CGA two-color graphics mode, the fg_setmode routine establishes
the initial display patterns such that all even-numbered color indices are
assigned the value 0000, while all odd-numbered color indices are assigned
the value 00FF. Note that pattern 0000 represents eight pixels of color 0,
and 00FF represents eight pixels of color 1.
Tandy/PCjr 16-color graphics mode
In the Tandy/PCjr 16-color graphics mode (mode 9), the display pattern
is also 16-bit quantity consisting of an 8-bit shift count followed by an 8-
bit pixel pattern. Each pixel assumes a value between 0 and 15, so the
pattern represents two pixels. In even-numbered pixel rows, Fastgraph uses
the pixel pattern itself. In odd-numbered pixel rows, Fastgraph rotates the
original pattern to the left by the number of bits specified by the shift
count.
For example, we could create a lighter shade of blue by alternating blue
pixels (color 1, 0001 binary) with white pixels (color 15, 1111 binary), as
shown below.
Chapter 9: Images and Image Management 161
0001 1111
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 1F.
To complete the display pattern, we need to determine the shift count.
Using the same process as in the CGA graphics modes, we must rotate the
pattern one pixel (four bits) to the left to achieve the checkerboard effect.
That is, a shift count of four produces the following pixel patterns:
even-numbered rows 0001 1111
odd-numbered rows 1111 0001
Combining the shift count with the pixel pattern yields the display pattern
041F hex. The shift count is normally zero or four; note that a zero shift
count results in the same pattern being applied to all pixel rows.
For the Tandy/PCjr 16-color graphics modes, the fg_setmode routine
establishes the initial display patterns such that color 0 is assigned the
value 0000 (two pixels of color 0), color 1 is assigned the value 0011 (two
pixels of color 1), color 2 is assigned the value 0022 (two pixels of color
2), and so forth. These values are repeated as necessary to define color
indices 16 to 255. That is, colors 0, 16, 32, ... , 240 use the same
defaults as color 0. Colors 1, 17, 33, ... , 241 use the same defaults as
color 1, and so forth.
Hercules graphics modes
The structure of the display patterns for the Hercules graphics modes
(modes 11 and 12) is the same as two of the CGA graphics modes. For the
standard Hercules graphics mode (mode 11), please refer to the discussion of
CGA two-color (mode 6) display patterns on page 160. For the low-resolution
Hercules graphics mode (mode 12), please refer to the discussion of the CGA
four-color (mode 4) display patterns on page 159.
EGA graphics modes
In the EGA graphics modes (modes 13 to 16), the display pattern is an 8-
bit quantity consisting of two 4-bit color values (for consistency with the
other video modes, we still pass the display pattern as a 16-bit quantity).
Each pixel assumes a value between 0 and 15 (0 and 5 in the EGA monochrome
graphics mode), so the pattern represents two pixels. In even-numbered pixel
rows, Fastgraph uses the pixel pattern itself. In odd-numbered pixel rows,
Fastgraph rotates the original pattern one pixel (four bits) to the left.
For example, we could create a lighter shade of blue by alternating blue
pixels (color 1, 0001 binary) with white pixels (color 15, 1111 binary), as
shown below.
0001 1111
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 1F. The implied four-bit shift count produces the following pixel
patterns:
162 Fastgraph User's Guide
even-numbered rows 0001 1111
odd-numbered rows 1111 0001
Extending the pixel pattern to a 16-bit quantify yields the display pattern
001F hex.
For the EGA and VGA 16-color graphics modes, the fg_setmode routine
establishes the initial display patterns such that color 0 is assigned the
value 0000 (two pixels of color 0), color 1 is assigned the value 0011 (two
pixels of color 1), color 2 is assigned the value 0022 (two pixels of color
2), and so forth. These values are repeated as necessary to define color
indices 16 to 255. That is, colors 0, 16, 32, ... , 240 use the same
defaults as color 0. Colors 1, 17, 33, ... , 241 use the same defaults as
color 1, and so forth.
MCGA/VGA 2-color graphics mode
In the two-color MCGA/VGA graphics mode (mode 17), the display pattern
is a 2-bit quantity consisting of two 1-bit color values (for consistency
with the other video modes, we still pass the display pattern as a 16-bit
quantity). Each pixel assumes the value 0 or 1, so the pattern represents
two pixels. In even-numbered pixel rows, Fastgraph uses the pixel pattern
itself. In odd-numbered pixel rows, Fastgraph rotates the original pattern
one pixel (one bit) to the left.
For example, we could create a lighter shade of white by alternating
black pixels (color 0) with white pixels (color 1), as shown below.
0 1
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 01. The implied one-bit shift count produces the following pixel
patterns:
even-numbered rows 0 1
odd-numbered rows 1 0
Extending the pixel pattern to a 16-bit quantity yields the display pattern
0001 hex.
For the MCGA/VGA two-color graphics mode, the fg_setmode routine
establishes the initial display patterns such that all even-numbered color
indices are assigned the value 0000 (two pixels of color 0), while all odd-
numbered color indices are assigned the value 0003 (11 binary, or two pixels
of color 1).
VGA 16-color graphics mode
The structure of the display patterns for the VGA 16-color graphics mode
(mode 18) is the same as that of the EGA graphics modes. A discussion of EGA
display patterns appears on page 161.
Chapter 9: Images and Image Management 163
MCGA and VGA 256-color graphics modes
The MCGA and VGA 256-color graphics modes (modes 19 through 23) offer
262,144 different colors, so dithering is seldom (if ever) required. For
this reason, the fg_pattern routine has no effect in these video modes.
An example
Example 9-14 illustrates the use of display patterns in several graphics
modes. This program runs in any 320 by 200 color graphics mode and displays
the coral image in packed pixel run format, as in example 9-13, but it
redefines one or more of the color indices. If the program runs in the
standard CGA four-color mode (mode 4), it redefines the first 16 display
patterns using the fg_pattern routine and the values in the CGApatterns
array. In the Tandy/PCjr 16-color graphics mode (mode 9) and the EGA low-
resolution graphics mode (mode 13), the program redefines color index 15 to
produce an alternating gray and bright white dither pattern. In the MCGA
256-color mode (mode 19), display patterns are not available, so the program
uses fg_setrgb to define color index 15 as slightly darker shade of gray than
the default for color 7.
Example 9-14.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
int CGApatterns[] = {
0x0000,0x00FF,0x00FF,0x00FF,
0x02BB,0x0000,0x0222,0x0255,
0x00FF,0x00FF,0x00FF,0x0055,
0x00AA,0x00AA,0x00FF,0x0277
};
void main()
{
int color;
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
if (new_mode == 4) {
fg_palette(0,0);
for (color = 0; color < 16; color++)
fg_pattern(color,CGApatterns[color]);
}
else if (new_mode == 9 || new_mode == 13)
164 Fastgraph User's Guide
fg_pattern(15,0x04F7);
else
fg_setrgb(15,38,38,38);
fg_move(0,199);
fg_dispfile("coral.ppr",320,1);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
PCX Images
The PCX file format was originally developed by ZSoft Corporation for
their commercial paint program, PC Paintbrush. It has evolved into one of
the more popular image file formats because so many products can read PCX
files to at least some extent. Fastgraph includes routines for displaying
and creating PCX files.
The fg_disppcx routine displays an image stored in a PCX file. It
positions the image such that its upper left corner is at the graphics cursor
position on the active video page. The first argument to fg_disppcx is the
name of the PCX file (it may include a path name), and its second argument is
a 16-bit mask that controls how the image is displayed. The file name must
be terminated with a null character, so QuickBASIC, FORTRAN, and Turbo Pascal
programmers will need to store a zero byte as the last character of the file
name string. In the current version of Fastgraph, only the low-order bit
(bit 0) of the bit mask argument is meaningful. If the bit is set,
fg_disppcx will use the current palette settings. If it is zero, fg_disppcx
will use the palette values stored in the PCX file. All other bits are
reserved and should be zero. The fg_disppcx routine returns a value of 0 if
successful, 1 if the specified file wasn't found, and 2 if the file is not a
PCX file.
The fg_makepcx routine creates a PCX file from the specified rectangular
region of the active video page. Its first four arguments define the minimum
x, maximum x, minimum y, and maximum y screen space coordinates of the region
(the minimum x coordinate is reduced to a byte boundary if necessary). Its
fifth argument is the name of the PCX file to create (it may include a path
name). As with fg_disppcx, the file name must be terminated with a null
character. If an identically named file exists, it is overwritten. The
fg_makepcx routine returns a value of 0 if successful, and 1 if the PCX file
was not created.
Example 9-15 uses the fg_disppcx and fg_makepcx routines to create a new
PCX file from selected rows of an existing 256-color 320 x 200 PCX file. As
written, the program uses the file CORAL.PCX to create NEW.PCX, but it could
easily be extended to work with any PCX files. The call to fg_disppcx
displays the contents of CORAL.PCX using the palette settings defined in the
PCX file. After waiting for a keystroke, the program calls fg_makepcx to
create a PCX file named NEW.PCX from pixel rows 80 through 99 of the original
image. In case the program encounters any problems, it prints an error
message before exiting.
Chapter 9: Images and Image Management 165
Example 9-15.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int old_mode;
int read_status, write_status;
if (fg_testmode(19,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 MCGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(19);
read_status = fg_disppcx("coral.pcx",0);
fg_waitkey();
if (read_status == 0)
write_status = fg_makepcx(0,319,80,99,"new.pcx");
else
write_status = 1;
fg_setmode(old_mode);
fg_reset();
if (read_status == 1)
printf("CORAL.PCX not found.\n");
else if (read_status == 2)
printf("CORAL.PCX is not a PCX file.\n");
if (write_status == 1)
printf("NEW.PCX not created.\n");
}
Because their structure parallels the structure of video memory, PCX
files are specific to certain video modes. The following table summarizes
the compatible video modes for PCX files.
If PCX file was You can display
created in mode it in these modes
4 or 5 4 or 5
6 or 11 6, 11, 13 to 18
9 9
13 to 18 13 to 18
19 19 to 23
Displaying a PCX file at a lower resolution (for example, a 640x480 PCX file
at 320x200) will truncate the display on the right and on the bottom. This
effectively displays the upper left corner of the PCX file. If you try to
166 Fastgraph User's Guide
display a PCX file in an incompatible video mode, fg_disppcx will still
display something, but it will be garbled.
In the Tandy/PCjr 16-color graphics mode (mode 9) and the native EGA
graphics modes (modes 13 through 16), the palette registers are not readable.
Hence, fg_makepcx will use the default palette settings when used in these
video modes. In 640-column EGA modes, you can get around this problem by
creating PCX files in mode 18 and only using the first 200 or 350 pixel rows.
PCX files created in mode 18 preserve the current palette settings and will
display properly in EGA modes. The fg_disppcx and fg_makepcx routines have
no effect in text video modes or in the Hercules low-resolution graphics
mode.
Masking Maps
It is not possible to include color 0 pixels in an image displayed with
the fg_drwimage, fg_clpimage, fg_revimage, or fg_flpimage routines. This is
because these routines consider color 0 pixels to be transparent, which means
such pixels do not affect the corresponding pixels in video memory. There
are times, however, when you will want color 0 pixels to be destructive, or
replace the video memory contents.
Consider again the arrow image of example 9-8 (see page 149). In this
example, we displayed a bright white (color 3) arrow against a black (color
0) background in the standard CGA four-color graphics mode. Suppose, though,
that we want to do just the opposite -- display a black (color 0) arrow
against a bright white (color 3) background. Example 9-9 (see page 151) does
this in an EGA graphics mode, but how would we display the black arrow in a
CGA graphics mode? We could of course use the fg_drawmap routine or one of
the routines for displaying pixel run maps, but fg_drawmap does not support
clipping or reversing an image. There are, however, four Fastgraph routines
designed just for this purpose. These routines are fg_drawmask, fg_clipmask,
fg_revmask, and fg_flipmask.
Each of these routines uses a data structure called a masking map. A
masking map is similar in structure to a pixel run map, but it does not
include any information about colors. Instead, it consists of a series of
pixel runs that alternate between protected and unprotected pixels. An
example might best clarify this.
Once again, here is the arrow image of examples 9-8 and 9-9.
. . . . . . * . . .
. . . . . . * * . .
* * * * * * * * * .
* * * * * * * * * *
* * * * * * * * * .
. . . . . . * * . .
. . . . . . * . . .
This time, though, we want the arrow to appear in color 0. Put another way,
we need the "period" pixels (.) to protect video memory, while we want the
"asterisk" pixels (*) to zero video memory. Looking at this problem from the
perspective of a pixel run map, we have an alternating series of "protect"
and "zero" runs. We don't need any information about pixel colors, just
whether to protect or to zero video memory.
Chapter 9: Images and Image Management 167
This is precisely the structure of a masking map. Starting from the
lower left corner of the image and proceeding to the right, wrapping up to
the next row when needed, we could represent this image as a masking map with
6 protected pixels, 1 zeroed pixel, 9 protected pixels, 2 zeroed pixels, and
so on. In general, the structure of a masking map is as follows.
[1] length of 1st protect run
[2] length of 1st zero run
[3] length of 2nd protect run
[4] length of 2nd zero run
.
.
.
[n-2] length of final protect run
[n-1] length of final zero run
Looking at this diagram, we see that the even-numbered array elements
hold the length of the "protect" runs, and the odd-numbered elements hold the
length of the "zero" runs. If you need the first run to be a "zero" run,
just include a "protect" run of length zero as the first element of the
array. If the final run is a "protect" run, you do not need to include a
zero-length "zero" run at the end of the array. Finally, if either type of
run exceeds 255 pixels, you'll need to split this into two or more pixel
runs. In this case, be sure to include a zero-length run of the other type
between the two array elements.
Example 9-16 illustrates the use of a masking map through the
fg_drawmask, fg_clipmask, fg_revmask, and fg_flipmask routines in the
standard CGA four-color graphics mode (mode 4) to draw a black (color 0)
arrow against a bright white background. These four routines are
respectively analogous to the fg_drwimage, fg_clpimage, fg_revimage, and
fg_flpimage routines, but they use masking maps rather than bit maps. The
first argument of each routine is the masking map array (passed by
reference), the second argument is the number of runs (that is, the number of
elements) in the masking map array, and the third argument is the width in
pixels of the image.
Example 9-16.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char arrow[] = {6,1,9,2,2,9,1,19,7,2,8,1};
void main()
{
int old_mode;
168 Fastgraph User's Guide
if (fg_testmode(4,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 CGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(4);
fg_setclip(0,15,0,199);
fg_setcolor(3);
fg_rect(0,319,0,199);
fg_move(10,10);
fg_drawmask(arrow,12,10);
fg_move(10,20);
fg_clipmask(arrow,12,10);
fg_move(10,30);
fg_revmask(arrow,12,10);
fg_move(10,40);
fg_flipmask(arrow,12,10);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
One of the more useful features of masking maps is the ability to clear
a portion of video memory before placing an image there. This technique
provides an efficient, simple way to include color 0 pixels in an image. It
is especially effective when displaying large or dithered images because the
masking map is typically much smaller than the bit map required by fg_drawmap
or its related routines. Example 9-17 illustrates this process in the
standard CGA four-color graphics mode (mode 4) by displaying our arrow image
against a colored background. In this example, the arrow has a bright white
(color 3) perimeter and a black (color 0) interior.
The program displays the arrow in two steps. It first uses fg_drawmask
to clear the video memory where the arrow will be displayed. It then draws
the arrow's perimeter using the fg_drwimage routine. The interior pixels in
the perimeter bit map are transparent, but since we just zeroed that video
memory, they appear in color 0. Note we could improve this example by
creating a smaller masking map that only applies to the rectangle inscribing
the arrow's interior. That is, we don't need to zero the video memory under
the arrow's perimeter because we will immediately display other pixels there.
Example 9-17.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
char arrow_white[] = {
0x00,0x0C,0x00, 0x00,0x0F,0x00, 0xFF,0xFC,0xC0,
0xC0,0x00,0x30, 0xFF,0xFC,0xC0, 0x00,0x0F,0x00,
0x00,0x0C,0x00
};
Chapter 9: Images and Image Management 169
char arrow_black[] = {6,1,9,2,2,9,1,19,7,2,8,1};
void main()
{
int old_mode;
if (fg_testmode(4,1) == 0) {
printf("This program requires a 320 ");
printf("x 200 CGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(4);
fg_setcolor(2);
fg_rect(0,319,0,199);
fg_move(10,10);
fg_drawmask(arrow_black,12,10);
fg_drwimage(arrow_white,3,7);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Retrieving Images
Sometimes it is necessary to retrieve an image from video memory and
store it in one or more bit map arrays. Fastgraph includes two routines,
fg_getmap and fg_getimage, for this purpose. The fg_getmap routine retrieves
pixels of the current color index and stores them in the mode-independent bit
map format used by fg_drawmap. The fg_getimage routine retrieves an image
and stores it in the mode-specific bit map format used by fg_drwimage,
fg_clpimage, fg_revimage, and fg_flpimage. The arguments to fg_getmap and
fg_getimage are respectively analogous to those of fg_drawmap and
fg_drwimage: the first is an array (passed by reference) to receive the bit
map, the second is the width of the bit map in bytes, and the last is the
height of the bit map in pixel rows. With either routine, the graphics
cursor position on the active video page defines the lower left corner of the
image to retrieve.
If we want to use the fg_getmap routine to retrieve an image containing
more than one color, we must call the routine once per color. In this case
we'll usually want to pass different bit map arrays to fg_getmap (or perhaps
different offsets into the same array). This might seem unusual at first,
but it parallels the behavior of the fg_drawmap routine. That is, to display
a multicolor image using fg_drawmap, we must call it once for each color in
the image.
Example 9-18 demonstrates a typical use of the fg_getmap routine. The
program displays the word "text" in the upper left corner of the screen using
a 320 by 200 graphics mode. It uses fg_getmap to retrieve the word as an
170 Fastgraph User's Guide
image and then displays it in a new position with the fg_drawmap routine.
Let's look at the program now, and afterward we'll more closely examine the
screen coordinates and the structure of the bit map array.
Example 9-18.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
char bitmap[32];
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(9);
fg_text("text",4);
fg_waitkey();
fg_move(0,7);
fg_getmap(bitmap,4,8);
fg_move(4,15);
fg_drawmap(bitmap,4,8);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
In all 320 by 200 graphics video modes, individual characters are 8
pixels wide and 8 pixels high. This means the lower left corner of the (0,0)
character cell is referenced by the screen coordinates (0,7). Hence, these
are the coordinates of the first call to fg_move. The image retrieved in
example 9-18 is four characters long (32 pixels wide), so we need a bit map
array capable of holding 8 rows of 32 pixels (4 bytes) each. Our bit map
array is therefore a 32-byte array, logically structured to have 4 columns
and 8 rows. These values are the width and height arguments passed to
fg_getmap and fg_drawmap.
After it retrieves the image, example 9-18 displays it one line below
and one-half character cell (four pixels) to the right of its original
position. In other words, the program displays the image four pixels to the
right of the (1,0) character cell. The lower left corner of that cell is
referenced by the screen coordinates (0,15), so the image should appear at
the position (4,15). These are the coordinates of the second call to
fg_move.
Chapter 9: Images and Image Management 171
Example 9-19 illustrates the use of the fg_getmap and fg_drawmap
routines to retrieve and display two-color image. This example is similar to
example 9-18, but this program first draws a rectangle in the upper left
corner of the screen and then displays the word "text" on top of the
rectangle in a different color. Each character in a 320 by 200 graphics
video mode is 8 pixels wide and 8 pixels high, so the rectangle must be 32
pixels wide (4 characters times 8 pixels per character) and 8 pixels high.
The image to retrieve will be the same size as the rectangle.
The image retrieved in example 9-18 required a 32-byte array, logically
structured to have 4 columns and 8 rows. Example 9-19 will retrieve an image
of the same structure, but the image contains two colors instead of just one.
This means we need two 32-byte arrays, one for each color, to hold the image.
We could instead use a single 64-byte array and pass an offset into that
array (specifically, &bitmap[32]) for processing the second color.
Example 9-19.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
char bitmap1[32], bitmap2[32];
int old_mode, new_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(7);
fg_rect(0,31,0,7);
fg_setcolor(9);
fg_text("text",4);
fg_waitkey();
fg_move(0,7);
fg_setcolor(7);
fg_getmap(bitmap1,4,8);
fg_setcolor(9);
fg_getmap(bitmap2,4,8);
fg_move(4,15);
fg_setcolor(7);
fg_drawmap(bitmap1,4,8);
fg_setcolor(9);
fg_drawmap(bitmap2,4,8);
fg_waitkey();
172 Fastgraph User's Guide
fg_setmode(old_mode);
fg_reset();
}
Example 9-20 is similar to example 9-19, but it uses fg_getimage and
fg_drwimage instead of fg_getmap and fg_drawmap to retrieve and display the
image. That is, it uses the mode-specific rather than the mode-independent
image retrieval and display routines. When using the mode-specific routines,
the size of the bit map needed to hold the image depends on the video mode.
For programs that run in only one video mode, bit map widths are constant,
but when a program must run in several video modes, the width is variable.
The Fastgraph routine fg_imagesiz computes the number of bytes required to
store a mode-specific bit-mapped image of specified dimensions. Its two
integer arguments specify the image width and height in pixels.
The program computes the image width in bytes by passing a height of 1
to fg_imagesiz. The size of the bit map array in example 9-20 is 256 bytes,
the size required in the MCGA graphics mode (32 bytes times 8 bytes). The
other video modes require less storage, so in these modes only a portion of
the bit map array will actually be used. The image width is then used in the
calls to both fg_getimage and fg_drwimage.
Example 9-20.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
char bitmap[256];
int old_mode, new_mode;
int width;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
width = (int)fg_imagesiz(32,1);
fg_setcolor(7);
fg_rect(0,31,0,7);
fg_setcolor(9);
fg_text("text",4);
fg_waitkey();
fg_move(0,7);
fg_getimage(bitmap,width,8);
fg_move(4,15);
fg_drwimage(bitmap,width,8);
fg_waitkey();
Chapter 9: Images and Image Management 173
fg_setmode(old_mode);
fg_reset();
}
While this example used an array to store the image, it's usually preferable
to allocate dynamic memory for this purpose. We could have done this in
example 9-20 by calling fg_imagesiz with arguments of 32 (width) and 8
(height). The routine's return value would then tell us the number of bytes
we would need to allocate.
We also can use the fg_getimage routine to retrieve images in text video
modes. In text modes, however, there are a few differences we must consider
when using fg_getimage. First, the text cursor position, not the graphics
cursor position, specifies the lower left corner of the image. Hence, we
must use the fg_locate routine instead of fg_move to define the image
location. Second, the image width is always twice the number of characters
per image row (that is, for each character we have a character byte and an
attribute byte). The fg_getmap routine has no effect when used in a text
video mode.
Example 9-21 shows a simple use of fg_getimage in text modes. This
program is similar to example 9-20, but it runs in an 80-column text mode
rather than a 320 by 200 graphics mode. As before, the program will retrieve
the four characters "text" as an image from the upper left corner of the
screen and then display it in a different location. Because the image
consists of four characters in one row, the image width is 8 bytes and the
image height is 1.
Example 9-21.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int old_mode;
char image[8];
old_mode = fg_getmode();
if (fg_testmode(3,1))
fg_setmode(3);
else if (fg_testmode(7,1))
fg_setmode(7);
else {
printf("This program requires\n");
printf("an 80-column display.\n");
exit(1);
}
fg_cursor(0);
fg_setattr(9,7,0);
fg_text("text",4);
174 Fastgraph User's Guide
fg_waitkey();
fg_locate(0,0);
fg_getimage(image,8,1);
fg_locate(1,1);
fg_drwimage(image,8,1);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Byte Boundaries
Video memory, like standard random-access memory, is divided into units
called bytes. In text modes, each byte holds either a character or an
attribute. In graphics modes, each byte of video memory holds one or more
horizontally contiguous pixels. If two adjacent horizontal pixels are stored
in different bytes, then we say that a byte boundary exists between the two
pixels.
The number of pixels per byte depends on the video mode being used, so
the byte boundaries also depend on the video mode. That is, a byte boundary
in a CGA graphics mode is not necessarily a byte boundary in an EGA graphics
mode. The following table summarizes the number of pixels per byte of video
memory and the byte boundary sequences for each supported graphics video
mode. Note that any horizontal coordinate whose value is a multiple of 8 is
always a byte boundary, regardless of the video mode.
mode pixels horizontal coordinates
number per byte of byte boundaries
4 4 0, 4, 8, 12, ... , 316
5 4 0, 4, 8, 12, ... , 316
6 8 0, 8, 16, 24, ... , 632
9 2 0, 2, 4, 6, ... , 318
11 8 0, 8, 16, 24, ... , 712
12 4 0, 4, 8, 12, ... , 316
13 8 0, 8, 16, 24, ... , 312
14 8 0, 8, 16, 24, ... , 632
15 8 0, 8, 16, 24, ... , 632
16 8 0, 8, 16, 24, ... , 632
17 8 0, 8, 16, 24, ... , 632
18 8 0, 8, 16, 24, ... , 632
19 1 0, 1, 2, 3, ... , 319
20 1 0, 1, 2, 3, ... , 319
21 1 0, 1, 2, 3, ... , 319
22 1 0, 1, 2, 3, ... , 319
23 1 0, 1, 2, 3, ... , 319
Chapter 9: Images and Image Management 175
Image Transfer Routines
The Fastgraph routines described in this section transfer images between
areas of video memory. These routines are often used in animation sequences
requiring high-performance graphics, so they must be as efficient as
possible. To this end, Fastgraph will force their horizontal pixel
coordinates to byte boundaries, which eliminates the need to process any
pixels individually. Fastgraph accomplishes this by reducing minimum
horizontal coordinates to a byte boundary and extending maximum horizontal
coordinates to the last pixel in a video memory byte. Note that since we are
talking about pixel coordinates and not character cells, the coordinate
modification only occurs in graphics video modes.
An example might best help explain this important feature. The CGA
four-color graphics modes (modes 4 and 5) store four pixels in each byte of
video memory. This means the byte boundaries occur at multiples of four
pixels. Thus, when you use the image transfer routines in modes 4 and 5,
Fastgraph reduces minimum x coordinates to the next lower multiple of four.
Similarly, it extends their maximum x coordinates to the next higher multiple
of four, less one pixel. That is, if a minimum x coordinate is 7 and a
maximum x coordinate is 30, Fastgraph will modify these values to 4 and 31
respectively. If the x coordinates were originally 4 and 31, Fastgraph would
leave them unchanged. Note, too, that because each pixel in the MCGA and VGA
256-color graphics modes (modes 19 through 23) occupies a separate byte of
video memory, Fastgraph does not need to modify horizontal coordinates in
these video modes.
Fastgraph's simplest image transfer routine is fg_copypage, which we
introduced in Chapter 8. The fg_copypage routine transfers the entire
contents of one video page to another. The first argument is the number of
the source video page, and the second argument is the number of the
destination video page. The pages may be physical, virtual, or logical video
pages. If both the source and destination pages are logical pages, the pages
must exist in the same type of memory. For example, you cannot copy a
logical page in extended memory to a logical page in conventional memory.
Example 9-22 illustrates the use of the fg_copypage routine in a 320 x
200 color graphics mode. The program displays the word "test" in the middle
of the visual page (page 0) and then uses fg_allocate to create a virtual
video page (page 1). The virtual page is needed in case the program is
running in a video mode with only one physical page. Next, the program uses
176 Fastgraph User's Guide
fg_copypage to transfer the visual page contents to page 1. After waiting
for a keystroke, the program erases the visual page, waits for another
keystroke, and copies the contents of page 1 back to the visual page. It
then releases the virtual page and exits.
Example 9-22.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int new_mode, old_mode;
new_mode = fg_bestmode(320,200,2);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_setcolor(9);
fg_locate(12,18);
fg_text("test",4);
fg_waitkey();
fg_allocate(1);
fg_copypage(0,1);
fg_erase();
fg_waitkey();
fg_copypage(1,0);
fg_waitkey();
fg_freepage(1);
fg_setmode(old_mode);
fg_reset();
}
Several of Fastgraph's image transfer routines reference a video page
called the hidden page. The Fastgraph routine fg_sethpage defines which
video page will be used as the hidden page. This routine takes as its only
argument an integer value specifying the hidden page number. If you are
using a virtual video page for the hidden page, you must call the fg_sethpage
routine after allocating that page. There is also a routine named
fg_gethpage that returns the hidden page number, as specified in the most
recent call to fg_sethpage, as its function value. The fg_gethpage routine
takes no arguments.
The next two image transfer routines we'll discuss are fg_save and
fg_restore. The fg_save routine transfers a rectangular region from the
Chapter 9: Images and Image Management 177
active video page (as defined in the most recent call to fg_setpage) to the
same position on the hidden video page (as defined in the most recent call to
fg_sethpage). The fg_restore routine performs the complementary task -- it
transfers a rectangular region from the hidden page to the active page. Each
of these routines requires four arguments that define the coordinates of the
region to transfer, in the order minimum x, maximum x, minimum y, and maximum
y. In text modes, the coordinates are expressed as character space
quantities (rows and columns). In graphics modes, they are expressed as
screen space values (pixels); the x coordinates are extended to byte
boundaries if required. There are also world space versions of these
routines named fg_savew and fg_restorew available in graphics modes.
Example 9-23 demonstrates the use of Fastgraph's fg_save, fg_restore,
and fg_sethpage routines in an 80-column text video mode. After establishing
the video mode (note the calls to fg_testmode specify that two video pages
are needed), the program fills the screen with text and then waits for a
keystroke. Following this, the program displays a small pop-up window
prompting for another keystroke. After waiting for the second keystroke, the
program erases the pop-up window by restoring the original screen contents,
and then waits for yet another keystroke before returning to DOS. We'll
present the program now, and afterward analyze it in detail.
Example 9-23.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int row;
int old_mode;
char string[17];
old_mode = fg_getmode();
if (fg_testmode(3,2))
fg_setmode(3);
else if (fg_testmode(7,2))
fg_setmode(7);
else {
printf("This program requires\n");
printf("an 80-column display.\n");
exit(1);
}
fg_cursor(0);
fg_setattr(9,7,0);
for (row = 0; row < 25; row++) {
sprintf(string," This is row %2d ",row);
fg_locate(row,0);
fg_text(string,16);
fg_text(string,16);
fg_text(string,16);
fg_text(string,16);
178 Fastgraph User's Guide
fg_text(string,16);
}
fg_waitkey();
fg_allocate(1);
fg_sethpage(1);
fg_save(32,47,11,13);
fg_setcolor(1);
fg_rect(32,47,11,13);
fg_setattr(15,1,0);
fg_locate(12,33);
fg_text("Press any key.",14);
fg_waitkey();
fg_restore(32,47,11,13);
fg_waitkey();
fg_freepage(1);
fg_setmode(old_mode);
fg_reset();
}
Example 9-23 first establishes the video mode and uses the fg_cursor
routine to make the BIOS cursor invisible. It then executes a for loop that
fills each row of the screen with the phrase "This is row n", where n is the
row number (between 0 and 24). Next, the program uses the fg_allocate
routine to create video page 1 as a virtual video page. This is needed in
case the program is running in mode 7, which has only one true page (if the
program is running in mode 3, the call to fg_allocate has no effect). The
program then makes page 1 the hidden page by calling the fg_sethpage routine.
After setting up the hidden video page, but before displaying the pop-up
window, example 9-23 uses the fg_save routine to save the current contents of
the area that the pop-up window will replace. The fg_save routine copies
this region to the hidden page. The program then displays the pop-up window
in the middle of the screen and leaves it there until a key is pressed. After
this, the program uses the fg_restore routine to replace the pop-up window
with the original contents of that region. This effectively erases the pop-up
window and restores the original screen. The program then waits for another
keystroke, after which it releases the virtual page and returns to DOS.
The next example, 9-24, is similar to example 9-23, but it runs in a 320
by 200 color graphics mode instead of a text mode. The main differences
between this program and example 9-23 are the use of 40-column text and the
use of screen space coordinates instead of character space coordinates in the
calls to fg_save, fg_restore, and fg_rect. Note that the call to fg_allocate
creates a virtual page if the program is running in modes 4, 9, or 19. In
mode 13, which has 8 true pages, the fg_allocate routine does nothing.
Example 9-24.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
Chapter 9: Images and Image Management 179
void main()
{
int row;
int new_mode, old_mode;
char string[21];
new_mode = fg_bestmode(320,200,2);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_setcolor(9);
for (row = 0; row < 25; row++) {
sprintf(string," This is row %2d ",row);
fg_locate(row,0);
fg_text(string,20);
fg_text(string,20);
}
fg_waitkey();
fg_allocate(1);
fg_sethpage(1);
fg_save(96,223,88,111);
fg_setcolor(1);
fg_rect(96,223,88,111);
fg_setcolor(15);
fg_locate(12,13);
fg_text("Press any key.",14);
fg_waitkey();
fg_restore(96,223,88,111);
fg_waitkey();
fg_freepage(1);
fg_setmode(old_mode);
fg_reset();
}
The fg_save and fg_restore routines each copy a rectangular region from
one video page to the same position on another video page. What if you need
to copy the region to a different position on another video page, or copy it
elsewhere on the same video page? Fastgraph provides a more general image
transfer routine named fg_transfer. The fg_transfer routine copies a
rectangular region on any video page to any position on any video page. Like
fg_save and fg_restore, the fg_transfer routine works in text and graphics
video modes. In graphics modes, fg_transfer extends its x coordinates to
byte boundaries if necessary.
The fg_transfer routine requires eight integer arguments. The first
four arguments define the region to copy, in the same order as expected by
the fg_save and fg_restore routines. The next two arguments define the lower
180 Fastgraph User's Guide
left corner of the image destination, while the final two arguments
respectively specify the source and destination video page numbers. In
short, fg_transfer copies the specified region from the source page to the
specified position on the destination page.
Example 9-25 is the same as example 9-23, but it uses fg_transfer rather
than fg_save and fg_restore. We have arbitrarily chosen to copy the region
overwritten by the pop-up window to the lower left corner of the hidden page
(page 1). When we copy this region back to the visual page, we copy from the
lower left corner of the hidden page back to the original position on the
visual page (page 0). This sequence is shown in the following diagram.
(11,32) (11,47) (22,0) (22,15)
first call
This is row 11 ------------> This is row 11
This is row 12 This is row 12
This is row 13 <------------ This is row 13
second call
(13,32) (13,47) (24,0) (24,15)
visual page (0) hidden page (1)
To copy one region to a new position and then back to its original position,
note how we make the fifth and sixth arguments in the first call to
fg_transfer the same values as the first and fourth arguments in the second
call. Similarly, the fifth and sixth arguments in the second call must be
the same as the first and fourth arguments in the first call. Now, here is
example 9-25.
Example 9-25.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int row;
int old_mode;
char string[17];
old_mode = fg_getmode();
if (fg_testmode(3,2))
fg_setmode(3);
else if (fg_testmode(7,2))
fg_setmode(7);
else {
printf("This program requires\n");
printf("an 80-column display.\n");
exit(1);
}
fg_cursor(0);
fg_setattr(9,7,0);
Chapter 9: Images and Image Management 181
for (row = 0; row < 25; row++) {
sprintf(string," This is row %2d ",row);
fg_locate(row,0);
fg_text(string,16);
fg_text(string,16);
fg_text(string,16);
fg_text(string,16);
fg_text(string,16);
}
fg_waitkey();
fg_allocate(1);
fg_transfer(32,47,11,13,0,24,0,1);
fg_setcolor(1);
fg_rect(32,47,11,13);
fg_setattr(15,1,0);
fg_locate(12,33);
fg_text("Press any key.",14);
fg_waitkey();
fg_transfer(0,15,22,24,32,13,1,0);
fg_fg_waitkey();
fg_freepage(1);
fg_setmode(old_mode);
fg_reset();
}
Example 9-26 illustrates another use of the fg_transfer routine. This
example is functionally identical to example 9-18 (see page 170), but it uses
fg_transfer instead of fg_getmap and fg_drawmap. With the fg_transfer
routine, we eliminate the calls to fg_getmap and fg_drawmap, the two calls to
fg_move, and the 32-byte array needed to retrieve the image. As an added
bonus, using fg_transfer is much faster than the technique of example 9-18,
although we probably won't notice this gain with such a small image.
The image copied in example 9-26 is one row of four characters, so its
width in screen space is 32 pixels and its height is 8 pixels. Because the
image is in the upper left corner of the screen, the image boundaries are
xmin=0, xmax=31, ymin=0, and ymax=7. We want to move the image one-half
character cell (4 pixels) to the right and one row (8 pixels) down, so our
destination coordinates are x=4 (xmin+4) and y=15 (ymax+8). Also, we are
copying the image from one position to another on the visual page, so both
the source and destination pages are 0.
Example 9-26.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int old_mode, new_mode;
182 Fastgraph User's Guide
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(9);
fg_text("text",4);
fg_waitkey();
fg_transfer(0,31,0,7,4,15,0,0);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Example 9-27 shows yet another application of the fg_transfer routine in
a graphics video mode. The program displays a rectangle in the upper left
quadrant of the screen and then centers the word "quadrant" inside the
rectangle. After waiting for a keystroke, the program uses fg_transfer to
first copy the upper left quadrant to the upper right quadrant. It then uses
fg_transfer again to copy the upper half of the screen to the lower half.
The result of this is the screen being filled with what was originally in the
upper left quadrant.
Example 9-27.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int new_mode, old_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
fg_setcolor(7);
fg_rect(0,159,0,99);
fg_setcolor(9);
fg_locate(6,6);
fg_text("quadrant",8);
fg_waitkey();
Chapter 9: Images and Image Management 183
fg_transfer(0,159,0,99,160, 99,0,0);
fg_transfer(0,319,0,99, 0,199,0,0);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
The final routines pertaining to image transfer are fg_tcxfer and
fg_tcmask. The fg_tcxfer routine is similar to fg_transfer in that it copies
a rectangular region from one position to another, but fg_tcxfer allows you
to treat one or more colors as transparent (the name fg_tcxfer stands for
"transparent color transfer"). In other words, any pixel whose color value
is defined to be transparent is not copied to the destination area. The
fg_tcxfer routine's arguments are the same as for the fg_transfer routine, but
fg_tcxfer has no effect in text video modes. Because fg_tcxfer must examine
the color of individual pixels, it is not as fast as the fg_transfer routine.
The fg_tcmask routine defines which colors are considered transparent in
subsequent calls to fg_tcxfer. Its argument is an integer bit mask
(specifically, a 16-bit mask) where each bit indicates whether or not the
color is transparent. For example, if bit 0 (the rightmost bit) is set in
the mask, then color 0 will be transparent; if bit 0 is reset, color 0 will
not be transparent. Because the bit mask size is 16 bits, only the first 16
color values may be defined as transparent.
Example 9-28 illustrates the use of the fg_tcxfer and fg_tcmask routines.
This program is the same as example 9-27, except the color of the word
"quadrant" (color 9) is defined to be transparent, and fg_tcxfer is used in
place of fg_transfer. Because color 9 maps to color 1 in the CGA four-color
graphics mode (mode 4), we must define both colors 1 and 9 to be transparent
(remember, fg_tcmask considers actual color values transparent, not color
indices). The bit mask passed to fg_tcmask thus will be 0000 0010 0000 0010
binary, or 0202 hex. The result of this program is the same as example 9-27,
but the word "quadrant" appears in the background color (color 0) instead of
color 9 in the upper right, lower left, and lower right quadrants.
Example 9-28.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int new_mode, old_mode;
new_mode = fg_bestmode(320,200,1);
if (new_mode < 0 || new_mode == 12) {
printf("This program requires a 320 ");
printf("x 200 color graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(new_mode);
184 Fastgraph User's Guide
fg_setcolor(7);
fg_rect(0,159,0,99);
fg_setcolor(9);
fg_locate(6,6);
fg_text("quadrant",8);
fg_waitkey();
fg_tcmask(0x0202);
fg_tcxfer(0,159,0,99,160, 99,0,0);
fg_tcxfer(0,319,0,99, 0,199,0,0);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Summary of Image Display Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these
routines, including their arguments and return values, may be found in the
Fastgraph Reference Manual.
For all image display routines, images are positioned so their lower
left corner is at the graphics cursor position (or text cursor position for
those routines that also work in text video modes). For all image transfer
routines, Fastgraph extends the horizontal pixel coordinates to a byte
boundary when the routines are used in a graphics video mode.
FG_CLIPMASK displays a clipped image stored as a masking map. This
routine has no effect when used in a text video mode.
FG_CLPIMAGE displays a clipped image stored as a mode-specific bit map.
This routine has no effect when used in a text video mode.
FG_COPYPAGE transfers the contents of one video page to another. The
pages may be physical, virtual, or logical video pages. If both pages are
logical pages, they must exist in the same type of memory.
FG_DISPFILE displays an image stored in Fastgraph's standard or packed
pixel run format, where the image resides in an external file. This routine
has no effect when used in a text video mode.
FG_DISPLAY displays an image stored in Fastgraph's standard pixel run
format, where the image resides in an array. This routine has no effect when
used in a text video mode.
FG_DISPLAYP displays an image stored in Fastgraph's packed pixel run
format, where the image resides in an array. This routine has no effect when
used in a text video mode.
FG_DISPPCX displays an image stored in a PCX file. The image will be
positioned so its upper left corner is at the graphics cursor position of the
active video page.
Chapter 9: Images and Image Management 185
FG_DRAWMAP displays an image stored as a mode-independent bit map. This
routine has no effect when used in a text video mode.
FG_DRAWMASK displays an image stored as a masking map. This routine has
no effect when used in a text video mode.
FG_DRWIMAGE displays an image stored as a mode-specific bit map.
FG_FLIPMASK displays a reversed clipped image stored as a masking map.
This routine has no effect when used in a text video mode.
FG_FLPIMAGE displays a reversed clipped image stored as a mode-specific
bit map. This routine has no effect when used in a text video mode.
FG_GETHPAGE returns the hidden page number, as defined in the most
recent call to fg_sethpage.
FG_GETIMAGE retrieves an image as a mode-specific bit map.
FG_GETMAP retrieves an image as a mode-independent bit map. This
routine has no effect when used in a text video mode.
FG_IMAGESIZ determines the number of bytes required to store a mode-
specific bit-mapped image of specified dimensions.
FG_MAKEPCX creates a PCX file from the specified rectangular region of
the active video page. The region's extremes are expressed in screen space
units.
FG_PATTERN defines a display pattern for use with the fg_dispfile,
fg_display, or fg_displayp routines. This routine has no effect when used in
a text video mode.
FG_RESTORE copies an image from the hidden video page to the same
position on the active video page.
FG_RESTOREW is the same as fg_restore, but the image extremes are
specified as world space coordinates.
FG_REVIMAGE displays a reversed image stored as a mode-specific bit map.
This routine has no effect when used in a text video mode.
FG_REVMASK displays a reversed image stored as a masking map. This
routine has no effect when used in a text video mode.
FG_SAVE copies an image from the active video page to the same position
on the hidden video page.
FG_SAVEW is the same as fg_save, but the image extremes are specified as
world space coordinates.
FG_SETHPAGE defines the hidden video page (used by fg_restore,
fg_restorew, fg_save, and fg_savew).
FG_TCMASK defines which colors the fg_tcxfer routine will consider
transparent. This routine has no effect when used in a text video mode.
186 Fastgraph User's Guide
FG_TCXFER copies an image from any position on any video page to any
position on any video page, excluding any pixels whose color value is
transparent. This routine has no effect when used in a text video mode.
FG_TRANSFER copies an image from any position on any video page to any
position on any video page. It is Fastgraph's most general image transfer
routine.