home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-07 | 315.6 KB | 7,674 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.
-
-
- Chapter 10
-
- Animation Techniques
- 188 Fastgraph User's Guide
-
- Overview
-
- Unlike other microcomputers, the IBM PC and PS/2 family of systems do
- not have any special graphics hardware or firmware to help in performing
- animation. This means that any animation done on these systems must be
- implemented entirely through software. This chapter will describe how to do
- this using Fastgraph's video page management and image management routines.
- The methods described in this chapter are not intended to be all inclusive,
- for that would itself fill a separate volume at least as large as this
- manual. However, the animation techniques presented here should provide a
- basis that you can readily extend to develop more sophisticated uses of
- animation. The examples in this chapter are restricted to graphics video
- modes.
-
-
- Simple Animation
-
- The first type of animation we'll examine is called simple animation.
- In simple animation, we display an object, erase it, and then display it in a
- new position. When we perform this "erase and redisplay" sequence
- repetitively, the object moves. This method, however, has two drawbacks.
- First, unless the object is rather small, it will flicker because the erasing
- and display of the object does not coincide with the refresh rate of the
- video display. Second, and perhaps more importantly, anything underneath the
- object is not saved as the object moves across it. Despite these
- limitations, simple animation is sometimes useful, and it is a good place to
- begin our discussion of animation techniques.
-
- Example 10-1 moves a small bright green rectangle (magenta in CGA) from
- left to right across the screen in any 320 by 200 color graphics mode. The
- program moves the rectangle, 20 pixels wide and 10 pixels high, using a for
- loop. This loop first uses the fg_clprect routine to display the rectangle,
- then uses the fg_waitfor routine to leave the object on the screen
- momentarily, and finally uses fg_clprect again to erase the rectangle by
- redisplaying it in the original background color (the fg_waitfor routine is
- described in Chapter 14). We use fg_clprect rather than fg_rect because the
- first few and last few loop iterations result in at least part of the
- rectangle being off the screen. Each successive loop iteration displays the
- rectangle five pixels to the right of its previous position.
-
- Example 10-1.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int new_mode, old_mode;
- int x;
-
- /* initialize the video environment */
-
- new_mode = fg_bestmode(320,200,1);
- if (new_mode < 0 || new_mode == 12) {
-
- Chapter 10: Animation Techniques 189
-
- printf("This program requires a 320 ");
- printf("x 200 color graphics mode.\n");
- exit(1);
- }
- old_mode = fg_getmode();
- fg_setmode(new_mode);
-
- /* move the object across the screen */
-
- for (x = -20; x < 320; x+=5) {
- fg_setcolor(10);
- fg_clprect(x,x+19,95,104);
- fg_waitfor(1);
- fg_setcolor(0);
- fg_clprect(x,x+19,95,104);
- }
-
- /* restore the original video mode and return to DOS */
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
- Example 10-2 is the same as example 10-1, but it shows what happens when
- we move the rectangle across an existing background (in this case, the
- background is solid white). If you run this program, you'll see that the
- rectangle leaves a trail of color 0 behind it. While this might be
- occasionally useful, it demonstrates that simple animation is destructive
- because it does not preserve the background. In this example, if we changed
- the second call to fg_setcolor within the for loop so revert to color 15
- instead of color 0, the background would be restored. In general, though, it
- may not be this easy to replace the background, so we must rely on some other
- method for preserving it.
-
- Example 10-2.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int new_mode, old_mode;
- int x;
-
- /* initialize the video environment */
-
- 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);
-
- 190 Fastgraph User's Guide
-
- /* draw some type of background */
-
- fg_setcolor(15);
- fg_rect(0,319,0,199);
-
- /* move the object across the screen */
-
- for (x = -20; x < 320; x+=5) {
- fg_setcolor(10);
- fg_clprect(x,x+19,95,104);
- fg_waitfor(1);
- fg_setcolor(0);
- fg_clprect(x,x+19,95,104);
- }
-
- /* restore the original video mode and return to DOS */
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
- To summarize, we see that simple animation is easy to implement, but it
- is destructive and typically causes the animated object to flicker. For
- these reasons, it is not used too frequently.
-
-
- XOR Animation
-
- "Exclusive or" animation, or XOR animation for short, is an interesting
- extension of simple animation and is most useful when animating a single-
- color object against a single-color background. Like simple animation, it
- uses the "erase and redisplay" technique to move an object, but it does this
- differently. Instead of erasing the object by displaying it in the
- background color, XOR animation does so by displaying it in the same color
- using an exclusive or, or XOR, operation. This method relies on a specific
- property of the exclusive or operator:
-
- (object XOR background) XOR object = background
-
- In other words, if you XOR something twice in the same position, the result
- is the same as the original image in that position.
-
- Example 10-3 demonstrates XOR animation. This program is similar to
- example 10-2, but it only runs in the 320 by 200 EGA graphics mode (mode 13).
- After establishing the video mode, it uses the Fastgraph routine fg_setfunc
- to select XOR mode. This causes any subsequent graphics output to be XORed
- with the contents of video memory instead of just replacing it. The
- fg_setfunc routine is described further in Chapter 15.
-
- The other differences between examples 10-3 and 10-2 are that the call
- to fg_setcolor has been moved outside the for loop, and that fg_setcolor
- takes a different value. Since the existing background is bright white
- (color 15), we can't just use color 10 if we want to display a bright green
- object. The desired value is that which when XORed with color 15 produces
- color 10; the easiest way to obtain this value is to XOR these two numbers.
- The call to fg_setcolor can be moved outside the loop because we display the
- object using the same color index throughout.
- Chapter 10: Animation Techniques 191
-
- Example 10-3.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int old_mode;
- int x;
-
- /* initialize the video environment */
-
- if (fg_testmode(13,1) == 0) {
- printf("This program requires EGA.\n");
- exit(1);
- }
- old_mode = fg_getmode();
- fg_setmode(13);
- fg_setfunc(3);
-
- /* draw some type of background */
-
- fg_setcolor(15);
- fg_rect(0,319,0,199);
-
- /* move the object across the screen */
-
- fg_setcolor(10^15);
- for (x = -20; x < 320; x+=5) {
- fg_clprect(x,x+19,95,104);
- fg_waitfor(1);
- fg_clprect(x,x+19,95,104);
- }
-
- /* restore the original video mode and return to DOS */
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- Fastgraph only supports the XOR pixel operation in the native EGA and
- VGA graphics video modes (modes 13 through 18). Thus, you cannot use XOR
- animation in CGA, Tandy/PCjr, Hercules, or MCGA graphics modes.
-
- While XOR animation is non-destructive (that is, it restores the
- original background), it still suffers from the flickering encountered in
- simple animation. In spite of this, it may be useful when animating a
- single-color object against a single-color background.
- 192 Fastgraph User's Guide
-
-
- Static Frame Animation
-
- Static frame animation uses a different strategy than simple animation
- or XOR animation. The general scheme of this method is to create the entire
- animation sequence off-screen and then successively display each item, or
- frame, in this sequence on one position of the visual video page. This
- results in a visually appealing animation that is non-destructive and does
- not include the flickering associated with simple animation and XOR
- animation. Static frame animation requires the visual video page and one or
- more additional pages to implement. The number of pages needed depends on
- the number of frames and the size of each frame.
-
- Example 10-4 runs in any 320 by 200 color graphics video mode and
- illustrates a simple use of static frame animation. The program displays an
- animation sequence containing 12 frames; it displays this sequence three
- times. The animation sequence consists of a bright green rectangle (magenta
- in CGA) moving from left to right across the center of the frame. Each frame
- is 96 pixels wide and 50 pixels high. The 12 frames are set up on an off-
- screen video page as shown below.
-
- 0 95 96 191 192 287
-
- 0
- frame 1 frame 2 frame 3
- 49
-
- 50
- frame 4 frame 5 frame 6
- 99
-
- 100
- frame 7 frame 8 frame 9
- 149
-
- 150
- frame 10 frame 11 frame 12
- 199
-
- Example 10-4 first establishes the video mode and allocates the
- additional video page (needed if using a video mode in which page 1 is a
- virtual video page). The program then generates the background for frame 1;
- the background is a blue rectangle (cyan in CGA) with a white ellipse
- centered on it. After the call to fg_ellipse, the first frame is ready.
-
- The next step is to create the remaining 11 frames. In frame 2, the
- right half of the 20-pixel wide rectangle will enter the left edge of the
- frame. In frame 3, the rectangle will be ten pixels farther right, or
- aligned against the left edge of the frame. In frames 4 through 12, the
- rectangle will be ten pixels farther right in each frame, so by frame 12 only
- the left half of the rectangle appears on the right edge of the frame. The
- first for loop in the program builds frames 2 through 12 by copying the
- background from frame 1 and then displaying the rectangle (that is, the
- animated object) in the proper position for that frame.
-
- The second for loop performs the animation sequence. To display the 12-
- frame sequence three times, it must perform 36 iterations. The loop simply
- Chapter 10: Animation Techniques 193
-
- copies each frame from the proper position on video page 1 to the middle of
- the visual video page. Note how the fg_waitfor routine is used to pause
- momentarily between each frame.
-
- Example 10-4.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- #define VISUAL 0
- #define HIDDEN 1
-
- int xmin[] = { 0, 96,192, 0, 96,192, 0, 96,192, 0, 96,192};
- int ymax[] = { 49, 49, 49, 99, 99, 99,149,149,149,199,199,199};
-
- void main()
- {
- int new_mode, old_mode;
- int frame, offset;
- int i, x, y;
-
- /* initialize the video environment */
-
- 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_allocate(HIDDEN);
-
- /* draw the background in the upper left corner */
-
- fg_setpage(HIDDEN);
- fg_setcolor(1);
- fg_rect(0,95,0,49);
- fg_setcolor(15);
- fg_move(48,25);
- fg_ellipse(20,20);
-
- /* display the animated object against each background */
-
- fg_setcolor(10);
- offset = -10;
- for (i = 1; i < 12; i++) {
- x = xmin[i];
- y = ymax[i];
- fg_transfer(0,95,0,49,x,y,HIDDEN,HIDDEN);
- fg_setclip(x,x+95,0,199);
- fg_clprect(x+offset,x+offset+19,y-29,y-20);
- offset += 10;
- }
-
- 194 Fastgraph User's Guide
-
- /* slide the object across the background three times */
-
- for (i = 0; i < 36; i++) {
- frame = i % 12;
- x = xmin[frame];
- y = ymax[frame];
- fg_transfer(x,x+95,y-49,y,112,124,HIDDEN,VISUAL);
- fg_waitfor(2);
- }
-
- /* restore the original video mode and return to DOS */
-
- fg_freepage(HIDDEN);
- fg_setmode(old_mode);
- fg_reset();
- }
-
- Dynamic Frame Animation
-
- Dynamic frame animation is similar to static frame animation, but all
- the animation frames are built as needed during the animation sequence
- instead of in advance. When using this method, you must first store a copy
- of the background on an off-screen video page. Then, to build a frame,
- create another copy (called the workspace) of the background elsewhere on the
- off-screen page (or even to a different off-screen page) and display the
- object on that copy. Finally, transfer the workspace to the visual page.
- Like static frame animation, this method produces a non-destructive, flicker-
- free animation sequence.
-
- Example 10-5 is functionally identical to example 10-4, but it uses
- dynamic rather than static frame animation. As before, the program builds
- the background in the upper left corner of video page 1, but it then uses
- fg_transfer to copy it to the center of the visual video page. The for loop
- builds each frame as it is needed and also copies it to the center of the
- visual page. Again, fg_waitfor creates the necessary pause between frames.
-
- Example 10-5.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- #define VISUAL 0
- #define HIDDEN 1
-
- void main()
- {
- int new_mode, old_mode;
- int frame, offset;
- int i;
-
- /* initialize the video environment */
-
- new_mode = fg_bestmode(320,200,2);
- if (new_mode < 0 || new_mode == 12) {
-
- Chapter 10: Animation Techniques 195
-
- printf("This program requires a 320 ");
- printf("x 200 color graphics mode.\n");
- exit(1);
- }
- old_mode = fg_getmode();
- fg_setmode(new_mode);
- fg_allocate(HIDDEN);
-
- /* draw the background in the upper left corner */
-
- fg_setpage(HIDDEN);
- fg_setcolor(1);
- fg_rect(0,95,0,49);
- fg_setcolor(15);
- fg_move(48,25);
- fg_ellipse(20,20);
-
- /* copy it to the center of the visual page */
-
- fg_transfer(0,95,0,49,112,124,HIDDEN,VISUAL);
-
- /* slide the object across the background three times */
-
- fg_setcolor(10);
- for (i = 0; i < 36; i++) {
- frame = i % 12;
- offset = 10 * frame - 10;
- fg_transfer(0,95,20,29,112,105,HIDDEN,HIDDEN);
- fg_rect(112+offset,131+offset,96,105);
- fg_transfer(112,207,96,105,112,105,HIDDEN,VISUAL);
- fg_waitfor(2);
- }
-
- /* restore the original video mode and return to DOS */
-
- fg_freepage(HIDDEN);
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- Two items in example 10-5 merit further discussion. First, we have
- chosen our workspace on page 1 so it uses the same screen space coordinates
- as the image area on the visual page. This is not necessary unless you are
- using the fg_restore routine instead of fg_transfer. Second, the program can
- use the faster fg_rect routine in place of fg_clprect. It can do this
- because even though the object will extend beyond the workspace limits, we
- only transfer the workspace itself. However, for this to function properly,
- the workspace's horizontal limits must fall on byte boundaries.
-
- Note too that we do not need to transfer the entire frame during the
- animation sequence. In example 10-5, we know the vertical extremes of the
- moving image are y=96 and y=105, so we only transfer 10 rows instead of the
- entire frame. We could similarly compute the x extremes for each frame and
- only transfer the necessary portion. Recall, however, that fg_transfer
- extends the horizontal coordinates to byte boundaries, so we may copy a few
- extra pixels as well. This may or may not affect the animation sequence.
- 196 Fastgraph User's Guide
-
- Again, the problem is eliminated if you align your workspace on byte
- boundaries.
-
- When we use dynamic frame animation, it is easy to change the number of
- frames in the animation sequence. Suppose we wish to produce a smoother
- animation by increasing the number of frames from 12 to 24. This means the
- object will move in increments of five pixels instead of ten. The only
- changes needed are to double the number of loop iterations, modify the
- calculations for the frame number and offset values as shown below, and
- reduce the fg_waitfor pause from 2 to 1.
-
- frame = i % 24;
- offset = 5 * frame - 10;
-
- Compare this to all the changes that would be necessary if we were using
- static frame animation.
-
-
- Page Flipping
-
- Page flipping is a variation of frame animation in which you construct
- images on off-screen video pages and then repetitively make those pages the
- visual page. We can further divide the page flipping technique into static
- and dynamic variants, as we did with frame animation.
-
- In static page flipping, we construct the entire animation sequence in
- advance, with one frame per video page. Once this is done, we can display
- each frame by using the fg_setvpage routine to switch instantly from one
- video page to another. Although this produces a smooth, flicker-free
- animation, we cannot carry the sequence very far before running out of video
- pages (and hence animation frames).
-
- In dynamic page flipping, we construct each animation frame when it is
- needed. As in static page flipping, we construct each frame on a separate
- video page. However, as example 10-6 demonstrates, we only need three video
- pages to produce the animation sequence, regardless of the number of frames
- in the sequence. Two of the three video pages will alternate as the visual
- page, while the remaining video page keeps a copy of the background.
-
- Example 10-6, which performs an animation sequence similar to examples
- 10-4 and 10-5, illustrates dynamic frame animation in the 320 by 200 EGA
- graphics video mode (mode 13). The program begins by displaying the
- background on video page 2. Video pages 0 and 1 will alternate as the visual
- page; the page that is not the visual page is called the hidden page. We
- start with page 0 as the visual page, and hence page 1 as the hidden page.
- To build each frame, the program uses fg_transfer to copy the background from
- page 2 to the hidden page and then uses fg_clprect to display the animated
- object at the correct position on the hidden page. After this, it displays
- the next frame by using fg_setvpage to make the hidden page the visual page.
- Before beginning the next iteration, the program toggles the hidden page
- number in preparation for the next frame.
-
- Example 10-6.
-
- #include <fastgraf.h>
- #include <stdio.h>
-
- Chapter 10: Animation Techniques 197
-
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int old_mode;
- int hidden;
- int x;
-
- /* initialize the video environment */
-
- if (testmode(fg_13,3) == 0) {
- printf("This program requires EGA.\n");
- exit(1);
- }
- old_mode = fg_getmode();
- fg_setmode(13);
-
- /* draw the background on page two */
-
- fg_setpage(2);
- fg_setcolor(1);
- fg_rect(0,319,0,199);
- fg_setcolor(15);
- fg_move(160,100);
- fg_ellipse(20,20);
-
- /* slide the object across the screen */
-
- hidden = 1;
- setcolor(10);
- for (x = -10; x < 320; x+=4) {
- fg_setpage(hidden);
- fg_transfer(0,319,0,199,0,199,2,hidden);
- fg_clprect(x,x+19,96,105);
- fg_setvpage(hidden);
- hidden = 1 - hidden;
- fg_waitfor(1);
- }
-
- /* restore the original video mode and return to DOS */
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- A problem with either page flipping technique arises if we use virtual
- video pages. Page flipping relies on the fact that changing the visual page
- number occurs instantly, which is exactly what happens when we use physical
- video pages. However, such is not the case with virtual or logical pages
- because Fastgraph must copy the entire page contents into video memory.
- While this occurs quite rapidly, it is not instantaneous, and its effects are
- immediately apparent on the animation.
- 198 Fastgraph User's Guide
-
-
- Summary of Animation Techniques
-
- This chapter has presented five animation techniques: simple animation,
- XOR animation, static frame animation, dynamic frame animation, and page
- flipping. The following table summarizes their behavior.
-
- technique destructive? flicker-free?
-
- simple yes no
- XOR no no
- static frame no yes
- dynamic frame no yes
- page flipping no yes
-
- Simple animation and XOR animation are elementary techniques that are seldom
- used once you master frame animation and page flipping.
-
- As stated at the beginning of this chapter, the simple examples
- presented here serve as the basis for understanding the mechanics of the
- animation techniques we have discussed. In "real world" programs, you'll
- typically want to display an image using the fg_drwimage or fg_drawmap
- routines instead using rudimentary images such as the rectangles in our
- examples. A helpful rule is to use pixel run maps (displayed by fg_dispfile,
- fg_display, or fg_displayp) for both backgrounds and moving objects, and then
- use fg_getimage or fg_getmap to retrieve the moving objects as bit-mapped
- images for later display. Of course, it is desirable to do this "behind the
- scenes" work on video pages other than the visual page.
-
-
- Chapter 11
-
- Special Effects
- 200 Fastgraph User's Guide
-
-
- Overview
-
- This chapter will discuss the Fastgraph routines that help produce
- special visual effects. These include the ability to dissolve the screen
- contents in small increments, scroll areas of the screen, and change the
- physical origin of the screen. The accompanying example programs illustrate
- how to use these routines to produce some interesting effects.
-
-
- Screen Dissolving
-
- Screen dissolving is the process of replacing the entire screen contents
- in random small increments instead of all at once. Fastgraph includes two
- routines, fg_fadeout and fg_fadein, for this purpose. The fg_fadeout routine
- incrementally replaces the visual page contents with pixels of the current
- color, while fg_fadein incrementally replaces the visual page contents with
- the hidden page contents (that is, the page defined in the most recent call
- to fg_sethpage). Both routines accept an integer argument that defines the
- delay between each incremental replacement. A value of zero means to perform
- the replacement as quickly as possible, while 1 is slightly slower, 2 is
- slower yet, and so forth. The fg_fadeout and fg_fadein routines have no
- effect in text video modes.
-
- Example 11-1 shows how to use the fg_fadeout routine. The program,
- which runs in any graphics video mode, first fills the screen with a
- rectangle of color 2. After waiting for a keystroke, the program
- incrementally replaces the screen contents with pixels of color 15 (the
- current color index when fg_fadeout is called). After another keystroke, the
- program exits gracefully.
-
- Example 11-1.
-
- #include <fastgraf.h>
- void main(void);
-
- void main()
- {
- int old_mode;
-
- old_mode = fg_getmode();
- fg_setmode(fg_automode());
-
- fg_setcolor(2);
- fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
- fg_waitkey();
-
- fg_setcolor(15);
- fg_fadeout(0);
- fg_waitkey();
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
- Example 11-2 shows how to use the fg_fadein routine in any 320 by 200
- color graphics video mode. The program first fills the screen with a
- Chapter 11: Special Effects 201
-
- rectangle of color 2 and then fills video page 1 with a rectangle of color 1.
- After waiting for a keystroke, the program incrementally transfers the
- contents of page 1 to the visual page. After the call to fg_fadein, both
- page 0 (the visual page) and page 1 (the hidden page) will contain rectangles
- of color 1 that fill the entire video page. Finally, the program waits for
- another keystroke before returning to DOS.
-
- Example 11-2.
-
- #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_allocate(1);
- fg_sethpage(1);
-
- fg_setcolor(2);
- fg_rect(0,319,0,199);
- fg_setpage(1);
- fg_setcolor(1);
- fg_rect(0,319,0,199);
- fg_waitkey();
-
- fg_fadein(0);
- fg_waitkey();
-
- fg_freepage(1);
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- You also can produce some appealing visual effects by replacing the
- screen contents in a non-random fashion using the fg_restore or fg_transfer
- routines. For example, you could copy the hidden page contents to the visual
- page with a through a series of concentric rectangular areas, each slightly
- larger than the previous, until the entire screen is copied. Another
- interesting effect is to start around the screen perimeter and proceed toward
- the screen center, thus producing a "snake-like" effect. Experimenting with
- such techniques may reveal other effects that suit your application.
- 202 Fastgraph User's Guide
-
-
- Scrolling
-
- Another useful effect is scrolling, and Fastgraph provides a routine
- that performs vertical scrolling within a given region of the active video
- page. The fg_scroll routine scrolls a region defined in screen space or
- character space. It can scroll up or down and offers two types of scrolling:
- circular and end-off. In circular scrolling, rows that scroll off one edge
- of the defined region appear at its opposite edge. In end-off scrolling,
- such rows are simply wind up above or below the scrolling area. The
- following diagrams illustrate the two types of scrolling.
-
- end-off scrolling circular scrolling
-
- before after before after
-
- C B
- A A
-
- A A
- B B
-
- In these diagrams, the area bounded by the double lines is the scrolling
- region, as specified in the call to fg_scroll. Also, the scrolling direction
- is assumed to be down (that is, toward the bottom of the screen), and the
- number of rows to scroll is the height of the area designated B. The number
- of rows to scroll is often called the scrolling increment.
-
- For the end-off scrolling example, the scrolling operation transfers
- region A downward so part of it is copied into area B. The area C (which is
- the same size as area B) at the top of the scrolling region is filled with
- pixels of the current color index (as defined in the most recent call to
- fg_setcolor), and the original contents of area B are lost. The circular
- scrolling example also copies region A downward into the original area B.
- Unlike end-off scrolling, however, circular scrolling preserves the area B by
- copying it to the opposite edge of the scrolling region.
-
- The fg_scroll routine takes six arguments. The first four define the
- scrolling region in the order minimum x coordinate, maximum x coordinate,
- minimum y coordinate, and maximum y coordinate. In graphics video modes, the
- x coordinates are extended by byte boundaries (see page 174) if needed. The
- fifth argument is the scrolling increment. It specifies the number of rows
- to scroll. If it is positive, the scrolling direction is toward the bottom
- of the screen; if it is negative, the scrolling direction is toward the top
- of the screen. The sixth and final argument specifies the scroll type. If
- this value is zero, the scroll will be circular; if it is any other value,
- the scroll will be end-off. If the scroll type is circular, Fastgraph will
- use the hidden page (as defined in the most recent call to fg_sethpage) as a
- workspace (more specifically, the area bounded by the scrolling region
- extremes on the hidden page will be used). We'll now present three example
- programs that use the fg_scroll routine.
-
- Example 11-3 runs in any 320 by 200 graphics video mode. The program
- displays two lines of text ("line one" and "line two") in the upper left
- corner of the screen against a white background. It then uses the fg_scroll
- routine to move the second line down four pixel rows using an end-off scroll.
- After waiting for a keystroke, the program again uses fg_scroll to move the
- Chapter 11: Special Effects 203
-
- text back to its original position. Note especially how the fg_setcolor
- routine appears before the first call to fg_scroll to replace the "scrolled
- off" rows with pixels of color 15, thus preserving the white background.
-
- Example 11-3.
-
- #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(15);
- fg_rect(0,319,0,199);
- fg_setcolor(10);
- fg_text("line one",8);
- fg_locate(1,0);
- fg_text("line two",8);
- fg_waitkey();
-
- fg_setcolor(15);
- fg_scroll(0,63,8,15,4,1);
- fg_waitkey();
- fg_scroll(0,63,12,19,-4,1);
- fg_waitkey();
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
- Example 11-4 is similar to example 11-3, but it runs in the 80-column
- color text mode (mode 3). In text modes, we cannot scroll half a character
- row (four pixels) as in example 11-3, so the program scrolls the minimum one
- row instead.
-
- Example 11-4.
-
- #include <fastgraf.h>
- void main(void);
-
- void main()
- {
- int old_mode;
-
- 204 Fastgraph User's Guide
-
- old_mode = fg_getmode();
- fg_setmode(3);
- fg_cursor(0);
-
- fg_setcolor(7);
- fg_rect(0,79,0,24);
- fg_setattr(10,7,0);
- fg_text("line one",8);
- fg_locate(1,0);
- fg_text("line two",8);
- fg_waitkey();
-
- fg_setcolor(7);
- fg_scroll(0,7,1,1,1,1);
- fg_waitkey();
- fg_scroll(0,7,2,2,-1,1);
- fg_waitkey();
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
- Example 11-5, the final scrolling example, demonstrates a circular
- scroll. The program runs in any 320 by 200 color graphics video mode; note
- the use of video page 1 for the workspace required when the fg_scroll routine
- performs a circular scroll. The program first fills the screen with a light
- blue rectangle (cyan in CGA), displays a smaller white rectangle in the
- center of the screen, and then uses fg_move, fg_draw, and fg_paint to display
- a light green star (magenta in CGA) within the white rectangle. The program
- executes a while loop to scroll the star upward in four pixel increments.
- Because the scroll is circular, rows of the star that "scroll off" the top
- edge of the white rectangle (whose height is the same as the scrolling
- region) reappear at its bottom edge. The use of fg_waitfor within the loop
- simply slows down the scroll. The scrolling continues until any key is
- pressed.
-
- Example 11-5.
-
- #include <conio.h>
- #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);
-
- Chapter 11: Special Effects 205
- fg_allocate(1);
- fg_sethpage(1);
-
- fg_setcolor(9);
- fg_rect(0,319,0,199);
- fg_setcolor(15);
- fg_rect(132,188,50,150);
-
- fg_setcolor(10);
- fg_move(160,67);
- fg_draw(175,107);
- fg_draw(140,82);
- fg_draw(180,82);
- fg_draw(145,107);
- fg_draw(160,67);
- fg_paint(160,77);
- fg_paint(150,87);
- fg_paint(160,87);
- fg_paint(170,87);
- fg_paint(155,97);
- fg_paint(165,97);
-
- while (kbhit() == 0) {
- fg_waitfor(1);
- fg_scroll(136,184,50,150,-4,0);
- }
- fg_waitkey();
-
- fg_freepage(1);
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- Changing the Screen Origin
-
- Fastgraph includes two routines for changing the screen origin. By
- changing the screen origin, we simply mean defining the (x,y) coordinate of
- the upper left corner of the display area. The fg_pan routine performs this
- function in screen space, while the fg_panw routine does in world space.
- Neither routine changes the graphics cursor position.
-
- Each of these routines has two arguments that specify the x and y
- coordinates of the screen origin. For the fg_pan routine, the arguments are
- integer quantities. For the fg_panw routine, they are floating point
- quantities.
-
- In the native EGA and VGA graphics modes (modes 13 through 18), you can
- set the screen origin to any (x,y) coordinate position (that is, to any
- pixel). In the other graphics modes, certain restrictions exist, as imposed
- by specific video hardware. These constraints limit the coordinate positions
- that can be used as the screen origin. Fastgraph compensates for these
- restrictions by reducing the specified x and y coordinates to values that are
- acceptable to the current video mode, as shown in the following table.
- 206 Fastgraph User's Guide
-
-
- x will be reduced y will be reduced
- video mode to a multiple of: to a multiple of:
-
- 4, 5 8 2
- 6 16 2
- 9 4 4
- 11 8 4
- 12 4 2 or 3
- 19 to 23 4 1
-
- For example, in modes 4 and 5, the x coordinate will be reduced to a multiple
- of 8 pixels, and the y coordinate will be reduced to a multiple of 2 pixels.
- In the Hercules low resolution mode (mode 12), the y coordinate reduction
- depends on whether or not the specified pixel row is scan doubled.
-
- Example 11-6 shows a useful effect that can be made with the fg_pan or
- fg_panw routines. This program uses the fg_automode routine to select a
- video mode and then draws an unfilled rectangle in color 15 (bright white).
- The top and bottom sides of the rectangle are intentionally drawn just
- smaller than the physical screen size. After waiting for a keystroke, the
- program uses a for loop to make the rectangle jiggle up and down. The
- rectangle moves because the fg_pan routine is called inside the loop to
- switch the screen origin between the rectangle's upper left corner and the
- original origin. Note also the use of the fg_waitfor routine to cause slight
- delays after each call to fg_pan. If we didn't use fg_waitfor, the changing
- of the origin would occur so rapidly we wouldn't notice the effect. Finally,
- the program restores the original video mode and screen attributes before
- returning to DOS.
-
- Example 11-6.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- #define DELAY 2
- #define JUMP 4
-
- void main()
- {
- int i;
- int old_mode;
-
- old_mode = fg_getmode();
- fg_setmode(fg_automode());
-
- fg_setcolor(15);
- fg_move(0,JUMP);
- fg_draw(fg_getmaxx(),JUMP);
- fg_draw(fg_getmaxx(),fg_getmaxy()-JUMP);
- fg_draw(0,fg_getmaxy()-JUMP);
- fg_draw(0,JUMP);
- fg_waitkey();
-
- Chapter 11: Special Effects 207
-
- for (i = 0; i < 6; i++) {
- fg_pan(0,JUMP);
- fg_waitfor(DELAY);
- fg_pan(0,0);
- fg_waitfor(DELAY);
- }
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
- The real power of the fg_pan routine becomes clear when it is used with
- the fg_resize routine to perform smooth panning. Recall from Chapter 7 that
- fg_resize changes the video page dimensions in native EGA graphics modes
- (modes 13 through 16), native VGA graphics modes (modes 17 and 18), and the
- extended VGA graphics modes (modes 20 through 23). We'll now present an
- example that shows how to use these two routines to perform panning in the
- low-resolution EGA graphics mode (mode 13). The method it uses also would
- work in any mode that supports video page resizing.
-
- Example 11-7 begins by establishing the video mode and then immediately
- calls fg_resize to increase the video page size to 640 x 400 pixels. Thus,
- the video page is now four times its original size. Following this, the
- program fills the page (the entire page, not just what is displayed) with a
- bright green rectangle with a white border around it. It then displays the
- message "Press arrow keys to pan" as close as possible to the center of the
- page.
-
- The main part of the program is a loop that accepts keystrokes and then
- calls fg_pan to perform the panning one pixel at a time. When you press any
- of the four arrow keys, the program adjusts the x and y coordinates for the
- screen origin as directed. For example, pressing the up arrow key scrolls
- the screen upward one pixel. Note that when we reach the edge of the video
- page, the program prevents further scrolling in that direction. This process
- continues until you press the Esc key, at which time the program restores the
- original video mode and screen attributes before exiting.
-
- Example 11-7.
-
- #include <fastgraf.h>
- void main(void);
-
- void main()
- {
- unsigned char key, aux;
- int old_mode;
- int x, y;
-
- old_mode = fg_getmode();
- fg_setmode(13);
- fg_resize(640,400);
-
- fg_setcolor(2);
- fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
- fg_setcolor(15);
- fg_box(0,fg_getmaxx(),0,fg_getmaxy());
-
- 208 Fastgraph User's Guide
-
- fg_locate(24,28);
- fg_text("Press arrow keys to pan.",24);
-
- x = 0;
- y = 0;
-
- do {
- fg_getkey(&key,&aux);
- if (aux == 72 && y < 200)
- y++;
- else if (aux == 75 && x < 320)
- x++;
- else if (aux == 77 && x > 0)
- x--;
- else if (aux == 80 && y > 0)
- y--;
- fg_pan(x,y);
- } while (key != 27);
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
-
- Summary of Special Effects 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.
-
- FG_FADEIN incrementally replaces the visual page contents with the
- hidden page contents. This routine has no effect in text video modes.
-
- FG_FADEOUT incrementally replaces the visual page contents with pixels
- of the current color. This routine has no effect in text video modes.
-
- FG_PAN changes the screen origin (the upper left corner of the screen)
- to the specified screen space coordinates. This routine has no effect in
- text video modes.
-
- FG_PANW is the world space version of the fg_pan routine.
-
- FG_RESIZE changes the dimensions of a video page in EGA and VGA graphics
- modes.
-
- FG_SCROLL vertically scrolls a region of the active video page. The
- scrolling may be done either up or down, using either an end-off or circular
- method. Circular scrolling uses part of the hidden page as a temporary
- workspace.
-
-
- Chapter 12
-
- Input Device Support
- 210 Fastgraph User's Guide
-
-
- Overview
-
- The selection of application input devices is an important part of
- designing a program for the IBM PC and PS/2 family of systems. The keyboard
- and mouse are very popular, and in fact more and more applications,
- especially those that use a graphical interface, actually require a mouse to
- use the product. Another input device, primarily used in entertainment
- software, is the joystick. Although not as popular as the mouse, the
- joystick nevertheless can simplify the use of certain applications.
- Fastgraph provides support for these three types of input devices, and this
- chapter will discuss this in detail.
-
-
- Keyboard Support
-
- Fastgraph's keyboard support includes routines to read keystrokes, check
- the state of certain keys, and set the state of these keys. These routines
- are independent of the other parts of Fastgraph and thus do not require that
- you call fg_setmode. All keyboard-related routines work in text and graphics
- video modes.
-
- The IBM PC and PS/2 keyboards produce two types of character codes --
- standard codes and extended codes (extended codes are sometimes called
- auxiliary codes). The standard codes correspond to the 128 characters in the
- ASCII character set. In general, pressing keys on the main part of the
- keyboard, or on the numeric keypad with NumLock turned on, will generate a
- standard code. The 128 extended codes are specific to the IBM PC and PS/2
- keyboards. Some common keystrokes that produce extended codes are keys on
- the numeric keypad with NumLock turned off, the function keys, or pressing
- Alt with another key. The following tables show the standard and extended
- keyboard codes.
-
- Table of standard keyboard codes
-
- key code key code key code key code
-
- (none) 0 space 32 @ 64 ` 96
- Ctrl+A 1 ! 33 A 65 a 97
- Ctrl+B 2 " 34 B 66 b 98
- Ctrl+C 3 # 35 C 67 c 99
- Ctrl+D 4 $ 36 D 68 d 100
- Ctrl+E 5 % 37 E 69 e 101
- Ctrl+F 6 & 38 F 70 f 102
- Ctrl+G 7 ' 39 G 71 g 103
- Ctrl+H 8 ( 40 H 72 h 104
- Ctrl+I 9 ) 41 I 73 i 105
- Ctrl+J 10 * 42 J 74 j 106
- Ctrl+K 11 + 43 K 75 k 107
- Ctrl+L 12 , 44 L 76 l 108
- Ctrl+M 13 - 45 M 77 m 109
- Ctrl+N 14 . 46 N 78 n 110
- Ctrl+O 15 / 47 O 79 o 111
- Ctrl+P 16 0 48 P 80 p 112
- Ctrl+Q 17 1 49 Q 81 q 113
- Ctrl+R 18 2 50 R 82 r 114
-
- Chapter 12: Input Device Support 211
-
- Ctrl+S 19 3 51 S 83 s 115
- Ctrl+T 20 4 52 T 84 t 116
- Ctrl+U 21 5 53 U 85 u 117
- Ctrl+V 22 6 54 V 86 v 118
- Ctrl+W 23 7 55 W 87 w 119
- Ctrl+X 24 8 56 X 88 x 120
- Ctrl+Y 25 9 57 Y 89 y 121
- Ctrl+Z 26 : 58 Z 90 z 122
- Ctrl+[ 27 ; 59 [ 91 { 123
- Ctrl+\ 28 < 60 \ 92 | 124
- Ctrl+] 29 = 61 ] 93 } 125
- Ctrl+^ 30 > 62 ^ 94 ~ 126
- Ctrl+- 31 ? 63 _ 95 Ctrl+BS 127
-
-
- Table of extended keyboard codes
-
- code key
-
- 3 Ctrl+@
- 15 Shift+Tab (back tab)
- 16-25 Alt+Q to Alt+P (top row of letters)
- 30-38 Alt+A to Alt+L (middle row of letters)
- 44-50 Alt+Z to Alt+M (bottom row of letters)
- 59-68 F1 to F10
- 71 Home
- 72 up arrow
- 73 PgUp
- 75 left arrow
- 77 right arrow
- 79 End
- 80 down arrow
- 81 PgDn
- 82 Ins
- 83 Del
- 84-93 Shift+F1 to Shift+F10
- 94-103 Ctrl+F1 to Ctrl+F10
- 104-113 Alt+F1 to Alt+F10
- 114 Ctrl+PrtSc
- 115 Ctrl+left arrow
- 116 Ctrl+right arrow
- 117 Ctrl+End
- 118 Ctrl+PgDn
- 119 Ctrl+Home
- 120-131 Alt+1 to Alt+= (top row of keys)
- 132 Ctrl+PgUp
-
- In addition, four keys generate the same standard codes as other control key
- combinations. These keys are:
-
- key same as code
-
- Backspace Ctrl+H 8
- Tab Ctrl+I 9
- Enter Ctrl+M 13
- Escape Ctrl+[ 27
-
- 212 Fastgraph User's Guide
-
- The CapsLock, NumLock, and ScrollLock keys do not generate a standard or
- extended code when pressed. Instead, they toggle between off and on states.
-
- Reading Keystrokes
-
- When you press a key or key combination, the standard or extended code
- representing that keystroke is stored in the ROM BIOS keyboard buffer. This
- buffer can hold up to 16 keystrokes and thus provides a type-ahead
- capability. Fastgraph includes three routines for reading keystroke
- information from the keyboard buffer. The fg_getkey routine reads the next
- item in the keyboard buffer if one is available (that is, if a key has been
- pressed). If the keyboard buffer is empty (meaning no key has been pressed),
- fg_getkey waits for a keystroke and then reports information about it.
- Another routine, fg_intkey, reads the next keystroke from the keyboard buffer
- if one is available. If the keyboard buffer is empty, fg_intkey immediately
- returns and reports this condition. The fg_intkey routine is useful when a
- program must continue performing a task until a key is pressed. We've
- already seen the third routine, fg_waitkey, which flushes the keyboard buffer
- and then waits for another keystroke. Unlike fg_getkey and fg_intkey,
- fg_waitkey does not return any keystroke information. It is most useful in
- "press any key to continue" situations.
-
- Both the fg_getkey and fg_intkey routines require two one-byte arguments
- passed by reference. If the keystroke is represented by a standard keyboard
- code, fg_getkey and fg_intkey return its code in the first argument and set
- the second argument to zero. Similarly, if the keystroke generates an
- extended code, the routines return its code in the second argument and set
- the first argument to zero. If the fg_intkey routine detects an empty
- keyboard buffer, it sets both arguments to zero.
-
- Example 12-1 is a simple program that uses the fg_getkey routine. It
- solicits keystrokes and then displays the two values returned by fg_getkey,
- one of which will always be zero. The variable key receives the key's
- standard code, while aux receives its extended code. Note that fg_getkey is
- the only Fastgraph routine in the program; this can be done because the
- keyboard support routines are logically independent from the rest of
- Fastgraph. The program returns to DOS when you press the Escape key.
-
- Example 12-1.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- #define ESC 27
-
- void main()
- {
- unsigned char key, aux;
-
- do {
- fg_getkey(&key,&aux);
- printf("key = %3d aux = %3d\n",key,aux);
- }
- while (key != ESC);
- }
-
- Chapter 12: Input Device Support 213
-
- Example 12-2 reads keystrokes using the fg_intkey routine at half-second
- intervals (18 fg_waitfor units equals one second). As in the previous
- example, the program displays the standard and extended codes for each
- keystroke. However, example 12-2 will continuously execute the while loop
- even if no keystrokes are available, in which case the key and aux values
- will both be zero. The program returns to DOS when you press the Escape key.
-
- Example 12-2.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- #define ESC 27
-
- void main()
- {
- unsigned char key, aux;
-
- do {
- fg_waitfor(9);
- fg_intkey(&key,&aux);
- printf("key = %3d aux = %3d\n",key,aux);
- }
- while (key != ESC);
- }
-
-
- When you use fg_intkey in a "tight" loop that does little else, you
- should force a small delay within the loop by calling fg_waitfor as in
- example 12-2. Typically a delay of one or two clock ticks is enough.
- Without this delay, the BIOS may not be able to handle all keyboard activity,
- and thus some keystrokes may not be available to your program.
-
-
- Testing and Setting Key States
-
- As mentioned earlier, the CapsLock, NumLock, and ScrollLock keys do not
- generate a standard or extended code when pressed but instead toggle between
- off and on states. Fastgraph includes routines for checking the state of
- these keys, as well as setting the state of the CapsLock and NumLock keys.
-
- The Fastgraph routines fg_capslock, fg_numlock, and fg_scrlock
- respectively read the state of the CapsLock, NumLock, and ScrollLock keys.
- Each routine has no arguments and returns the key state as its function
- value. A return value of 0 means the associated key is in the off state,
- while 1 indicates the key is in the on state. If the keyboard does not have
- a ScrollLock key, fg_scrlock considers the key off and returns a value of
- zero.
-
- Example 12-3 is a simple program that uses the fg_capslock, fg_numlock,
- and fg_scrlock routines to print messages describing the current state of
- these three keys.
- 214 Fastgraph User's Guide
-
- Example 12-3.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- if (fg_capslock())
- printf("CapsLock is on.\n");
- else
- printf("CapsLock is off.\n");
-
- if (fg_numlock())
- printf("NumLock is on.\n");
- else
- printf("NumLock is off.\n");
-
- if (fg_scrlock())
- printf("ScrollLock is on.\n");
- else
- printf("ScrollLock is off.\n");
- }
-
- You also can set the state of the CapsLock and NumLock keys within a
- program. Fastgraph includes two routines, fg_setcaps and fg_setnum, for this
- purpose. Each routine requires an integer argument that specifies the new
- key state. If the argument value is 0, the key will be turned off; if the
- value is 1, the key will be turned on. Example 12-4 uses fg_setcaps and
- fg_setnum to turn off CapsLock and NumLock.
-
- Example 12-4.
-
- #include <fastgraf.h>
- void main(void);
-
- void main()
- {
- fg_setcaps(0);
- fg_setnum(0);
- }
-
- On most keyboards, changing key states with fg_setcaps or fg_setnum also
- will change the keyboard state light to reflect the new key state. However,
- some older keyboards, especially when used on PC, PC/XT, or Tandy 1000
- systems, do not update the state light. This makes the state light
- inconsistent with the true key state.
-
-
- Mouse Support
-
- The mouse is a very popular input and pointing device, especially in
- graphically-oriented programs. Fastgraph contains several routines to
- support mice. These routines perform such tasks as mouse initialization,
- controlling and defining the mouse cursor, and reporting information about
- the mouse position and button status.
- Chapter 12: Input Device Support 215
-
- The underlying software that controls the mouse is called the mouse
- driver. Fastgraph's mouse support routines provide a high-level interface to
- this driver. The Microsoft Mouse and its accompanying mouse driver have
- become an industry standard, and other manufacturers of mice have also made
- their mouse drivers Microsoft compatible. For this reason, the Fastgraph
- mouse support routines assume you are using a Microsoft or compatible mouse
- driver.
-
- Unfortunately, not all mouse drivers are created equal. That is, some
- drivers are not Microsoft compatible, even though they may be advertised as
- such. In some cases, these incompatibilities are rather trivial, but others
- are significant. For example, early versions of some third party mouse
- drivers had real problems in the EGA graphics modes. The Microsoft mouse
- driver, the Logitech mouse driver (version 3.2 or above), and the DFI mouse
- driver (version 3.00 or above) are known to work well with Fastgraph's mouse
- support routines. Any other Microsoft compatible mouse driver also should
- work properly.
-
-
- Initializing the Mouse
-
- There are two steps required to use Fastgraph's mouse support routines
- within an application program. First, you must install the mouse driver.
- This is done before running the application, typically by entering the
- command MOUSE at the DOS command prompt. Second, you must use the Fastgraph
- routine fg_mouseini to initialize the mouse within the program.
-
- The fg_mouseini routine has no arguments and returns a "success or
- failure" indicator as its function value. If the return value is -1, it
- means fg_mouseini could not initialize the mouse (either because the mouse
- driver is not installed, or the driver is installed but the mouse is
- physically disconnected). The fg_mouseini routine also will return -1 when
- used in the extended VGA graphics video modes (modes 20 through 23) because
- there is no mouse support available in these video modes. If fg_mouseini
- returns a positive integer value, then the mouse initialization was
- successful. The value itself indicates the number of buttons (either 2 or 3)
- on the mouse. If you don't call fg_mouseini, or if fg_mouseini can't
- initialize the mouse, none of Fastgraph's other mouse support routines will
- have any effect.(3)
-
- Example 12-5 illustrates how to initialize the mouse. Unlike the
- keyboard support routines, Fastgraph's mouse support routines require that
- fg_setmode first be called. In this example, we simply pass fg_setmode the
- value -1 to initialize Fastgraph for whatever video mode is in effect when we
- run the program. The program then calls fg_mouseini and prints a message
- indicating whether or not the initialization was successful. If it was, the
- message includes the number of buttons on the mouse.
-
- Example 12-5.
-
- #include <fastgraf.h>
-
- ____________________
- (3) If you use another mouse library or communicate directly with the
- mouse driver, you must still call fg_mouseini if your program runs in modes
- 13 through 18. Otherwise, Fastgraph won't know that your program is using
- a mouse and may display graphics incorrectly.
- 216 Fastgraph User's Guide
-
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- int status;
-
- fg_setmode(-1);
- status = fg_mouseini();
-
- if (status < 0)
- printf("Mouse not available.\n");
- else
- printf("%d button mouse found.\n",status);
- }
-
- You should be aware that certain mouse drivers do not fully initialize
- the mouse when a program changes video modes. This problem most frequently
- occurs when you restore the original video mode at the end of a program that
- has called fg_mouseini. When changing video modes, you must first make the
- mouse cursor invisible (this is described in the next section), change the
- video mode, and then call fg_mouseini again to initialize the mouse for the
- new video mode.
-
-
- Controlling the Mouse Cursor
-
- The mouse cursor indicates the current position of the mouse. By
- default, the cursor is a small white arrow in graphics modes and a one-
- character rectangle in text modes. After you use fg_mouseini to initialize
- the mouse, the mouse cursor is invisible. To make it visible, you must use
- the fg_mousevis routine. This routine has a single integer argument that
- defines the mouse cursor visibility. If it is 0, the mouse cursor will be
- invisible; if it is 1, the mouse cursor becomes visible.
-
- If the mouse cursor is in an area of the screen that is being updated,
- or if it moves into this area during the update process, you must make the
- mouse cursor invisible. Additionally, when performing any video output in
- the native EGA and VGA graphics modes (modes 13 through 18), you also must
- make the mouse cursor invisible. Instead of checking for these conditions,
- it is more convenient and efficient to make the mouse cursor invisible during
- all screen updates and then make it visible again when the updating is
- finished. Finally, you must make the mouse cursor invisible whenever you
- change the visual page number with fg_setvpage.
-
- After you initialize the mouse, the cursor is positioned in the center
- of the screen. Moving the mouse of course changes the cursor position, but
- you also can position the mouse cursor with the Fastgraph routine
- fg_mousemov. This routine has two arguments that specify the new horizontal
- and vertical cursor position. The position is expressed in screen space
- units for graphics modes, while it is expressed in character cells for text
- modes. The fg_mousemov routine moves the cursor whether or not it is
- visible.
-
- Sometimes it is useful to restrict the mouse cursor to a specific area
- of the screen. The Fastgraph routine fg_mouselim prevents the mouse cursor
- from moving outside the specified rectangular area. It requires four
- Chapter 12: Input Device Support 217
-
- arguments that specify the minimum horizontal coordinate, maximum horizontal
- coordinate, minimum vertical coordinate, and maximum vertical coordinate of
- this area. Again, the coordinates are expressed in screen space units for
- graphics modes and character cells for text modes.
-
- One of the most important functions of the mouse driver is to translate
- the horizontal and vertical mouse movements into a position on the screen.
- The mouse reports these movements to the mouse driver in units called mickeys
- (one mickey is about 1/200 of an inch). By default, moving the mouse 8
- mickeys in the horizontal direction moves the mouse cursor one horizontal
- pixel. Similarly, moving the mouse 16 mickeys vertically moves the cursor
- one vertical pixel. Fastgraph provides a routine named fg_mousespd that can
- change these values, which effectively allows you to control the speed at
- which the mouse cursor moves relative to the movement of the mouse itself.
- The fg_mousespd routine requires two arguments that define the number of
- mickeys required for eight pixels of mouse cursor movement. The first
- argument specifies this for the horizontal direction, and the second for the
- vertical direction.
-
- Example 12-6, which runs in any graphics mode, demonstrates the
- fg_mousevis, fg_mousemov, fg_mouselim, and fg_mousespd routines. The program
- first establishes the video mode, initializes the mouse, and fills the screen
- with a white rectangle. Next, the program calls fg_mousevis to make the
- mouse cursor visible and then calls fg_mouselim to restrict the mouse cursor
- to an area one-fourth the size of the screen, centered in the middle of the
- screen. At this point you should move the mouse cursor around the screen to
- see the effect of fg_mouselim and note the speed at which the cursor moves
- relative to the mouse itself. The program continues when you press any key.
-
- The program then uses fg_mousemov to move the mouse cursor to each
- corner of the region established by fg_mouselim. The call to fg_waitfor
- keeps the cursor in each corner for two seconds, unless you move the mouse.
- Note how the program tries to move the mouse cursor to each corner of the
- screen, but since doing so would move the cursor outside the defined region
- of movement, fg_mousemov just positions the cursor at the nearest point
- possible within this region. The last call to fg_mousemov moves the cursor
- back to the middle of the screen. After doing this, the program calls
- fg_mousespd to change the mouse cursor speed. The values passed to
- fg_mousespd (16 and 32) are twice the defaults and therefore make you move
- the mouse twice as far as before to move the mouse cursor the same distance.
- When you run the program, compare the mouse sensitivity to the original
- speed. After a keystroke, the program returns to DOS.
-
- Example 12-6.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int maxx, maxy;
- int old_mode;
-
- old_mode = fg_getmode();
-
- 218 Fastgraph User's Guide
-
- fg_setmode(fg_automode());
- if (fg_mouseini() < 0) {
- fg_setmode(old_mode);
- fg_reset();
- exit(1);
- }
-
- maxx = fg_getmaxx();
- maxy = fg_getmaxy();
- fg_setcolor(15);
- fg_rect(0,maxx,0,maxy);
-
- fg_mousevis(1);
- fg_mouselim(maxx/4,3*maxx/4,maxy/4,3*maxy/4);
- fg_waitkey();
-
- fg_mousemov(0,0);
- fg_waitfor(36);
- fg_mousemov(maxx,0);
- fg_waitfor(36);
- fg_mousemov(maxx,maxy);
- fg_waitfor(36);
- fg_mousemov(0,maxy);
- fg_waitfor(36);
- fg_mousemov(maxx/2,maxy/2);
- fg_mousespd(16,32);
- fg_waitkey();
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
-
- Reporting the Mouse Status
-
- It is obviously important to be able to track the mouse position and
- button status. The Fastgraph routines fg_mousepos and fg_mousebut enable you
- to do this.
-
- The fg_mousepos routine returns information about the current mouse
- cursor position and button status. It requires three integer arguments, all
- passed by reference. The first two arguments respectively receive the
- horizontal and vertical coordinates of the mouse cursor. These values are
- expressed in screen space units for graphics modes and character cells for
- text modes. The third argument receives a three-bit mask containing the
- button status as indicated below.
-
- bit
- number meaning
-
- 0 1 if left button pressed, 0 if not
- 1 1 if right button pressed, 0 if not
- 2 1 if middle button pressed, 0 if not
-
- Chapter 12: Input Device Support 219
-
-
- For example, if both the left and right buttons are pressed, the button
- status will be set to 3. If the mouse only has two buttons, bit 2 will
- always be zero.
-
- Another routine, fg_mousebut, is available for returning the number of
- button press or release counts that have occurred since the last check, or
- since calling fg_mouseini. Each mouse button maintains its own separate
- counters, so fg_mousebut returns this information for a specific button.
- Additionally, fg_mousebut returns the horizontal and vertical position of the
- mouse cursor at the time the specified button was last pressed or released.
-
- The fg_mousebut routine takes four integer arguments, of which the last
- three are passed by reference. The first argument specifies the button of
- interest (1 means the left button, 2 is the right button, and 3 is the middle
- button). If this value is positive, button press counts will be reported.
- If it is negative, release counts will be reported. The second, third, and
- fourth arguments respectively receive the press or release count, the
- horizontal mouse cursor position at the time of the last press or release,
- and the vertical position at that same time. If the press or release count
- is zero, the mouse cursor position is returned as (0,0). The coordinate
- positions are expressed in screen space units for graphics modes and
- character cells for text modes.
-
- Example 12-7 runs in any graphics video mode and illustrates the use of
- the fg_mousepos and fg_mousebut routines. The program first establishes the
- video mode and then initializes the mouse (the program exits if the
- initialization fails). It next fills the entire screen with a white
- rectangle and then calls fg_mousevis to make the mouse cursor visible.
-
- The main part of example 12-7 is a while loop that polls the mouse at
- three-second intervals (the call fg_waitfor(54) delays the program for three
- seconds). Within the loop, the program first uses fg_mousebut to get the
- number of times the left mouse button was pressed in the last three seconds.
- Following this, the fg_mousepos routine gets the current mouse position. The
- program then displays this information in the upper left corner of the
- screen; note how fg_mousevis is used to make the cursor invisible during
- graphics operations. The program continues until you press the right mouse
- button, checked by the call to fg_mousebut at the end of the loop.
-
- Example 12-7.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int old_mode;
- int buttons, count;
- int x, y;
- char string[25];
-
- old_mode = fg_getmode();
- fg_setmode(fg_automode());
-
- 220 Fastgraph User's Guide
-
- if (fg_mouseini() < 0) {
- fg_setmode(old_mode);
- fg_reset();
- exit(1);
- }
-
- fg_setcolor(15);
- fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
- fg_mousevis(1);
-
- do {
- fg_waitfor(54);
- fg_mousebut(1,&count,&x,&y);
- fg_mousepos(&x,&y,&buttons);
- sprintf(string,"X=%3d Y=%3d count=%4d",x,y,count);
- fg_mousevis(0);
- fg_setcolor(15);
- fg_rect(0,fg_xconvert(25),0,fg_yconvert(1));
- fg_setcolor(0);
- fg_locate(0,0);
- fg_text(string,24);
- fg_mousevis(1);
- fg_mousebut(2,&count,&x,&y);
- }
- while (count == 0);
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
-
- Defining the Mouse Cursor
-
- By default, the mouse cursor is a small white arrow in graphics modes
- and a one-character rectangle in text modes. In graphics modes, you can
- change the mouse cursor to any 16 by 16 pixel image with the Fastgraph
- routine fg_mouseptr (in the CGA four-color graphics modes, the cursor size is
- 8 by 16 pixels). You cannot change the mouse cursor shape in text modes, but
- you can use the Fastgraph routine fg_mousecur to define how it interacts with
- existing characters on the screen.
-
- Text Modes
-
- To change the mouse cursor in text modes, you must first define two 16-
- bit quantities called the screen mask and cursor mask. The following figure
- defines the format of each mask.
-
- bits meaning
-
- 0 to 7 ASCII character value
- 8 to 11 foreground color
- 12 to 14 background color
- 15 blink
-
- Chapter 12: Input Device Support 221
-
-
- Notice how this structure parallels the character and attribute bytes
- associated with each character cell. The default screen mask is 77FF hex,
- and the default cursor mask is 7700 hex.
-
- When you position the mouse over a specific character cell, the mouse
- driver uses the current screen and cursor masks to determine the mouse
- cursor's appearance. First, the mouse driver logically ANDs the screen mask
- with the existing contents of that character cell. It then XORs that result
- with the cursor mask to display the mouse cursor.
-
- For example, consider how the mouse cursor is produced in the 80-column
- color text mode (mode 3). Suppose a specific character cell contains the
- ASCII character 0 (48 decimal, 30 hex) and an attribute byte that specifies a
- white (color 15) foreground on a blue background (color 1) and does not blink
- (blink bit 0). The binary structure of the character and its attribute are:
-
- attribute character
-
- 0 001 1111 00110000
-
- Now let's see what happens when we apply the screen and cursor masks to the
- character and its attribute.
-
- attribute/character 0001 1111 0011 0000 (1F30 hex)
- default screen mask 0111 0111 1111 1111 (77FF hex)
- -------------------
- result of AND 0001 0111 0011 0000 (1730 hex)
- default cursor mask 0111 0111 0000 0000 (7700 hex)
- -------------------
- result of XOR 0110 0000 0011 0000 (6030 hex)
-
- The resulting character (30 hex) is the original character, but the new
- attribute (60 hex) represents a black foreground with a brown background and
- does not blink. As long as the mouse cursor remains positioned on this
- character cell, it would appear black on brown.
-
- When we use the default screen and cursor masks, the mouse cursor will
- always display the original character and it will not blink. The cursor
- foreground color will be 15-F, where F is the displayed character's
- foreground color. Similarly, the cursor background color will be 7-B, where
- B is the displayed character's background color. The default masks will
- virtually always produce a satisfactory mouse cursor.
-
- It is possible, however, to change the appearance of the mouse cursor in
- text modes by using your own screen and cursor masks. The Fastgraph routine
- fg_mousecur does just that. It expects two arguments, the first being the
- cursor mask and the second the screen mask. Example 12-8 demonstrates the
- use of fg_mousecur. The program displays some text and uses the default
- mouse cursor. After waiting for a keystroke, the program calls fg_mousecur
- to define a new mouse cursor. The new cursor is similar to the default
- cursor, but it displays the foreground colors in the opposite intensity as
- 222 Fastgraph User's Guide
-
- the default cursor. The program then waits for another keystroke before
- returning to DOS.
-
- Example 12-8.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int old_mode;
- int row;
-
- old_mode = fg_getmode();
- fg_setmode(3);
-
- if (fg_mouseini() < 0) {
- fg_setmode(old_mode);
- fg_reset();
- exit(1);
- }
-
- fg_setattr(7,0,0);
- fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
-
- fg_setattr(12,7,0);
- for (row = 0; row < 25; row++) {
- fg_locate(row,34);
- fg_text("example 12-8",12);
- }
-
- fg_mousevis(1);
- fg_waitkey();
- fg_mousecur(0x7FFF,0x7F00);
- fg_waitkey();
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- Graphics Modes
-
- Defining the mouse cursor in graphics video modes also requires creating
- a screen mask and cursor mask, but as one might expect, the structure of
- these masks is vastly different from for text modes. In fact, it closely
- resembles the mode-independent bit map format used by the fg_drawmap routine.
- Although their structure differs, the way the mouse driver uses the masks is
- the same as in the text modes. That is, the driver displays the mouse cursor
- by first logically ANDing video memory with the screen mask, and then XORing
- that result with the cursor mask.
-
- Let's begin by looking at the masks for the default mouse cursor in
- graphics modes. The size of each mask (and hence the mouse cursor) is 16
- pixels wide and 16 pixels high. As mentioned earlier, the default cursor is
- Chapter 12: Input Device Support 223
-
- a small white arrow with a black outline around it. Here are its screen and
- cursor masks expressed as binary values.
-
- screen cursor cursor
- mask mask appearance
-
- 1001111111111111 0000000000000000 **
- 1000111111111111 0010000000000000 *x*
- 1000011111111111 0011000000000000 *xx*
- 1000001111111111 0011100000000000 *xxx*
- 1000000111111111 0011110000000000 *xxxx*
- 1000000011111111 0011111000000000 *xxxxx*
- 1000000001111111 0011111100000000 *xxxxxx*
- 1000000000111111 0011111110000000 *xxxxxxx*
- 1000000000011111 0011111111000000 *xxxxxxxx*
- 1000000000001111 0011111000000000 *xxxxx*****
- 1000000011111111 0011011000000000 *xx*xx*
- 1000100001111111 0010001100000000 *x* *xx*
- 1001100001111111 0000001100000000 ** *xx*
- 1111110000111111 0000000110000000 *xx*
- 1111110000111111 0000000110000000 *xx*
- 1111111000111111 0000000000000000 ***
-
- The mouse driver first ANDs the screen mask with video memory at the
- mouse cursor position. This means the screen mask 1 bits leave video memory
- intact, while the 0 bits change the corresponding pixels to black. Next, the
- mouse driver XORs the result with the cursor mask. This time the cursor mask
- 0 bits leave video memory unchanged, while the 1 bits change the
- corresponding pixels to white. This produces a mouse cursor as shown above
- on the right, where a dot ( ) represents an unchanged pixel, an asterisk (*)
- a black pixel, and an x a white pixel. The following table summarizes the
- cursor appearance for all possible combinations of mask bits.
-
- screen mask bit cursor mask bit resulting cursor pixel
-
- 0 0 black
- 0 1 white
- 1 0 unchanged
- 1 1 inverted
-
- The color of an "inverted" pixel is n-k, where n is the maximum color
- number in the current video mode, and k is the color of the pixel being
- replaced. Also, "black" and "white" pixels are not necessarily these colors
- in 16-color and 256-color modes. More correctly, "black" pixels are
- displayed in the color assigned to palette 0, and "white" pixels are the
- displayed in the color assigned to palette 15. If you're using the CGA color
- modes, "black" pixels are displayed in the background color, and "white"
- pixels appear in color 3 (whose actual color is determined by the selected
- CGA palette).
-
- With an understanding of the way the default mouse cursor works in
- graphics modes, we're now ready to define our own mouse cursor. Shown below
- are the screen mask, cursor mask, and resulting appearance for a solid plus-
- shaped cursor. The hexadecimal equivalents of the binary mask values are
- also given.
- 224 Fastgraph User's Guide
-
- ----- screen mask ---- ----- cursor mask ----
- cursor
- binary hex binary hex appearance
-
- 1110000000111111 E03F 0000000000000000 0000 ...*******......
- 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*......
- 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*......
- 0000000000000111 0007 0000111110000000 0F80 ****xxxxx****...
- 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*...
- 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*...
- 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*...
- 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*...
- 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*...
- 0000000000000111 0007 0000111110000000 0F80 ****xxxxx****...
- 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*......
- 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*......
- 1110000000111111 E03F 0000000000000000 0000 ...*******......
- 1111111111111111 FFFF 0000000000000000 0000 ................
- 1111111111111111 FFFF 0000000000000000 0000 ................
- 1111111111111111 FFFF 0000000000000000 0000 ................
-
- If we wanted to make the mouse cursor hollow rather than solid, the masks and
- resulting cursor appearance would look like this.
-
- ----- screen mask ---- ----- cursor mask ----
- cursor
- binary hex binary hex appearance
-
- 1110000000111111 E03F 0000000000000000 0000 ...*******......
- 1110111110111111 EFBF 0000000000000000 0000 ...*.....*......
- 1110111110111111 EFBF 0000000000000000 0000 ...*.....*......
- 0000111110000111 0F87 0000000000000000 0000 ****.....****...
- 0111111111110111 7FF7 0000000000000000 0000 *...........*...
- 0111111111110111 7FF7 0000000000000000 0000 *...........*...
- 0111111111110111 7FF7 0000001000000000 0200 *.....x.....*...
- 0111111111110111 7FF7 0000000000000000 0000 *...........*...
- 0111111111110111 7FF7 0000000000000000 0000 *...........*...
- 0000111110000111 0F87 0000000000000000 0000 ****.....****...
- 1110111110111111 EFBF 0000000000000000 0000 ...*.....*......
- 1110111110111111 EFBF 0000000000000000 0000 ...*.....*......
- 1110000000111111 E03F 0000000000000000 0000 ...*******......
- 1111111111111111 FFFF 0000000000000000 0000 ................
- 1111111111111111 FFFF 0000000000000000 0000 ................
- 1111111111111111 FFFF 0000000000000000 0000 ................
-
- Note that the center bit defined in the cursor mask causes the corresponding
- pixel in video memory to be inverted.
-
- There is one more item needed to define a graphics mode mouse cursor
- completely. That item is the hot spot, or the actual screen position used or
- reported by the mouse driver. For the plus-shaped cursors just constructed,
- it would be sensible to define the hot spot in the center of the plus. The
- hot spot is specified relative to the upper left corner of the cursor, so its
- position within the cursor would be (6,6) -- that is, six pixels to the right
- and six pixels below the upper left corner. You can specify the hot spot
- offsets using negative values or values above 15 to position it outside the
- mouse cursor matrix if desired.
- Chapter 12: Input Device Support 225
-
-
- The Fastgraph routine fg_mouseptr defines a mouse cursor in graphics
- modes. The first of its three arguments is a 32-element integer array,
- passed by reference. The array's first 16 elements contain the screen mask,
- and its second 16 elements contain the cursor mask. The remaining two
- arguments respectively specify the horizontal and vertical offsets for the
- hot spot. The fg_mouseptr routine has no effect in a text video mode.
-
- Example 12-9 is similar to example 12-8. It shows how to define a
- graphics mode mouse cursor using fg_mouseptr. The values stored in the solid
- and hollow arrays define the screen and cursor masks for the solid and hollow
- plus-shaped mouse cursors discussed earlier. After making the mouse cursor
- visible, the program uses the default mouse cursor until a key is pressed.
- Following this, it changes to the solid cursor. After another keystroke, the
- program changes to the hollow cursor. When you run example 12-9, compare the
- differences among the three mouse cursors.
-
- Example 12-9.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- int solid[] = {0xE03F,0xE03F,0xE03F,0x0007,0x0007,0x0007,0x0007,0x0007,
- 0x0007,0x0007,0xE03F,0xE03F,0xE03F,0xFFFF,0xFFFF,0xFFFF,
- 0x0000,0x0F80,0x0F80,0x0F80,0x7FF0,0x7FF0,0x7FF0,0x7FF0,
- 0x7FF0,0x0F80,0x0F80,0x0F80,0x0000,0x0000,0x0000,0x0000};
-
- int hollow[] = {0xE03F,0xEFBF,0xEFBF,0x0F87,0x7FF7,0x7FF7,0x7FF7,0x7FF7,
- 0x7FF7,0x0F87,0xEFBF,0xEFBF,0xE03F,0xFFFF,0xFFFF,0xFFFF,
- 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0200,0x0000,
- 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
-
- void main()
- {
- int old_mode;
- int column, row, last_row;
-
- old_mode = fg_getmode();
- fg_setmode(fg_automode());
-
- if (fg_mouseini() < 0) {
- fg_setmode(old_mode);
- fg_reset();
- exit(1);
- }
- fg_setcolor(15);
- fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
-
- fg_setcolor(12);
- column = fg_xalpha(fg_getmaxx()/2) - 6;
- last_row = fg_yalpha(fg_getmaxy()) + 1;
- for (row = 0; row < last_row; row++) {
- fg_locate(row,column);
- fg_text("example 12-9",12);
-
- 226 Fastgraph User's Guide
-
- }
-
- fg_mousevis(1);
- fg_waitkey();
- fg_mouseptr(solid,6,6);
- fg_waitkey();
- fg_mouseptr(hollow,6,6);
- fg_waitkey();
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- CGA Considerations
-
- The mouse driver treats the screen and cursor masks differently in the
- CGA four-color graphics modes (modes 4 and 5) than in the other graphics
- modes. In the CGA modes, each pair of mask bits corresponds to one pixel.
- This means the masks more closely resemble the mode-specific format used by
- fg_drwimage instead of the mode-independent format of fg_drawmap.
-
- Fastgraph uses a different default mouse cursor for modes 4 and 5. Its
- screen and cursor masks, as well as the resulting cursor appearance, are
- shown in the following diagram.
-
- screen cursor cursor
- mask mask appearance
-
- 0000111111111111 0000000000000000 **
- 0000001111111111 0011000000000000 ***
- 0000000011111111 0011110000000000 ****
- 0000000000111111 0011111100000000 *****
- 0000000000001111 0011111111000000 ******
- 0000000000000011 0011111111110000 *******
- 0000000000000011 0011111100000000 *******
- 0000000000111111 0011111110000000 *****
- 0000000000001111 0011000011000000 ******
- 0000110000001111 0000000011000000 ** ***
- 1111111100000011 0000000000110000 ***
- 1111111100000011 0010000000110000 ***
- 1111111111000011 0000000000000000 **
- 1111111111111111 0000000000000000
- 1111111111111111 0000000000000000
- 1111111111111111 0000000000000000
-
- As you can see, the resulting mouse cursor is eight pixels wide instead of
- 16.
-
- Another important point concerning mouse cursors in modes 4 and 5 is the
- chance of pixel bleeding, or the changing of colors within the mouse cursor
- as it moves horizontally. Bleeding will occur if you use the bit pairs 01 or
- 10 in either mask to represent a pixel. In the default masks for modes 4 and
- 5, note that only the binary values 00 and 11 appear as bit pairs. Keep this
- in mind if you create your own masks in these video modes.
- Chapter 12: Input Device Support 227
-
-
- Joystick Support
-
- The third type of input device supported by Fastgraph is the joystick.
- Although joysticks are not as popular as mice, they are often preferable when
- a user's reactions are critical, such as in an arcade-style game. Fastgraph
- includes routines for initializing a joystick, reading a joystick's position
- or button status, and making a joystick behave analogously to the keyboard.
- These routines are independent of the rest of Fastgraph and thus do not
- require that you first call the fg_setmode routine.
-
- Joysticks are connected to a system through a game port. The PCjr and
- Tandy 1000 systems come equipped with two game ports, and hence support two
- joysticks. On other systems in the IBM family, you can install a game port
- card that contains either one or two game ports. If the card only has one
- game port, you can use a splitter cable to fork two joysticks into the port.
-
-
- Initializing Joysticks
-
- Before you can use any of Fastgraph's joystick support routines with a
- specific joystick, you must initialize that joystick. The fg_initjoy routine
- performs this task. This routine requires a single integer argument that
- specifies which joystick to initialize, either 1 or 2. If successful,
- fg_initjoy returns 0 as the function value. If the machine has no game port,
- or if the requested joystick is not connected to the game port, fg_initjoy
- returns -1. When you use fg_initjoy, the joystick being initialized must be
- centered (that is, the stick itself must not be tilted in either direction).
-
- Example 12-10 uses the fg_initjoy routine to try to initialize both
- joysticks. For each joystick, the program prints a message stating whether
- or not the initialization was successful.
-
- Example 12-10.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- if (fg_initjoy(1) < 0)
- printf("Joystick 1 not available.\n");
- else
- printf("Joystick 1 found.\n");
-
- if (fg_initjoy(2) < 0)
- printf("Joystick 2 not available.\n");
- else
- printf("Joystick 2 found.\n");
- }
-
- 228 Fastgraph User's Guide
-
- Reporting Joystick Status
-
- Each joystick can report three items: its horizontal position, its
- vertical position, and the button status. Fastgraph includes routines for
- obtaining each of these quantities.
-
- The fg_getxjoy and fg_getyjoy routines respectively return the
- horizontal and vertical position of the indicated joystick. Both routines
- require a single integer argument, whose value is either 1 or 2, to identify
- the joystick. The requested position is returned as the function value.
- Horizontal coordinates increase as the joystick moves to the right, while
- vertical coordinates increase as the joystick moves downward. If fg_initjoy
- did not initialize the specified joystick, or if your program hasn't yet
- called fg_initjoy, both fg_getxjoy and fg_getyjoy will return the value -1.
-
- Joystick characteristics vary more than those of any other input device.
- The values returned by fg_getxjoy and fg_getyjoy depend on the system's
- processor speed and the brand of joystick used. It often suffices to know
- the joystick position relative to its previous position, in which case the
- actual coordinate values do not matter. However, if you must rely on
- specific coordinate values, your program must perform some type of manual
- joystick calibration and then scale the coordinates reported by fg_getxjoy
- and fg_getyjoy as needed.
-
- The other piece of information joysticks provide is the button status.
- Most joysticks have two buttons, called the top and bottom buttons. Others
- have three buttons, but one of them duplicates the functionality of another
- (for example, a joystick might have one bottom button on its left side and
- another on its right side). The Fastgraph routine fg_button returns the
- joystick button status as its function value. Like fg_getxjoy and
- fg_getyjoy, the fg_button routine requires a single argument that specifies
- the joystick number. The meaning of the returned value is shown below.
-
- value meaning
-
- 0 neither button pressed
- 1 top button pressed
- 2 bottom button pressed
- 3 top and bottom buttons pressed
-
- You don't need to call fg_initjoy before using fg_button. If the
- specified joystick is not present, the fg_button routine will return a value
- of 0.
-
- Example 12-11 uses fg_getxjoy, fg_getyjoy, and fg_button to poll both
- joysticks at half-second intervals. It then displays the joystick number (1
- or 2), horizontal position, vertical position, and button status for each
- joystick. As the program runs, you can move the joysticks and watch how the
- movements affect the displayed coordinate values. The program continues
- doing this until you press Ctrl/C or Ctrl/Break to stop it.
- Chapter 12: Input Device Support 229
-
- Example 12-11.
-
- #include <fastgraf.h>
- #include <stdio.h>
-
- void main(void);
-
- void main()
- {
- int b, x, y;
-
- fg_initjoy(1);
- fg_initjoy(2);
-
- while (1) {
- x = fg_getxjoy(1);
- y = fg_getyjoy(1);
- b = fg_button(1);
- printf("1: %3d %3d %1d\n",x,y,b);
- x = fg_getxjoy(2);
- y = fg_getyjoy(2);
- b = fg_button(2);
- printf("2: %3d %3d %1d\n\n",x,y,b);
- fg_waitfor(9);
- }
- }
-
-
- There are two ways of effectively monitoring joystick button status.
- One is to call fg_button at many places in your program and then take the
- necessary action depending on the button status. However, the preferable
- method is to extend the BIOS time-of-day interrupt to check the button status
- at each clock tick (there are 18.2 clock ticks per second), set a flag if a
- button is pressed, and then check the flag as needed in your program.
- Information on changing the BIOS time-of-day interrupt appears in Appendix C
- of this document.
-
-
- Keyboard Emulation
-
- Although we can use the fg_getxjoy and fg_getyjoy routines to monitor
- relative joystick movements, it is usually easier to do this with another
- Fastgraph routine, fg_intjoy. This routine is similar to the fg_intkey
- routine in that it returns two values that are equivalent to the standard or
- extended keyboard codes for analogous keystrokes.
-
- The fg_intjoy routine needs three arguments. The first argument
- specifies the joystick number, either 1 or 2. The second and third
- arguments, both one-byte quantities passed by reference, receive the standard
- and extended keyboard codes analogous to the joystick movement and button
- status. The second argument receives a value of 13 (the standard keyboard
- code for the Enter key) if any joystick button is pressed; it receives a
- value of 0 if not. The third argument receives a value corresponding to the
- extended keyboard code for one of the directional keys on the numeric keypad,
- as summarized in the following table.
- 230 Fastgraph User's Guide
-
- joystick position corresponding key extended key code
-
- up and left Home 71
- up up arrow 72
- up and right PgUp 73
- left left arrow 75
- centered (no action) 0
- right right arrow 77
- down and left End 79
- down down arrow 80
- down and right PgDn 81
-
- The fg_intjoy routine will set both key code arguments to zero if the
- specified joystick has not yet been initialized.
-
- Example 12-12 is similar to example 12-10, but it uses fg_intjoy in
- place of fg_getxjoy and fg_getyjoy to report relative joystick position.
- This program does not report the joystick button status as example 12-10
- does, but you could readily add this feature to it.
-
- Example 12-12.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- char key, aux;
-
- fg_initjoy(1);
- fg_initjoy(2);
-
- while (1) {
- fg_intjoy(1,&key,&aux);
- printf("1: %2d %2d\n",key,aux);
- fg_intjoy(2,&key,&aux);
- printf("2: %2d %2d\n\n",key,aux);
- fg_waitfor(9);
- }
- }
-
-
-
- Special Joystick Considerations
-
- If you develop a program that supports only one joystick, you should use
- joystick 1. The reasons for this are twofold. First, it will make your
- program consistent with most other products that support joysticks. Second,
- and perhaps more importantly, many Tandy 1000 series machines cannot
- determine if joystick 2 is present when neither joystick is connected. This
- means if you use joystick 2 instead of joystick 1 in a single joystick
- program, you won't be able to tell if a joystick is available when running on
- a Tandy 1000.
- Chapter 12: Input Device Support 231
-
- Summary of Input 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.
-
- FG_BUTTON returns information about the state of either joystick's
- buttons.
-
- FG_CAPSLOCK determines the state of the CapsLock key.
-
- FG_GETKEY waits for a keystroke (or reads the next entry from the BIOS
- keyboard buffer). It returns the keystroke's standard or extended keyboard
- code.
-
- FG_GETXJOY and FG_GETYJOY return the horizontal and vertical coordinate
- position of the specified joystick. The actual coordinates depend on the
- processor speed and brand of joystick used.
-
- FG_INITJOY initializes joystick 1 or 2 and must be called before using
- fg_getxjoy, fg_getyjoy, or fg_intjoy. It returns a status code indicating
- whether or not the initialization was successful.
-
- FG_INTJOY returns the standard and extended keyboard codes analogous to
- the current position and button status of the specified joystick.
-
- FG_INTKEY reads the next entry from the BIOS keyboard buffer and returns
- the keystroke's standard or extended keyboard code. It is similar to
- fg_getkey, but it does not wait for a keystroke if the keyboard buffer is
- empty.
-
- FG_MOUSEBUT returns information about mouse button press or release
- counts, as well as the mouse cursor position at the time of the last button
- press or release.
-
- FG_MOUSECUR defines the appearance of the mouse cursor in text video
- modes.
-
- FG_MOUSEINI initializes the mouse and must be called before any of
- Fastgraph's other mouse support routines. It returns an error status if the
- mouse driver has not been loaded, or if the mouse is not connected.
-
- FG_MOUSELIM defines the rectangular area in which the mouse cursor may
- move.
-
- FG_MOUSEMOV moves the mouse cursor to the specified character cell (in
- text modes) or screen space position (in graphics modes).
-
- FG_MOUSEPOS returns the current mouse position and button status.
-
- FG_MOUSEPTR defines the shape and appearance of the mouse cursor in
- graphics video modes.
-
- FG_MOUSESPD defines the number of mickey units per eight pixels of
- cursor movement. This effectively controls the speed at which the mouse
- cursor moves relative to the movement of the mouse itself.
- 232 Fastgraph User's Guide
-
-
- FG_MOUSEVIS makes the mouse cursor visible or invisible.
-
- FG_NUMLOCK determines the state of the NumLock key.
-
- FG_SCRLOCK determines the state of the ScrollLock key (which is not
- present on some keyboards).
-
- FG_SETCAPS controls the state of the CapsLock key.
-
- FG_SETNUM controls the state of the NumLock key.
-
- FG_WAITKEY flushes the BIOS keyboard buffer (that is, removes any type-
- ahead characters) and then waits for another keystroke.
-
-
- Chapter 13
-
- Sound Effects
- 234 Fastgraph User's Guide
-
- Overview
-
- In the realm of the IBM PC and PS/2 family of systems, a sound is
- defined by its frequency, duration, and volume. The frequency of a sound is
- measured in units called Hertz. While the PC and PS/2 can produce sounds
- ranging from 18 to more than one million Hertz, the average human can hear
- sounds between 20 and about 20,000 Hertz. The length of a sound, called its
- duration, is expressed in clock ticks; there are either 18.2 of 72.8 clock
- ticks per second, depending on the method used to produce the sound.
- Finally, the volume determines the loudness of the sound. As we'll see in
- this chapter, we can control a sound's volume only on the PCjr and Tandy 1000
- systems.
-
- Fastgraph contains several different methods for producing sound
- effects. These include single tones, a series of tones expressed
- numerically, or a series of tones expressed as musical notes. The sound
- effects may be discrete, continuous, or performed at the same time as other
- activity. The sound-related routines are independent of the other parts of
- Fastgraph and do not require any initialization routines be called.
-
-
- Sound Sources
-
- All members of the PC and PS/2 families can produce sounds using the
- 8253-5 programmable timer chip and the internal speaker. This method is
- limited to producing single sounds of given frequencies and durations,
- although we can combine these sounds to create interesting audio effects or
- play music. When we use this technique, we have no control over the sound
- volume. In fact, sound volumes often vary slightly on different systems
- because the physical properties of the speaker and its housing are not always
- the same.
-
- The PCjr and Tandy 1000 systems have an additional, more powerful chip
- for producing sounds. This is the Texas Instruments SN76496A sound chip,
- called the TI sound chip for short. The TI sound chip has three independent
- voice channels for producing pure tones, and a fourth channel for generating
- periodic or white noise. Each voice channel has a separate volume control
- that allows us to control the loudness of the sound it emits.
-
-
- Synchronous Sound
-
- A sound effect is said to be synchronous if it is produced while no
- other activity is being performed. In other words, a program makes a
- synchronous sound by starting the sound, waiting for a specified duration,
- and then stopping the sound. The program must wait for the sound to complete
- before doing anything else. As long as the duration is relatively short, the
- fact that the sound is synchronous has little or no effect on the program's
- execution speed. Fastgraph includes routines for producing synchronous sound
- using either the 8253-5 programmable timer or the TI sound chip.
-
- The fg_sound routine uses the programmable timer to produce a sound of a
- given frequency and duration. The frequency, defined by the first argument,
- is expressed in Hertz and must be an integer value between 18 and 32,767.
- The second argument defines the duration and is expressed in clock ticks;
- there are 18.2 clock ticks per second. If the duration is zero or negative,
- the sound will continue until it is stopped with the fg_quiet routine.
- Chapter 13: Sound Effects 235
-
-
- Example 13-1 uses the fg_sound routine to create different sound
- effects, pausing for one second between each. It first produces three
- distinct sounds of 20, 100, and 1,000 Hertz. Each of these sounds lasts for
- approximately 1/6 of a second (three clock ticks). The program then makes a
- warbling noise by quickly alternating sounds of similar frequencies.
- Finally, the program creates a sliding tone of increasing frequencies between
- 100 and 500 Hertz. Each tone in this sequence lasts for two clock ticks, so
- it takes about 4.5 seconds to play the entire sequence. In all cases,
- example 13-1 displays an identifying message just before each sound.
-
- Example 13-1.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- int freq;
-
- printf("20 Hz tone...\n");
- fg_sound(20,3);
- fg_waitfor(18);
-
- printf("100 Hz tone...\n");
- fg_sound(100,3);
- fg_waitfor(18);
-
- printf("1000 Hz tone...\n");
- fg_sound(1000,3);
- fg_waitfor(18);
-
- printf("warble...\n");
- fg_sound(400,1);
- fg_sound(410,1);
- fg_sound(400,1);
- fg_sound(410,1);
- fg_waitfor(18);
-
- printf("sliding tone from 100 to 500 Hz...\n");
- for (freq = 100; freq <= 500; freq+=10)
- fg_sound(freq,2);
- }
-
-
- The fg_voice routine is analogous to the fg_sound routine, but it uses
- the TI sound chip rather than the programmable timer to create sound. For
- this reason, the fg_voice routine can only be used on the PCjr or Tandy 1000
- systems. The TI sound chip allows us to control the volume of a sound, and
- it also offers four distinct voice channels. Thus, fg_voice requires two
- additional arguments besides frequency and duration to define the voice
- channel and sound volume.
-
- The first argument to fg_voice defines the voice channel, as shown
- below.
- 236 Fastgraph User's Guide
-
- value meaning
-
- 1 voice channel #1
- 2 voice channel #2
- 3 voice channel #3
- 4 voice channel #4, periodic noise
- 5 voice channel #4, white noise
-
- If we use voice channels 1, 2, or 3, the second argument defines the sound
- frequency in Hertz, between 18 and 32,767. If we use voice channel 4,
- however, the second argument instead is a value that represents a specific
- frequency, as shown in this table.
-
- value frequency
-
- 0 512 Hertz
- 1 1024 Hertz
- 2 2048 Hertz
-
- The third argument defines the sound volume. It must be between 0 and 15,
- where 0 is silent and 15 is loudest. The fourth argument defines the sound
- duration in clock ticks. As with the fg_sound routine, there are 18.2 clock
- ticks per second, and if the duration is zero or negative, the sound will
- continue until stopped with the fg_quiet routine.
-
- Example 13-2 uses the fg_voice routine to create different sound effects
- using the TI sound chip. As in example 13-1, there is a pause of one second
- between each. The program first calls the fg_testmode routine to be sure it
- is running on a PCjr or Tandy 1000 system (video mode 9 is only available on
- these systems). If so, the program uses voice channel #4 to produce a 2,048
- Hertz periodic noise, followed by white noise of the same frequency. Both
- sounds are emitted at the maximum volume level (15) and last for about 1/6 of
- a second each (three clock ticks). After these noises, example 13-2 produces
- a 500 Hertz tone of increasing volume. In all cases, the program displays an
- identifying message just before each sound.
-
- Example 13-2.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- int volume;
-
- if (fg_testmode(9,0) == 0) {
-
- Chapter 13: Sound Effects 237
-
- printf("This program requires a PCjr or ");
- printf("a Tandy 1000 system.\n");
- exit(1);
- }
-
- printf("2048 Hz periodic noise...\n");
- fg_voice(4,2,15,3);
- fg_waitfor(18);
-
- printf("2048 Hz white noise...\n");
- fg_voice(5,2,15,3);
- fg_waitfor(18);
-
- printf("500 Hz tone of increasing volume...\n");
- for (volume = 1; volume <= 15; volume++) {
- fg_voice(1,500,volume,0);
- fg_waitfor(4);
- }
-
- fg_quiet();
- }
-
- Note how example 13-2 uses a duration of zero (continuous sound) and the
- fg_waitfor routine to specify the duration for each volume level the 500
- Hertz tone sequence. This causes the transition between changes in volume to
- blend better with each other. The fg_quiet routine, which stops continuous
- sound started with the fg_sound or fg_voice routines, ends the sound after
- the final volume level.
-
- The fg_sound and fg_voice routines each produce a single sound. We've
- seen how to combine sounds to produce sound effects, but still the individual
- sounds are defined numerically -- that is, by a certain frequency and
- duration. It is often easier to create sounds from musical notes, and for
- this reason Fastgraph includes a routine fg_music that produces such sounds.
- The fg_music routine uses the programmable timer to produce synchronous
- sound; it does not support the TI sound chip.
-
- The fg_music routine has a single argument called the music string,
- passed by reference as a byte array or character string. The music string is
- simply a variable-length sequence of music commands, followed by a dollar-
- sign ($) terminator. Music commands are summarized in the following table.
-
- command meaning
-
- A thru G Play the specified note in the current
- octave.
-
- # May be appended to a note character (A
- through G) to make that note sharp.
-
- . May be appended to a note character (A
- through G) or a sharp (#) to extend that note
- by half its normal length. Multiple dots may
- be used, and each will again extend the note
- by half as much as the previous extension.
- 238 Fastgraph User's Guide
-
- Ln Set the length of subsequent notes and
- pauses. The value of n is an integer between
- 1 and 64, where 1 indicates a whole note, 2 a
- half note, 4 a quarter note, and so forth.
- If no L command is present, L4 is assumed.
-
- On Set the octave for subsequent notes. The
- value of n may be an integer between 0 and 6
- to set a specific octave. It also can be a
- plus (+) or minus (-) character to increment
- or decrement the current octave number.
- Octave 4 contains middle C, and if no O
- command is present, O4 is assumed.
-
- P Pause (rest) for the duration specified by
- the most recent L command.
-
- Sn Set the amount of silence between notes. The
- value of n is an integer between 0 and 2. If
- n is 0, each note plays for the full period
- set by the L command (music legato). If n is
- 1, each note plays for 7/8 the period set by
- the L command (music normal). If n is 2,
- each note plays for 3/4 the period set by the
- L command (music staccato). If no S command
- is present, S1 is assumed.
-
- Tn Set the tempo of the music (the number of
- quarter notes per minute). The value of n is
- an integer between 32 and 255. If no T
- command is present, T120 is assumed.
-
- The fg_music routine ignores any other characters in the music string. It
- also ignores command values outside the allowable range, such as T20 or O8.
-
- Example 13-3 illustrates some uses of the fg_music routine. The program
- plays the first few bars of "Mary Had a Little Lamb", followed by the musical
- scale (including sharps) in two octaves, and finally the introduction to
- Beethoven's Fifth Symphony. There is a pause of one second between each
- piece of music, and the program displays the titles before playing the music.
- Blank characters appear in the music strings to help make them more readable.
-
- Example 13-3.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- printf("Mary Had a Little Lamb...\n");
- fg_music("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$");
- fg_waitfor(18);
-
- printf("up the scale in two octaves...\n");
- fg_music("L16 CC#DD#EFF#GG#AA#B O+ CC#DD#EFF#GG#AA#B$");
-
- Chapter 13: Sound Effects 239
-
- fg_waitfor(18);
-
- printf("Beethoven's Fifth Symphony...\n");
- fg_music("T180 O2 L2 P L8 P GGG L2 D# L24 P L8 P FFF L2 D$");
- }
-
-
-
-
- Asynchronous Sound
-
- Sounds made concurrently with other activity in a program are said to be
- asynchronous. Fastgraph's routines that produce asynchronous sound just
- start the sound and then immediately return control to the calling program.
- The sounds will automatically stop when the end of the sequence is reached,
- and you also can suspend or stop it on demand before that time. None of
- Fastgraph's asynchronous sound routines have any effect if there is already
- asynchronous sound in progress. In addition, the asynchronous sound routines
- temporarily disable the synchronous sound routines (fg_sound, fg_voice, and
- fg_music) while asynchronous sound is in progress.
-
- To expand the range of sound effects and to play fast-tempo music,
- Fastgraph temporarily quadruples the clock tick interrupt rate from 18.2 to
- 72.8 ticks per second while producing asynchronous sound. Because many disk
- controllers rely on the 18.2 tick per second clock rate to synchronize disk
- accesses, your programs should not perform any disk operations when
- asynchronous sound is in progress.
-
- The fg_sounds routine is the asynchronous version of the fg_sound
- routine. It uses the programmable timer to play a sequence of tones
- simultaneous to other operations. This routine expects as its first argument
- a variable-length integer array, passed by reference, containing pairs of
- frequency and duration values. As with the fg_sound routine, each frequency
- is expressed in Hertz and must be between 18 and 32,767. The durations are
- also measured in clock ticks, but because the interrupt rate is quadrupled,
- there are 72.8 instead of 18.2 ticks per second.
-
- The format of the frequency and duration array passed to fg_sounds is
- shown below.
-
- [0] frequency of sound 1
-
- [1] duration of sound 1
-
- [2] frequency of sound 2
-
- [3] duration of sound 2
- .
- .
- .
- [2n-2] frequency of sound n
-
- [2n-1] duration of sound n
-
- [2n] terminator (0)
-
- 240 Fastgraph User's Guide
-
-
- Note that a null character (that is, a zero byte) terminates the array. The
- second argument passed to fg_sounds is an integer value indicating the number
- of times to cycle through the frequency and duration array. If this value is
- negative, the sounds will continue until stopped with the fg_hush or
- fg_hushnext routines.
-
- Example 13-4 uses the fg_sounds routine to play the 100 to 500 Hertz
- sliding tone sequence of example 13-1. To prove the sounds are being made
- concurrently with other operations, messages are displayed while the sequence
- is playing. This is controlled by the Fastgraph routine fg_playing, which
- returns a value of 1 if asynchronous sounds are in progress, and 0 if not.
- Note how the duration must be specified as 8 clock ticks (instead of 2 as in
- example 13-1) to compensate for the quadrupled clock tick interrupt rate.
-
- Example 13-4.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- int i;
- int freq;
- int sound_array[83];
-
- i = 0;
-
- for (freq = 100; freq <= 500; freq+=10) {
- sound_array[i++] = freq;
- sound_array[i++] = 8;
- }
- sound_array[i] = 0;
-
- fg_sounds(sound_array,1);
-
- while(fg_playing())
- printf("Still playing...\n");
- }
-
- Just as the fg_sounds routine is analogous to the fg_sound routine,
- there is a Fastgraph routine fg_voices that is similar to the fg_voice
- routine. That is, fg_voices uses the TI sound chip to play an asynchronous
- sequence of tones. Its arguments are the same as those of the fg_sounds
- routine, but the structure of the sound array is different. Its structure
- is:
-
-
- [0] channel # of sound 1
-
- [1] frequency of sound 1
-
- [2] volume of sound 1
-
- [3] duration of sound 1
-
- Chapter 13: Sound Effects 241
-
- [4n-4] channel # of sound n
-
- [4n-3] frequency of sound n
-
- [4n-2] volume of sound n
-
- [4n-1] duration of sound n
-
- [4n] terminator (0)
-
-
- The channel numbers, frequencies, volumes, and durations must be in the same
- ranges as discussed in the description of the fg_voice routine, except the
- durations are quadrupled because of the accelerated clock tick interrupt
- rate. Again, note that a null character (that is, a zero byte) terminates
- the array.
-
- Example 13-5 uses the fg_voices routine to play the 500 Hertz tone
- sequence of increasing volume introduced in example 13-2. As in example
- 13-4, the program displays messages while the tone sequence is playing to
- demonstrate the sounds are being made concurrently with other operations.
- Note how the duration is now 16 clock ticks (instead of 4 as in example 13-2)
- because of the quadrupled clock tick interrupt rate.
-
- Example 13-5.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- int voice_array[61];
- int i;
- int volume;
-
- if (fg_testmode(9,0) == 0) {
- printf("This program requires a PCjr or ");
- printf("a Tandy 1000 system.\n");
- exit(1);
- }
-
- i = 0;
-
- for (volume = 1; volume <= 15; volume++) {
- voice_array[i++] = 1; /* use channel 1 */
- voice_array[i++] = 500; /* 500 Hz frequency */
- voice_array[i++] = volume; /* variable volume */
- voice_array[i++] = 16; /* duration */
- }
- voice_array[i] = 0;
-
- fg_voices(voice_array,1);
-
- 242 Fastgraph User's Guide
-
-
- while(fg_playing())
- printf("Still playing...\n");
- }
-
-
- There is also an asynchronous version of the fg_music routine. It is
- called fg_musicb, and it uses the same format music string as the fg_music
- routine does. However, the fg_musicb routine has a second argument that
- specifies the number of times to cycle through the music string. If this
- value is negative, the music will play repetitively until you stop it with
- the fg_hush or fg_hushnext routine.
-
- Example 13-6 plays the same three pieces of music as example 13-3, but
- it does so concurrently with other operations. As the music plays, the
- program continuously displays the title of each piece. Note how we can take
- advantage of the repetition in the music string for the "up the scale"
- sequence by playing the sequence twice.
-
- Example 13-6.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- fg_musicb("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$",1);
- while (fg_playing())
- printf("Mary Had a Little Lamb...\n");
- fg_waitfor(18);
-
-
- fg_musicb("L16 CC#DD#EFF#GG#AA#B O+$",2);
- while (fg_playing())
- printf("up the scale in two octaves...\n");
- fg_waitfor(18);
-
- fg_musicb("T180 O2 L2 P L8 P GGG L2 D# L24 P L8 P FFF L2 D$",1);
- while (fg_playing())
- printf("Beethoven's Fifth Symphony...\n");
- }
-
- The next example demonstrates the effects of the Fastgraph routines
- fg_hush and fg_hushnext, which stop sounds started with the fg_sounds,
- fg_voices, or fg_musicb routines. The fg_hush routine immediately stops
- asynchronous sound, whereas the fg_hushnext routine does so when the current
- cycle finishes. Neither routine has any arguments, and neither routine has
- any effect if no asynchronous sound is in progress. Furthermore, note that
- fg_hushnext has no effect unless the asynchronous sound is continuous.
-
- Example 13-7 runs in any text or graphics video mode. It displays
- rectangles in up to 16 colors while playing continuous asynchronous music.
- The program periodically checks for keystrokes with the fg_intkey routine,
- and it continues to play the music while there is no keyboard activity. If
- you press the Escape key, the program uses fg_hush to stop the music
- immediately; this causes an exit from the while loop. If you press any other
- Chapter 13: Sound Effects 243
-
- key, the program uses fg_hushnext to stop the music as soon as the current
- repetition finishes. Once it does, the program exits the while loop because
- fg_playing will return a value of zero.
-
- Example 13-7.
-
- #include <fastgraf.h>
- void main(void);
-
- #define ESC 27
-
- void main()
- {
- int color;
- int old_mode;
- unsigned char key, aux;
-
- old_mode = fg_getmode();
- fg_setmode(fg_automode());
- color = 0;
-
- fg_musicb("O4 L16 CC#DD#EFF#GG#AA#B O+ CC#DD#EFF#GG#AA#B$",-1);
-
- while (fg_playing())
- {
- color = (color + 1) & 15;
- fg_setcolor(color);
- fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
-
- fg_waitfor(4);
- fg_intkey(&key,&aux);
- if (key == ESC)
- fg_hush();
- else if (key+aux != 0)
- fg_hushnext();
- }
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
- Example 13-7 also demonstrates an important side-effect of the fg_musicb
- routine when playing continuous music. Any length, octave, silence, or tempo
- values changed within the string are not reset to their original values at
- the beginning of each repetition. If we did not include the O4 command at
- the beginning of the string, the later O+ command would cause the music to
- play in octaves 4 and 5 during the first repetition, 5 and 6 during the
- second repetition, and octave 6 for all subsequent repetitions (because you
- cannot increase the octave number above 6).
-
- The final two routines relating to asynchronous sound are fg_resume and
- fg_suspend. The fg_suspend routine suspends music previously started by
- fg_musicb, while fg_resume restarts the music from the point where it was
- suspended. Example 13-8 plays the first few bars of "Mary Had a Little
- Lamb". If you press any key while the song is playing, it stops. Then,
- after another keystroke, the music resumes and continues until finished.
- 244 Fastgraph User's Guide
-
- Example 13-8.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- fg_musicb("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$",1);
- fg_waitkey();
-
- fg_suspend();
- printf("Music suspended. Press any key to resume.\n");
- fg_waitkey();
-
- fg_resume();
- printf("Music resumed.\n");
- while (fg_playing());
- printf("Music finished.\n");
- }
-
-
- The fg_suspend routine has no effect if there is no asynchronous music in
- progress. Similarly, fg_resume has no effect if there is no suspended music.
- If you call fg_suspend and then need to cancel the music or exit to DOS
- instead of restarting the music, call fg_hush instead of fg_resume.
-
-
- Summary of Sound 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.
-
- FG_HUSH immediately stops asynchronous sound started with the fg_sounds,
- fg_voices, or fg_musicb routines.
-
- FG_HUSHNEXT is similar to fg_hush, but it does not stop the asynchronous
- sound until the current repetition finishes.
-
- FG_MUSIC uses the programmable timer to play a sequence of musical
- tones.
-
- FG_MUSICB is the asynchronous version of the fg_music routine. It uses
- the programmable timer to play a sequence of musical tones, concurrent with
- other activity.
-
- FG_PLAYING determines whether or not there is any asynchronous sound in
- progress.
-
- FG_QUIET stops continuous synchronous sound started with the fg_sound or
- fg_voice routines.
-
- FG_RESUME restarts asynchronous music previously suspended by
- fg_suspend.
- Chapter 13: Sound Effects 245
-
- FG_SOUND produces a tone of a specified frequency and duration using the
- programmable timer.
-
- FG_SOUNDS is the asynchronous version of the fg_sound routine. It can
- play a series of tones of specified frequencies and durations, concurrent
- with other activity.
-
- FG_SUSPEND suspends asynchronous music previously started by fg_musicb.
-
- FG_VOICE produces a tone of a specified frequency, duration, and volume
- using one of the TI sound chip's four voice channels.
-
- FG_VOICES is the asynchronous version of the fg_voice routine. It can
- play a series of tones of specified frequencies, durations, and volumes,
- concurrent with other activity.
- 246 Fastgraph User's Guide
-
-
- Chapter 14
-
- Program Timing
- 248 Fastgraph User's Guide
-
-
- Overview
-
- It is occasionally necessary to delay a program's execution for a brief
- period, or to determine how long it takes to execute specific sections of a
- program. Fastgraph includes routines to accomplish these tasks. Some of
- these routines are said to be real-time, which means they are independent of
- a system's processor speed, while the speed of others is processor-specific.
- This chapter describes both classes of timing routines, all of which are
- independent of the other parts of Fastgraph.
-
-
- Real-Time Routines
-
- Real-time operations center around the BIOS time-of-day clock, which is
- nothing more than a counter that the system automatically increments 18.2
- times per second. This number is often called the clock tick interrupt rate
- because an interrupt routine performs the incrementing. In addition, each
- increment is usually called a clock tick.
-
- The Fastgraph routine fg_waitfor delays a program's execution by the
- number of clock ticks specified as its argument. Because fg_waitfor uses
- clock ticks, the actual length of the delay is the same, regardless of the
- system's processor speed. Even when Fastgraph's asynchronous sound routines
- quadruple the clock tick interrupt rate, Fastgraph compensates for this
- internally so fg_waitfor always works as though the actual rate were still
- 18.2 times per second.
-
- Example 14-1 displays a message every five seconds that states how long
- the program has been running. The fg_waitfor routine produces the five-
- second delay by pausing 91 (18.2 times 5) clock ticks before the program
- displays each message. The program returns to DOS when you press any key.
-
- Example 14-1.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- unsigned int seconds;
- unsigned char key, aux;
-
- seconds = 0;
-
- do {
- fg_waitfor(91);
- seconds += 5;
- printf("%u seconds have elapsed.\n",seconds);
- fg_intkey(&key,&aux);
- }
- while (key+aux == 0);
- }
-
- Another common application of the fg_waitfor routine is to slow down a
- loop that uses the fg_intkey routine to check for keystrokes. In loops that
- Chapter 14: Program Timing 249
-
- do little else, we may call fg_intkey too rapidly without this delay, and it
- is then possible that the BIOS may not be able to store characters in its
- keyboard buffer fast enough. A small delay, even one clock tick, often helps
- such "tight" loops.
-
- The fg_getclock routine provides an efficient way to measure time,
- especially differences in time. This routine has no arguments and returns a
- 32-bit unsigned integer (as its function value) representing the number of
- clock ticks since midnight. Example 14-2 demonstrates the fg_getclock
- routine. In response to any keystroke (except Escape, which returns control
- to DOS), the program displays the number of clock ticks since midnight, and
- the number of ticks since the program started.
-
- Example 14-2.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- #define ESC 27
-
- void main()
- {
- unsigned long start, ticks;
- unsigned char key, aux;
-
- start = fg_getclock();
-
- do {
- ticks = fg_getclock();
- printf("%lu ticks since midnight.\n",ticks);
- printf("%lu ticks since start of program.\n\n",ticks-start);
- fg_getkey(&key,&aux);
- }
- while (key != ESC);
- }
-
-
-
- Routines Dependent on the System Speed
-
- The fg_waitfor routine described in the previous section is independent
- of the system's processor speed. This means the actual length of its delay
- is the same on any system. Another routine, fg_stall, is similar to
- fg_waitfor, but its delay is proportional to the processor speed. Like
- fg_waitfor, fg_stall has a single integer argument that specifies the length
- of the delay. However, instead of being expressed in clock ticks, fg_stall
- measures the delay in delay units. The fg_stall routine treats the length as
- an unsigned quantity, so the maximum number of delay units we can specify is
- 65,535. The following table lists the approximate number of delay units per
- clock tick on three typical systems.
- 250 Fastgraph User's Guide
-
- system delay units
- type per clock tick
-
- Tandy 1000 HX 675
- 10 MHz 80286 3,000
- 25 MHz 80386 11,000
-
- Fastgraph includes a routine that determines the number of delay units
- per clock tick for the processor being used. This is the fg_measure routine,
- which has no arguments and returns the number of delay units per clock tick
- as its function value. Once we determine this value, we can use fg_stall to
- delay a program's execution in real time. This provides a much more refined
- delay than the clock tick unit used by fg_waitfor.
-
- Example 14-3 is functionally identical to example 14-1, but it uses the
- fg_stall routine instead of fg_waitfor to delay the program execution. The
- program first calls the fg_measure routine to determine number of delay units
- equivalent to one clock tick. It then passes this value to fg_stall, called
- 91 times inside the for loop to create the five-second delay (because 91
- clock ticks equals five seconds). The program returns to DOS when you press
- any key.
-
- Example 14-3.
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- void main()
- {
- int i;
- int units_per_tick;
- unsigned int seconds;
- unsigned char key, aux;
-
- seconds = 0;
-
- printf("Benchmarking system speed...\n");
- units_per_tick = fg_measure();
- printf("Benchmark completed.\n\n");
-
- do {
- for (i = 0; i < 91; i++)
- fg_stall(units_per_tick);
- seconds += 5;
- printf("%u seconds have elapsed.\n",seconds);
- fg_intkey(&key,&aux);
- }
- while (key+aux == 0);
- }
-
-
- One final point: the fg_measure routine takes a few seconds to
- benchmark the system speed accurately. For this reason, you should only call
- fg_measure once (typically at the beginning of the program) and use its
- return value instead of calling fg_measure throughout the program.
- Chapter 14: Program Timing 251
-
-
- Summary of Timing 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.
-
- FG_GETCLOCK returns the number of clock ticks since midnight as its
- function value. This quantity is a 32-bit unsigned integer.
-
- FG_MEASURE returns the approximate number of delay units per clock tick
- as its function value. This quantity is proportional to the system's
- processor speed.
-
- FG_STALL delays a program's execution for a given number of processor-
- specific delay units.
-
- FG_WAITFOR delays a program's execution for a given number of clock
- ticks. There are 18.2 clock ticks per second, regardless of the system's
- processor speed.
- 252 Fastgraph User's Guide
-
-
- Chapter 15
-
- Miscellaneous Routines
- 254 Fastgraph User's Guide
-
- Overview
-
- There are a few remaining Fastgraph routines that really don't fit into
- any of the categories discussed so far. For this reason, they are described
- separately in this chapter.
-
-
- Determining Available Memory
-
- The fg_memavail routine returns the amount of free conventional memory
- (in bytes) available to DOS. It returns the amount of memory as its function
- value, which is a 32-bit unsigned integer. Fg_memavail has no arguments.
-
- Example 15-1 uses fg_memavail to show the effects of creating and
- releasing virtual pages. When run in a video mode in which video pages 1 and
- 2 are physical pages, the amount of free memory remains the same because
- these pages use memory that is resident on the video adapter. However, in
- modes where pages 1 and 2 are virtual pages, the amount of free memory
- decreases after each call to fg_allocate and returns to its original value
- after the calls to fg_freepage. Note how the program requests and validates
- the video mode.
-
- Example 15-1.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- void main()
- {
- long original, mem0, mem1, mem2;
- int mode, old_mode;
-
- printf("Which video mode? ");
- scanf("%d",&mode);
-
- if (fg_testmode(mode,0) == 0) {
- printf("Your system does not support that video mode.\n");
- exit(1);
- }
- if (fg_testmode(mode,3) == 0) {
- printf("Your system does not have enough memory.\n");
- exit(1);
- }
-
- original = fg_memavail();
- old_mode = fg_getmode();
- fg_setmode(mode);
- mem0 = fg_memavail();
- fg_allocate(1);
- mem1 = fg_memavail();
- fg_allocate(2);
- mem2 = fg_memavail();
- fg_freepage(1);
- fg_freepage(2);
-
- Chapter 15: Miscellaneous Routines 255
-
- fg_setmode(old_mode);
- fg_reset();
-
- printf("originally = %ld\n",original);
- printf("after setmode = %ld\n",mem0);
- printf("after 1st page = %ld\n",mem1);
- printf("after 2nd page = %ld\n",mem2);
- printf("at end = %ld\n",memavail());
- }
-
-
-
- Choosing the Video Memory Update Function
-
- In Chapter 10, we saw how to use the fg_setfunc routine to perform XOR
- animation in native EGA and VGA graphics modes (modes 13 to 18). In these
- video modes, fg_setfunc controls the logical operation applied when the
- contents of video memory change. The specific operation is defined by its
- argument, as shown below.
-
- value of logical
- argument operation
-
- 0 replacement
- 1 and
- 2 or
- 3 exclusive or
-
- If your program does not use the fg_setfunc routine, replacement mode is
- always used. That is, information written to video memory replaces whatever
- was there before. The fg_setfunc routine does nothing in CGA, Tandy/PCjr,
- Hercules, or MCGA graphics modes, or in any text modes.
-
- Example 15-2 demonstrates the fg_setfunc routine. The program is
- similar to example 6-10 which displays 200 random rectangles on the screen.
- However, example 15-2 displays the rectangles in XOR mode, which means the
- rectangle intersections will appear in different colors.
-
- Example 15-2.
-
- #include <fastgraf.h>
- #include <stdio.h>
- #include <stdlib.h>
- void main(void);
-
- #define RECTANGLES 200
- #define SWAP(a,b,temp) { temp = a; a = b; b = temp; }
-
- void main()
- {
- int i;
- int minx, maxx, miny, maxy;
- int old_mode;
- int temp;
-
- 256 Fastgraph User's Guide
-
- int xres, yres;
-
- if (fg_egacheck() == 0) {
- printf("This program requires EGA or VGA.\n");
- exit(1);
- }
-
- old_mode = fg_getmode();
- fg_setmode(fg_automode());
- fg_setfunc(3);
-
- xres = fg_getmaxx() + 1;
- yres = fg_getmaxy() + 1;
-
- for (i = 0; i < RECTANGLES; i++) {
- minx = rand() % xres;
- maxx = rand() % xres;
- miny = rand() % yres;
- maxy = rand() % yres;
- if (minx > maxx)
- SWAP(minx,maxx,temp);
- if (miny > maxy)
- SWAP(miny,maxy,temp);
- fg_setcolor(rand()%16);
- fg_rect(minx,maxx,miny,maxy);
- }
-
- fg_setmode(old_mode);
- fg_reset();
- }
-
-
-
- Summary of Miscellaneous 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.
-
- FG_MEMAVAIL returns the amount of memory available to DOS.
-
- FG_SETFUNC specifies the logical operation (replacement, or, and,
- exclusive or) applied when video memory changes in the native EGA and VGA
- graphics modes. This routine has no effect in other video modes.
-
-
- Appendix A
-
- Fastgraph Utilities
- 258 Fastgraph User's Guide
-
-
- Overview
-
- This appendix describes utilities for creating and managing pixel run
- files used with the fg_dispfile routine. By default, the Fastgraph
- installation procedure places these utilities in the \FG directory. To use
- these utilities, you must either (1) copy the .EXE file from \FG to your
- current directory, (2) make \FG your current directory, or (3) include the
- \FG directory in your DOS path specification.
-
-
- SNAPSHOT Utility
-
- The SNAPSHOT utility is a terminate and stay resident program (TSR) to
- capture graphic images. It stores the image in Fastgraph's standard pixel
- run format. To load SNAPSHOT, just enter the command SNAPSHOT at the DOS
- prompt, and you'll see messages similar to the following if SNAPSHOT loads
- successfully.
-
-
- C> SNAPSHOT
-
- SNAPSHOT Version 1.01
- Copyright (c) 1991 Ted Gruber Software. All Rights Reserved.
-
- Press <alt>-<left shift> to activate.
-
-
- After SNAPSHOT loads, control returns to the DOS prompt. At this point,
- you can use any method whatsoever to display a graphic image and then press
- the Alt and left shift keys at the same time to capture the image. You don't
- need to load SNAPSHOT for each image capture, just once per system boot.
- SNAPSHOT uses about 14,000 bytes of conventional memory once loaded.
-
- To illustrate the use of SNAPSHOT, suppose you have drawn and saved an
- image with a commercial paint program, and you want to incorporate this image
- into a Fastgraph application. Once you load SNAPSHOT, start the paint
- program and retrieve your image. Then press the Alt and left shift keys
- simultaneously and wait for the success tone (three quick medium-pitched
- sounds). Finally, exit the paint program to return to the DOS prompt.
-
- The sequence described in the preceding paragraph will store the
- captured image in Fastgraph's standard pixel run format, in a file named
- SNAPSHOT.nnn in the current directory. The file type nnn will be the first
- sequence of digits that does not result in a duplicate file name. That is,
- if there are no captured image files in the current directory, SNAPSHOT will
- use the file name SNAPSHOT.000. The next time you capture an image, SNAPSHOT
- will store it in SNAPSHOT.001, then SNAPSHOT.002, and so forth. If you
- rename or delete one of these files, SNAPSHOT will again use that file name.
- For example, if you delete SNAPSHOT.000 but keep SNAPSHOT.001, SNAPSHOT will
- store the next image it captures in SNAPSHOT.000.
-
- If SNAPSHOT is unable to capture the image, it will produce its error
- tone (a single low-pitched sound). The most common cause of this is trying
- to capture an image from a text video mode, but it also will occur if there
- is not enough disk space or if all 1,000 image file names are already being
- used.
- Appendix A: Fastgraph Utilities 259
-
-
- CLIP Utility
-
- The SNAPSHOT utility described in the previous section captures the
- entire screen. While this might be desirable in some cases, other times
- you'll just need a portion of the screen. CLIP is an interactive utility
- that you can use to reduce the size of any image stored in Fastgraph's
- standard or packed pixel run format. The syntax of the command for invoking
- the CLIP utility from the DOS prompt is
-
- CLIP input_file output_file options
-
- where input_file is the name of the original image file, and output_file is
- the name of the new image file. CLIP does not modify the input_file in any
- way, but it will overwrite the output_file if an identically named file
- exists in the current directory. The options list specifies one or more
- optional switches as shown below.
-
-
- option meaning
-
- /M:mode Specifies the video mode number in which to
- display the image. The mode value must be an
- integer between 0 and 23. If that video mode
- is a text mode, an unsupported graphics mode,
- or an unavailable graphics mode, CLIP
- displays an error message stating this. If
- the /M switch is not present, CLIP uses the
- first available video mode from the list 16,
- 15, 19, 13, 9, 4, 12.
-
- /P Indicates the input_file is in Fastgraph's
- packed pixel run format. If the /P switch is
- not present, CLIP assumes it is in standard
- pixel run format. The output_file will be in
- the same format as the input_file.
-
- /W:width Specifies the image width in pixels. The
- width value must be an integer between 1 and
- the horizontal resolution of the selected
- video mode. If the /W switch is not present,
- CLIP uses the horizontal resolution of the
- selected video mode.
-
- For example, if you wanted to create the image file PARTIAL.PPR from the
- packed pixel run file SCREEN.PPR, and use the native 320 by 200 EGA graphics
- video mode (mode 13), you would start CLIP with the following command.
-
- CLIP PARTIAL.PPR SCREEN.PPR /P /M:13
-
- Because no /W switch appears in the above command and the horizontal
- resolution of mode 13 is 320 pixels, CLIP assumes the image width is 320
- pixels.
- 260 Fastgraph User's Guide
-
-
- When CLIP displays the image and the plus-shaped cursor, you are ready
- to define one corner of the clipping region (that part of the image used to
- create the output_file). To do this, use the directional keys on the numeric
- keypad to move the cursor to the desired position, then press the Enter key.
- You are then ready to define the clipping region's opposite corner. Again,
- use the directional keys to move the cursor to the desired position. When
- defining the second corner, however, CLIP uses a rectangular box instead of
- the plus-shaped cursor to simplify marking the clipping region's boundaries.
- After you press Enter to define the second corner, CLIP creates the
- output_file and displays the resulting image width and the number of pixel
- runs the image contains.
-
- CLIP includes some features that may help you define the clipping
- region. You can change the distance the cursor moves in response to the
- directional keys, display the current (x,y) pixel coordinates of the cursor,
- and change the cursor color. The following table explains the keystrokes
- that CLIP recognizes when you are defining the clipping region.
-
- key meaning
-
- F1 Displays the (x,y) coordinate bar at the top
- of the screen. If the coordinate bar is
- already on, F1 removes it.
- F2 Displays the (x,y) coordinate bar at the
- bottom of the screen. If the coordinate bar
- is already on, F2 removes it.
- F3 Changes the cursor or box color from white to
- black, or from black to white.
- F4 Displays a summary of the keys CLIP
- recognizes when defining the clipping region.
- KP1 Moves the cursor one unit down and to the
- left.
- KP2 Moves the cursor one unit down.
- KP3 Moves the cursor one unit down and to the
- right.
- KP4 Moves the cursor one unit to the left.
- KP6 Moves the cursor one unit to the right.
- KP7 Moves the cursor one unit up and to the left.
- KP8 Moves the cursor one unit up.
- KP9 Moves the cursor one unit up and to the
- right.
- + Increases the unit of cursor movement by one
- pixel. The default cursor movement is one
- pixel.
- - Decreases the unit of cursor movement by one
- pixel.
- Enter Defines a corner of the clipping region
- at the cursor position.
- Esc Exits to DOS without creating the
- output_file. CLIP will first issue an "Exit
- to DOS?" prompt in case you pressed the Esc
- key accidentally.
- Appendix A: Fastgraph Utilities 261
-
- The CLIP utility requires two video pages to run. Thus, you cannot use
- it in video modes 17, 18, and 23 because they have only one physical video
- page and no virtual video pages.
-
-
- CONVERT Utility
-
- The CONVERT utility lets you translate files between Fastgraph's
- supported image file formats. The syntax of the command for invoking CONVERT
- from the DOS prompt is
-
- CONVERT input_file output_file
-
- where input_file is the name of the original image file, and output_file is
- the name of the new translated image file. CONVERT does not modify the
- input_file in any way, but it will overwrite the output_file if an
- identically named file exists in the current directory.
-
- By default, the file type of the input_file and output_file determine
- the image format of that file. If the file type is .PPR, CONVERT assumes the
- image is in Fastgraph's packed pixel run format. If the file type is .SPR,
- CONVERT assumes it is in the Fastgraph's standard pixel run format. If your
- image files use other file types, you can explicitly specify the file's image
- format by appending one of the switches /PPR or /SPR to the file name. The
- input_file and output_file must not both specify the same image format
- (CONVERT will display an error message if this is so).
-
- The following command will translate the standard pixel run file
- PICTURE.SPR to packed format. The packed image will be stored in the file
- PICTURE.IMG, so we must append the switch /PPR to tell CONVERT that it will
- be a packed file.
-
- CONVERT PICTURE.SPR PICTURE.IMG/PPR
-
-
- EDITSPR Utility
-
- The EDITSPR utility changes all pixel runs of one color to another color
- in an image file stored in Fastgraph's standard pixel run (.SPR) format. The
- syntax of the command for invoking the EDITSPR utility from the DOS command
- prompt is
-
- EDITSPR input_file output_file
-
- where input_file is the name of the original image file, and output_file is
- the name of the new image file. EDITSPR does not modify the input_file in
- any way, but it will overwrite the output_file if an identically named file
- exists in the current directory.
-
- After it reads the pixel runs from the input_file, EDITSPR will perform
- the requested color changes. It does this iteratively by asking for an old
- color value followed by a new color value (each value must be between 0 and
- 262 Fastgraph User's Guide
-
- 255). EDITSPR then finds the pixel runs of the old color value and changes
- them to the new color value. Following this, EDITSPR displays a message
- stating how many pixel runs it changed. This process repeats until you enter
- a negative number for either color value.
-
- EDITSPR will next combine adjacent pixel runs of like colors. For
- example, suppose the original image file contained a color 1 pixel run of
- length 50, followed by a color 2 pixel run of length 20, followed by another
- color 1 pixel run of length 10. If you changed all color 2 pixel runs to
- color 1, EDITSPR will combine these three pixel runs into a single run of
- length 80.
-
- Finally, EDITSPR will close the output_file.
-
-
- GrabRGB Utility
-
- The GrabRGB utility is a terminate and stay resident program (TSR) to
- capture the current red, green, and blue color components of video DAC
- registers in the 256-color MCGA and VGA graphics modes. You can use GrabRGB
- together with Fastgraph's SNAPSHOT utility to preserve the original colors of
- a captured image.
-
- To load GrabRGB, just enter the command GRABRGB at the DOS prompt.
- After GrabRGB loads, control returns to the DOS prompt. At this point, you
- can use any method whatsoever to display a 256-color graphic image and then
- press the Alt and right shift keys at the same time to capture the current
- DAC values. You don't need to load GrabRGB for each image, just once per
- system boot. GrabRGB uses about 15,000 bytes of conventional memory once
- loaded.
-
- To illustrate the use of GrabRGB, suppose you have drawn and saved a
- 256-color image with a commercial paint program, and you want to incorporate
- this image into a Fastgraph application. Once you load SNAPSHOT and GrabRGB,
- start the paint program and retrieve your image. Then press the Alt and left
- shift keys to capture the image with SNAPSHOT. After SNAPSHOT's success tone
- (three quick medium-pitched sounds), press Alt and right shift to capture the
- RGB components of each DAC register with GrabRGB, and wait for GrabRGB's
- success tone. Finally, exit the paint program and return to the DOS prompt.
-
- The sequence described in the preceding paragraph will write the RGB
- color components for each DAC register to a file named GRABRGB.nnn in the
- current directory. The file type nnn will be the first sequence of digits
- that does not result in a duplicate file name. That is, if there are no
- GrabRGB output files in the current directory, GrabRGB will use the file name
- GRABRGB.000. The next time you use GrabRGB, it will store the RGB
- information in GRABRGB.001, then GRABRGB.002, and so forth. If you rename or
- delete one of these files, GrabRGB will again use that file name. For
- example, if you delete GRABRGB.000 but keep GRABRGB.001, GrabRGB will next
- use the file name GRABRGB.000.
-
- If GrabRGB is unable to obtain the RGB components of each DAC register,
- it will produce its error tone (a single low-pitched sound). The most common
- cause of this is trying to capture an image from a text video mode, or from a
- graphics video mode with fewer than 256 colors. It also will occur if there
- is not enough disk space or if all 1,000 output file names are already being
- used.
- Appendix A: Fastgraph Utilities 263
-
- Each line in the output file created by GrabRGB is of the form
-
- nnn,rr,gg,bb,
-
- where nnn is a DAC register index (between 0 and 255), rr is the red
- component of that DAC register, gg is the green component, and bb is the blue
- component. Each color component is between 0 and 63. You can edit and
- reformat these lines as necessary for inclusion in a C initializer list, a
- QuickBASIC or FORTRAN data statement, or a Turbo Pascal array-type constant
- list. Such an array of RGB components, but without the nnn indices, is in
- the format expected by fg_setdacs.
-
- By default, GrabRGB captures information for all 256 DAC registers. If
- you want to consider only the DAC registers with color components different
- from their initial values, just include the /D option when you load GrabRGB
- (that is, use the command GRABRGB /D). If you specify the /D option and all
- 256 DACs use their default values, the output file will contain a message
- stating this.
-
-
- HERCFIX Utility
-
- The HERCFIX utility allows you to use SNAPSHOT (and possibly other TSRs)
- with programs that do not update the BIOS data area when establishing the
- 720x348 Hercules graphics mode. If you use SNAPSHOT with such a program, it
- will think the monochrome text mode (video mode 7) is active and will produce
- its low-pitched error tone when activated.
-
- If this occurs, use HERCFIX to load the application from which you are
- trying to capture the image. To do this, enter
-
- HERCFIX command
-
- at the DOS prompt, where command is the command that starts the application.
- For example, suppose you use the command PAINTER /H to run a commercial paint
- program in Hercules graphics mode. To load the paint program with HERCFIX,
- you would enter the command HERCFIX PAINTER /H.
- 264 Fastgraph User's Guide
-
-
- Appendix B
-
- Using Fastgraph
- from Assembly Language
- 266 Fastgraph User's Guide
-
-
- Fastgraph uses the same naming and calling conventions as Microsoft C
- and Turbo C. The details of these conventions that are important to assembly
- language programming are summarized below. If you are calling Fastgraph
- routines from an assembly language program, the program must follow these
- conventions.
-
- All arrays and pointers are passed by reference
- All other items are passed by value
- Arguments are pushed onto the stack in reverse order
- 16-bit function values are returned in the AX register
- 32-bit function values are returned in the DX:AX register pair
- Fastgraph routine names are prefixed with an underscore character
-
- The small and medium model Fastgraph libraries pass arrays and pointers by
- near reference, while the large model library does so by far reference. This
- is consistent with the run-time libraries for the supported compilers.
-
- All Fastgraph routines preserve the BP, DS, DI, and SI registers. The
- contents of any other registers are unknown upon return from a Fastgraph
- routine (except for the AX register, which will either contain zero or the
- routine's return value).
-
- The following DOS commands show how to assemble a program (using the
- Microsoft Macro Assembler) and then link it with Fastgraph. In all cases,
- we'll assume the file EXAMPLE.ASM contains the source code for the program.
- The resulting executable file will be called EXAMPLE.EXE.
-
- small memory model
-
- MASM EXAMPLE.ASM;
- LINK /CP:4096 /E EXAMPLE,,NUL.MAP,FGS
-
-
- medium memory model
-
- MASM EXAMPLE.ASM;
- LINK /CP:4096 /E EXAMPLE,,NUL.MAP,FGM
-
-
- large memory model
-
- MASM EXAMPLE.ASM;
- LINK /CP:4096 /E EXAMPLE,,NUL.MAP,FGL
-
-
- Example B-1 calls the fg_getmode, fg_setmode, fg_reset, and fg_version
- routines from an assembly language program. The fg_getmode routine returns
- its function value in the AX register. The fg_setmode routine has a single
- argument, while fg_reset has no arguments. The fg_version routine has two
- arguments, both passed by reference. Notice how they are pushed on the stack
- in reverse order. This example would work with either the medium or large
- memory model Fastgraph libraries. To make it work with the small model
- library, all you would need to do is change the word "far" to "near" in the
- EXTRN declarations, and change the name of the code segment from "main_TEXT"
- to "_TEXT".
- Appendix B: Using Fastgraph from Assembly Language 267
-
-
- Example B-1.
-
- EXTRN _fg_getmode:far ; Fastgraph's GETMODE routine
- EXTRN _fg_reset:far ; Fastgraph's RESET routine
- EXTRN _fg_setmode:far ; Fastgraph's SETMODE routine
- EXTRN _fg_version:far ; Fastgraph's VERSION routine
-
- stackseg SEGMENT stack ; suppress the linker's
- stackseg ENDS ; "no stack segment" error message
-
- _DATA SEGMENT word public 'DATA'
-
- major dw ? ; major version number
- minor dw ? ; minor version number
- old_mode dw ? ; original video mode
-
- _DATA ENDS
-
- dgroup GROUP _DATA
- ASSUME cs:main_TEXT,ds:dgroup
-
- main_TEXT SEGMENT byte public 'CODE'
-
- start: mov ax,_DATA ; load segment location
- mov ds,ax ; into DS register
-
- call _fg_getmode ; AX = current video mode
- mov old_mode,ax ; save it
-
- mov ax,4 ; use video mode 4
- push ax ; pass argument to SETMODE
- call _fg_setmode ; establish CGA four-color mode
- add sp,2 ; remove SETMODE argument
-
- push old_mode ; pass argument to SETMODE
- call _fg_setmode ; restore original video mode
- add sp,2 ; remove SETMODE argument
-
- call _fg_reset ; restore screen attributes
-
- lea ax,minor ; get address of minor variable
- push ax ; pass argument #2 to VERSION
- lea ax,major ; get address of major variable
- push ax ; pass argument #1 to VERSION
- call _fg_version ; get the Fastgraph version number
- add sp,4 ; remove VERSION arguments
-
- mov ah,76 ; function 76: terminate process
- xor al,al ; errorlevel 0
- int 21h ; exit to DOS
-
- main_TEXT ENDS
- END start
-
- 268 Fastgraph User's Guide
-
-
- Appendix C
-
- Interrupts and Fastgraph
- 270 Fastgraph User's Guide
-
- Interrupts Used by Fastgraph
-
- DOS maintains an interrupt vector table that contains the addresses of
- 256 interrupt handlers, or routines, that perform various functions. The
- handlers are usually referenced by their hexadecimal interrupt number,
- between 00 and FF. Of these, only interrupts 60 through 66 and F1 through FF
- are not used by DOS, the ROM BIOS, or other software and are thus available
- for user applications.
-
- Certain Fastgraph routines use some of the available interrupts.
- Namely, the fg_music routine uses interrupt 60, the asynchronous sound
- routines (fg_musicb, fg_sounds, and fg_voices) use interrupts 60 and 61, and
- all Fastgraph/Light routines use interrupt 62. If your program defines its
- own interrupt handlers, it must not use any of the interrupts reserved for
- Fastgraph (unless, of course, it doesn't use any of the Fastgraph routines
- that would create a conflict).
-
-
- Extending the Time-of-Day Interrupt
-
- As mentioned in Chapter 14, the BIOS time-of-day clock is incremented by
- an interrupt handler. The routine that does this is interrupt 08, a hardware
- interrupt automatically activated 18.2 times per second. After incrementing
- the clock, interrupt 08 invokes interrupt 1C, which by default references a
- "do-nothing" interrupt handler. While changing interrupt 08 can be tricky,
- it is fairly straightforward to define our own handler for interrupt 1C.
- This handler also will be executed automatically 18.2 times per second.
- Example C-1 illustrates how to do this.
-
- When we discussed joysticks in Chapter 12, we said there were two ways
- to monitor joystick button status. One is to intersperse calls to the
- fg_button routine at strategic places in your program and then take necessary
- action depending on the button status. However, the problem with this scheme
- is the chance of missing a button press -- if you press the joystick button
- and then release it between calls to fg_button, the program will not detect
- the joystick activity. A preferable method is to call fg_button from a
- handler for interrupt 1C, which essentially provides continuous monitoring of
- the joystick buttons. When we need the button status within our program, all
- we need to do is examine a global variable.
-
- Example C-1 consists of a main program (written in C) and an assembly
- language subroutine named int1C (suitable for the medium memory model). The
- main program calls int1C to define a handler for interrupt 1C. In response
- to any keystroke (except Escape), the program displays the button press
- information for each joystick since the previous keystroke (refer to the
- discussion of the fg_button routine for the meanings of the status values).
- When you press the Escape key, the program exits to DOS, but not before
- calling int1C to restore the original interrupt 1C handler.
-
- Example C-1 (main program).
-
- #include <fastgraf.h>
- #include <stdio.h>
- void main(void);
-
- #define ESC 27
-
- Appendix C: Interrupts and Fastgraph 271
-
- int status1, status2;
-
- void main()
- {
- unsigned char key, aux;
-
- int1C(1);
-
- status1 = 0;
- status2 = 0;
-
- do {
- printf("\n");
- printf("Joystick 1 status: %d\n",status1);
- printf("Joystick 2 status: %d\n",status2);
- status1 = 0;
- status2 = 0;
- fg_getkey(&key,&aux);
- }
- while (key != ESC);
-
- int1C(0);
- }
-
-
- We'll now examine the int1C assembly language subroutine. It actually
- consists of three parts: a portion to enable our interrupt handler, our
- handler itself, and a portion to disable the handler. When we call int1C
- with a nonzero argument, it saves the original data segment (so we can access
- the global variables within the handler), saves the original handler's
- address (called the vector) for interrupt 1C, and then enables our handler,
- which takes the form of a far procedure.
-
- The handler routine then begins to be activated at 18.2 times per
- second. After saving all the important registers, the handler calls the
- Fastgraph routine fg_button twice, once for each joystick. The return values
- are logically ORed with the status1 and status2 C global variables to update
- the button status information. Finally, the handler restores the original
- registers and returns control to the point of the interrupt.
-
- Before the main program exits, it calls int1C with a zero argument to
- restore the original handler for interrupt 1C. No provision is made in the
- program to check if we had previously defined our own handler (and hence
- saved the original interrupt 1C vector), but this could be added with little
- difficulty.
-
- Example C-1 (assembly language subroutine).
-
-
- EXTRN _status1:word ; C global variable for button 1 status
-
- EXTRN _status2:word ; C global variable for button 2 status
-
- EXTRN _fg_button:far ; Fastgraph routine
-
- 272 Fastgraph User's Guide
-
- int1C_TEXT SEGMENT byte public 'CODE'
-
- ASSUME cs:int1C_TEXT
-
-
- int1C_CS dw ? ; holds original INT 1C segment address
-
- int1C_IP dw ? ; holds original INT 1C offset
-
- orig_DS dw ? ; holds original data segment
-
-
-
- _int1C PROC far
-
- PUBLIC _int1C
-
-
-
- push bp ; save caller's BP register
-
- mov bp,sp ; make BP point to argument list
-
- push si ; save caller's SI register
-
- push di ; save caller's DI register
-
-
-
- mov dx,[bp+6] ; get the flag parameter
-
- or dx,dx ; replace the old interrupt handler?
-
- jz replace ; yes, branch to that processing
-
-
-
- ; define a new handler for INT 1C
-
-
-
- define: mov ax,ds ; put current data segment in AX
-
- mov cs:orig_DS,ax ; save it in the control information area
-
-
-
- mov al,1Ch ; interrupt vector to save
-
- mov ah,53 ; function 53: get interrupt vector
-
- int 21h ; get the interrupt vector
-
- mov cs:int1C_CS,es; save the segment
-
- mov cs:int1C_IP,bx; save the offset
-
- Appendix C: Interrupts and Fastgraph 273
-
-
-
- push ds ; save our DS register
-
- mov dx,offset handler ; get offset of interrupt handler
-
- mov ax,seg handler; get segment of interrupt handler
-
- mov ds,ax ; put it in DS
-
- mov al,1Ch ; interrupt vector to change
-
- mov ah,37 ; function 37: set interrupt vector
-
- int 21h ; change the INT 1C vector to our handler
-
- pop ds ; restore our DS register
-
-
-
- jmp short return ; return to the caller
-
-
-
- ; replace the original handler for INT 1C
-
-
-
- replace: push ds ; save our DS register
-
- mov dx,cs:int1C_IP; put original INT 1C offset in DX
-
- mov ds,cs:int1C_CS; put original INT 1C segment in DS
-
- mov ah,37 ; function 37: set interrupt vector
-
- mov al,1Ch ; interrupt vector 1C
-
- int 21h ; restore original INT 1C vector
-
- pop ds ; restore our DS register
-
-
-
- return: xor ax,ax ; in case int1C was called as a function
-
- pop di ; restore our DI register
-
- pop si ; restore our SI register
-
- pop bp ; restore our BP register
-
- ret
-
-
- _int1C ENDP
-
- 274 Fastgraph User's Guide
-
-
-
- handler PROC far ; interrupt handler that replaces INT 1C
-
-
-
- cli ; disable interrupts while handler active
-
- push ax ; save registers that may be altered
-
- push bx
-
- push cx
-
- push dx
-
- push di
-
- push si
-
- push ds
-
- push es
-
-
-
- mov ds,cs:orig_DS ; retrieve the original data segment
-
-
-
- mov ax,1 ; use joystick 1
-
- push ax ; pass joystick number to button routine
-
- call _fg_button ; AX = button status for joystick 1
-
- add sp,2 ; remove the argument
-
- or _status1,ax ; update status variable for joystick 1
-
-
-
- mov ax,2 ; use joystick 2
-
- push ax ; pass joystick number to button routine
-
- call _fg_button ; AX = button status for joystick 2
-
- add sp,2 ; remove the argument
-
- or _status2,ax ; update status variable for joystick 2
-
-
-
- pop es ; restore altered registers
-
- Appendix C: Interrupts and Fastgraph 275
-
- pop ds
-
- pop si
-
- pop di
-
- pop dx
-
- pop cx
-
- pop bx
-
- pop ax
-
- iret ; return from the interrupt routine
-
-
-
- handler ENDP
-
-
-
- int1C_TEXT ENDS
-
- END
-
-
-
-
- The example just presented is not meant to be a tutorial on interrupts;
- there are many good references on DOS that explain them in detail. However,
- an example specific to Fastgraph should be helpful.
- 276 Fastgraph User's Guide
-
-
- Appendix D
-
- Contents of the
- Compiler-Specific Libraries
- 278 Fastgraph User's Guide
-
-
- For each of the supported Fastgraph compilers except QuickBASIC, there
- is a compiler-specific Fastgraph library (also called the extended Fastgraph
- library) that contains the following routines:
-
-
- fg_circlew fg_getworld fg_rectw fg_setworld
- fg_clprect fg_initw fg_restorew fg_swchar
- fg_dashrw fg_moverw fg_savew fg_swlength
- fg_dashw fg_movew fg_setangle fg_swtext
- fg_drawrw fg_paintw fg_setclipw fg_xscreen
- fg_draww fg_panw fg_setratio fg_xworld
- fg_drectw fg_pointw fg_setsize fg_yscreen
- fg_ellipsew fg_polygonw fg_setsizew fg_yworld
-
-
- These routines use the world space coordinate system, either directly or
- internally. Note that none of them are included in Fastgraph/Light.
-
- As mentioned in Chapter 1, if your program uses any of these routines,
- you must link it with the standard Fastgraph library (FGx.LIB) and the
- compiler-specific Fastgraph library (FGcccx.LIB).
- Index 279
-
- I n d e x
-
- 8253-5 programmable timer chip 234
- Active page 119
- Animation 188
- dynamic frame 194
- dynamic page flipping 196
- page flipping 196
- simple 188
- static frame 192
- static page flipping 196
- summary 198
- XOR 190
- ANSI.SYS 28, 29
- Assembly language 266
- Attribute 48, 104, 105
- Available memory 254
- Background color 49, 50
- Bit maps 136
- CGA 141, 142, 149
- EGA 144, 151
- filler bits 137
- Hercules 144
- MCGA 145
- memory requirements 172
- mode-independent 136
- mode-specific 140
- PCjr 143, 151
- retrieving 169
- subscript order 137, 138, 147
- Tandy 143, 151
- text modes 146
- VGA 144, 145, 151
- Bit-mapped characters 114
- Borland C++ 3, 7
- Byte boundary 174, 175
- CapsLock 212-214
- CGA palettes 51
- Character cells 18
- Character space 40, 100
- Characters
- bit-mapped 114
- hardware 101
- software 108
- Circles 83, 84
- Clearing the screen 76
- CLIP 259, 260
- /M option 259
- /P option 259
- /W option 259
- Clipping 76
- Clock tick 248-250
- Clock tick interrupt 239, 241, 248
- Closed shapes 83
- Color 48
- Color indices 69
-
- 280 Fastgraph User's Guide
-
- Color number 50
- Color value 50
- Compilation 5
- Compiler-specific Fastgraph library 278
- CONVERT 261
- /PPR switch 261
- /SPR switch 261
- Coordinate conversion 44, 107
- Current color 50
- Cursor mask 220, 222
- Dash pattern 82
- Delay units 249, 250
- Display patterns 158
- CGA 159, 160
- EGA 161
- Hercules 161
- MCGA 162, 163
- PCjr 160
- Tandy 160
- VGA 162, 163
- Dithering 88
- Dithering matrix 89
- alignment 94
- CGA 89, 90
- EGA 92
- Hercules 91
- MCGA 93
- PCjr 91
- Tandy 91
- VGA 92, 93
- EDITSPR 261, 262
- Ellipses 83, 84
- EMM386.EXE 129
- EMS 129
- Expanded memory 129
- Expanded Memory Manager 129
- Extended Fastgraph library 278
- Extended memory 129
- Fade 66, 67
- FASTGRAF.BI 6
- FASTGRAF.H 5
- Fastgraph 2
- Fastgraph routines
- fg_allocate 122, 124, 125, 127, 129, 132, 175, 178, 254
- fg_alloccms 129
- fg_allocems 129, 132
- fg_allocxms 129, 132
- fg_automode 33, 34, 36, 77, 84, 86, 206
- fg_bestmode 30, 34, 35, 36, 95, 122, 124, 125
- fg_box 87, 96
- fg_boxdepth 87, 88, 96
- fg_button 228, 229, 231, 270, 271
- fg_capslock 213, 231
- fg_chgattr 104, 114
- fg_chgtext 104, 114
- fg_circle 84, 85, 96
-
- Fastgraph routines (continued)
- fg_circlew 84, 96
- fg_clipmask 166, 167, 184
- fg_clpimage 148, 149, 150, 166, 167, 169, 184
- fg_clprect 86, 96, 188, 195, 196
- fg_clprectw 86, 96
- fg_copypage 129, 131, 133, 175, 176, 184
- fg_cursor 28, 36, 73, 105, 178
- fg_dash 82, 96
- fg_dashrel 82, 97
- fg_dashrw 82, 97
- fg_dashw 82, 97
- fg_defcolor 70, 73, 94
- fg_dispfile 157, 158, 184, 198, 258
- fg_display 153-158, 184, 198
- fg_displayp 154, 155, 156-158, 184, 198
- fg_disppcx 164, 166, 184
- fg_draw 79, 80, 97, 204
- fg_drawmap 114, 136, 138-141, 152, 166, 168-172, 181, 185, 198,
- 222, 226
- fg_drawmask 166, 167, 168, 185
- fg_drawrel 79, 80, 95, 97
- fg_drawrw 79, 97
- fg_draww 79, 97
- fg_drect 88, 89, 92, 93, 94, 97
- fg_drectw 89, 94, 97
- fg_drwimage 114, 141, 142-144, 146, 147, 148-150, 152, 166,
- 167-169, 172, 185, 198, 226
- fg_egacheck 32, 36
- fg_ellipse 84, 85, 97, 192
- fg_ellipsew 84, 97
- fg_erase 76, 97
- fg_fadein 200, 201, 208
- fg_fadeout 200, 208
- fg_flipmask 166, 167, 185
- fg_flpimage 149, 150, 166, 167, 169, 185
- fg_freepage 122, 124, 125, 129, 132, 133, 254
- fg_getaddr 127, 128, 133
- fg_getattr 105, 114
- fg_getchar 105, 114
- fg_getclock 249, 251
- fg_getcolor 49-51, 57, 73
- fg_getdacs 66, 67, 73
- fg_gethpage 176, 185
- fg_getimage 105, 169, 172, 173, 185, 198
- fg_getindex 73
- fg_getkey 212, 231
- fg_getlines 31, 36
- fg_getmap 169-173, 181, 185, 198
- fg_getmaxx 41, 42, 44, 86
- fg_getmaxy 41, 42, 44, 86
- fg_getmode 30, 36, 266
- fg_getpage 127, 133
- fg_getpixel 76, 77, 97
- fg_getrgb 65, 66, 73
- fg_getvpage 127, 133
- fg_getworld 43, 44
- fg_getxjoy 228-231
-
- 282 Fastgraph User's Guide
-
- Fastgraph routines (continued)
- fg_getxpos 79, 97
- fg_getyjoy 228-231
- fg_getypos 79, 97
- fg_hush 240, 242, 244
- fg_hushnext 240, 242, 243, 244
- fg_imagesiz 172, 173, 185
- fg_initems 129, 132, 133
- fg_initjoy 132, 227, 228, 231
- fg_initw 42, 44, 79, 108, 109
- fg_initxms 129, 132, 133
- fg_intjoy 229-231
- fg_intkey 212, 213, 229, 231, 242, 248, 249
- fg_locate 101-103, 107, 114, 120, 126, 173
- fg_makepcx 164, 166, 185
- fg_maprgb 68, 73
- fg_measure 250, 251
- fg_memavail 254, 256
- fg_mousebut 218, 219, 231
- fg_mousecur 220, 221, 231
- fg_mouseini 132, 215, 216, 219, 231
- fg_mouselim 216, 217, 231
- fg_mousemov 216, 217, 231
- fg_mousepos 218, 219, 231
- fg_mouseptr 220, 225, 231
- fg_mousespd 217, 231
- fg_mousevis 216, 217, 219, 232
- fg_move 79, 80, 82, 95, 98, 139, 140, 156, 170, 173, 181, 204
- fg_moverel 79, 80, 98
- fg_moverw 79, 98
- fg_movew 79, 98
- fg_music 237-239, 242, 244, 270
- fg_musicb 242-244, 270
- fg_numlock 213, 232
- fg_paint 95, 98, 204
- fg_paintw 95, 98
- fg_palette 51-60, 62, 64, 65, 68, 69, 74
- fg_palettes 69, 74
- fg_pan 205-208
- fg_panw 205, 206, 208
- fg_pattern 158, 159, 163, 185
- fg_playing 240, 243, 244
- fg_point 76, 77, 98
- fg_pointw 76, 98
- fg_polygon 83, 98
- fg_polygonw 83, 98
- fg_quiet 234, 236, 237, 244
- fg_rect 60, 65, 86, 87, 88, 98, 107, 120, 138, 141, 178, 188, 195
- fg_rectw 86, 98, 113
- fg_reset 29, 30, 36, 266
- fg_resize 131-133, 207, 208
- fg_restore 176-180, 185, 195, 201
- fg_restorew 177, 185
- fg_resume 243, 244
- fg_revimage 149, 150, 166, 167, 169, 185
- fg_revmask 166, 167, 185
-
- Index 283
-
- Fastgraph routines (continued)
- fg_save 176-180, 185
- fg_savew 177, 185
- fg_scrlock 213, 232
- fg_scroll 202-204, 208
- fg_setangle 112, 114
- fg_setattr 48-50, 74, 101, 102, 104, 114, 120, 121, 123, 125
- fg_setcaps 214, 232
- fg_setclip 76, 98, 148
- fg_setclipw 76, 98
- fg_setcolor 28, 49, 50, 51-60, 62, 64, 65, 74, 76, 79, 82, 92, 93,
- 101, 104, 108, 115, 120, 121, 123, 125, 138, 189, 190, 202,
- 203
- fg_setdacs 66, 67, 74, 263
- fg_setfunc 190, 255, 256
- fg_sethpage 176, 177, 178, 185, 200, 202
- fg_setlines 31, 36
- fg_setmode 28, 30, 37, 50, 51, 57, 64, 69, 70, 76, 77, 79, 84, 86,
- 91, 92, 101, 102, 104, 109, 119, 120, 126, 132, 151, 159, 160,
- 161, 162, 210, 215, 227, 266
- fg_setnum 214, 232
- fg_setpage 119, 120, 133, 177
- fg_setratio 109, 111, 115
- fg_setrgb 53, 56, 60, 62, 64-66, 68, 73, 74, 163
- fg_setsize 109, 115
- fg_setsizew 109, 115
- fg_setvpage 119, 128, 133, 196, 216
- fg_setworld 42-44, 109
- fg_sound 234-237, 239, 240, 245
- fg_sounds 239, 240, 242, 245, 270
- fg_stall 249-251
- fg_suspend 243-245
- fg_swchar 108-113, 115
- fg_swlength 113, 115
- fg_swtext 112, 113, 115
- fg_tcmask 183, 185
- fg_tcxfer 183, 186
- fg_testmode 29, 30, 35, 37, 120, 122, 151, 177, 236
- fg_text 28, 101, 102, 103, 104, 108, 115, 119
- fg_transfer 179, 180, 181-183, 186, 194, 195, 196, 201
- fg_version 5, 266
- fg_voice 235-237, 239, 240, 241, 245
- fg_voices 240-242, 245, 270
- fg_waitfor 66, 188, 194, 196, 204, 206, 213, 217, 237, 248-251
- fg_waitkey 29, 212, 232
- fg_where 102, 103, 115, 126
- fg_xalpha 44, 107, 115
- fg_xconvert 44, 45, 107, 115
- fg_xscreen 44, 45, 77
- fg_xworld 44, 45, 79
- fg_yalpha 44, 107, 115
- fg_yconvert 44, 45, 107, 115
- fg_yscreen 44, 45, 77
- fg_yworld 44, 45, 79
- Fastgraph/Light 2
- Fastgraph/Light Video Driver 2, 16
-
- 284 Fastgraph User's Guide
-
- FGDRIVER 16
- /U option 16
- FGTP unit 6
- FGTPX unit 6
- Filler bits 137
- Foreground color 48, 49
- FORTRAN see Microsoft FORTRAN
- Game port 227
- GrabRGB 158, 262, 263
- /D option 263
- output file format 263
- Graphics cursor 79
- Graphics modes 18, 21, 50
- CGA 21, 51, 52
- EGA 23, 56, 58, 59
- extended VGA 24
- Hercules 22, 54, 55
- MCGA 24, 61, 64
- native EGA 23
- native VGA 24
- PCjr 22, 53
- Tandy 53
- Tandy 1000 22
- VGA 24, 61, 63, 64
- Hardware characters 101
- graphics modes 105
- side effects 106
- text modes 101
- HERCFIX 263
- Hidden page 119, 176
- HIMEM.SYS 129
- Hot spot 224
- Image array 147
- Image transfer routines 175
- Images 136
- clipped 148
- regular 141
- reversed 149
- reversed clipped 149
- INCLUDE environment variable 5, 6
- Input devices 210
- INSTALL program 4
- /L option 4
- Installation 4
- Interrupts 270
- INTRFACE.FOR 6
- Joystick 227
- button status 228, 229, 270
- calibration 228
- characteristics 228
- horizontal position 228
- initialize 227
- keyboard emulation 229
- special considerations 230
- vertical position 228
-
- Index 285
- Keyboard 210
- extended codes 210
- standard codes 210
- Keyboard buffer 212, 249
- Keyboard state light 214
- Lines
- dashed 82
- solid 79
- Linking 5
- Logical pages 129
- creating 129
- releasing 129
- Masking map 166, 167
- Memory models 3
- large 3
- medium 3
- small 3
- Memory update function 255
- Mickeys 217
- Microsoft C 3, 8
- Microsoft FORTRAN 3, 9
- Microsoft Mouse 215
- Microsoft QuickBASIC 3, 10
- Microsoft QuickC 3, 11
- Mode X 26
- Mouse 214
- button status 218
- CGA Considerations 226
- cursor 216, 220
- cursor mask 220, 222
- cursor visibility 216
- default cursor 222
- hot spot 224
- initialize 215
- limits 216
- position 216, 218
- screen mask 220, 222
- screen updates 216
- speed 217
- Mouse cursor 216, 220
- graphics modes 222
- hot spot 224
- text modes 220
- Mouse driver 215
- Music 237
- asynchronous 242
- restarting 243
- stopping 242
- suspending 243
- synchronous 237
- Music commands 237
- Music string 237, 242
- Musical notes 237
- Naming conventions 4
- NumLock 212-214
- Overscan 51
- Packed pixel run map 154, 155
-
- 286 Fastgraph User's Guide
-
- Palette 19
- Palette number 53, 56, 58, 59, 62
- Palette registers 53, 56, 58, 59, 61, 63, 69, 70
- Palette value 53, 56, 58, 59
- Palettes 53, 56, 58, 59, 61, 63
- Panning 131, 207
- PC Paintbrush 164
- PCOPTION environment variable 5
- PCX file
- creating 164
- displaying 164
- video mode compatibility 165
- PCX images 164
- Periodic noise 236
- Physical pages 118
- Pixel bleeding 226
- Pixel run 152
- Pixel run file 156-158, 258
- Pixel run map 152, 153, 158
- Pixels 18
- Points 76
- Polygons 83
- Power C 3, 13
- Put_string 103
- QuickBASIC see Microsoft QuickBASIC
- QuickC see Microsoft QuickC
- Real-time operations 248
- Rectangles
- dithered 88
- solid 86
- unfilled 87
- Region fill 95
- Register preservation 266
- Resolution 18
- Reverse video 104
- RGB color mapping 68
- Screen dissolving 200
- Screen mask 220, 222
- Screen origin 205
- Screen space 40, 41
- Scrolling 202
- circular 202
- end-off 202
- Scrolling increment 202
- Scrolling region 202
- ScrollLock 212, 213
- Shadow 104
- Sliding tone 235
- SNAPSHOT 158, 258, 259, 262, 263
- error tone 258
- image files 258
- success tone 258
- Software characters 108
- alternate font 108, 109, 112
- angle 112
- aspect ratio 109
-
- Software characters (continued)
- font change operator (\) 109
- primary font 108, 109
- size 109
- string length 113
- subscript operator (\v) 110
- superscript operator (\^) 110
- underline operator (_) 110
- Sound 234
- asynchronous 239
- disk accesses during 239
- duration 234
- frequency 234
- PCjr 234
- stopping 242
- synchronous 234
- Tandy 234
- volume 234
- Sound effects 234-236
- Splitter cable 227Standard color set 50
- Strlen 103
- Stroke characters 108
- Texas Instruments SN76496A sound chip 234
- Text cursor 28, 101, 126
- Text modes 18, 19, 48
- 43 lines 31
- 50 lines 31
- color 48
- monochrome 49
- TI sound chip 234
- Transparent color 183
- Turbo C 3, 14
- Turbo C++ 3, 14
- Turbo Pascal 3, 15
- Utilities 258
- Vector characters 108
- Video DAC registers 61, 62, 63-66, 69
- Video modes 18
- mode 00 20
- mode 01 20
- mode 02 20
- mode 03 20
- mode 04 21
- mode 05 21
- mode 06 22
- mode 07 20
- mode 09 22
- mode 11 23
- mode 12 23
- mode 13 23
- mode 14 24
- mode 15 24
- mode 16 24
- mode 17 25
- mode 18 25
- mode 19 25
- mode 20 25
-
- Index 287
- Video modes (continued)
- mode 21 25
- mode 22 26
- mode 23 26
- mode X 26
- summary 18
- Video page 118
- Video page resizing 207
- Video pages 19
- active 119
- hidden 119, 176
- information 127
- logical 129
- physical 118
- resizing 131
- segment address 127
- virtual 118, 122
- visual 119
- Video subsystem 19
- Virtual colors 69, 70
- Virtual pages 118
- creating 122
- releasing 122
- special considerations 128
- Visual effects 201
- Visual page 119
- Warbling 235
- White noise 236
- World space 40, 42
- XMS 129