home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Hack-Phreak Scene Programs
/
cleanhpvac.zip
/
cleanhpvac
/
FGL402B.ZIP
/
MANUALS.ARJ
/
USER08.DOC
< prev
next >
Wrap
Text File
|
1995-02-06
|
90KB
|
2,009 lines
Chapter 8
Video Pages and
Virtual Buffers
148 Fastgraph User's Guide
Overview
The amount of memory required to store one full screen of information is
called a video page (or sometimes simply a page). Fastgraph offers a variety
of page types, including physical pages, virtual pages, extended pages, and
logical pages. In addition, virtual buffers let you define arbitrary blocks of
conventional memory and treat them as if they were video memory. This chapter
will discuss video pages and virtual buffers in detail, along with the
Fastgraph routines to manage them.
Physical Pages and Virtual Pages
Pages that use the memory that resides on the video adapter are called
physical pages or true pages. The number of physical pages available depends
on the video mode and the amount of memory resident on the user's video
adapter. All video modes have at least one physical page. In certain video
modes, Fastgraph can allocate available random-access memory (RAM) and treat
this memory as a video page. Pages that use standard RAM in this sense are
called virtual pages. From a programmer's perspective, virtual pages are
essentially identical to physical pages.
The following table shows the number of physical pages in each video
mode. It also indicates whether or not specific video modes support virtual
pages.
Mode Page Size Physical Virtual
Number Description in Bytes Pages Pages
0 40 column color text 2,000 8 no
1 40 column color text 2,000 8 no
2 80 column color text 4,000 4 no
3 80 column color text 4,000 4 no
4 320x200x4 CGA graphics 16,000 1 yes
5 320x200x4 CGA graphics 16,000 1 yes
6 640x200x2 CGA graphics 16,000 1 yes
7 80 column monochrome text 4,000 1 yes
9 320x200x16 Tandy graphics 32,000 1 yes
11 720x348 Hercules graphics 31,320 2 yes
12 320x200 Hercules graphics 31,320 2 yes
13 320x200x16 EGA graphics 32,000 8 no
14 640x200x16 EGA graphics 64,000 4 no
15 640x350 EGA mono graphics 56,000 2 no
16 640x350x16 EGA graphics 112,000 2 no
17 640x480x2 MCGA/VGA graphics 38,400 1+ no
18 640x480x16 VGA graphics 153,600 1+ no
19 320x200x256 MCGA graphics 64,000 1 yes
20 320x200x256 XVGA graphics 64,000 4 no
21 320x400x256 XVGA graphics 128,000 2 no
22 320x240x256 XVGA graphics 76,800 3+ no
23 320x480x256 XVGA graphics 153,600 1+ no
24 640x400x256 SVGA graphics 256,000 4 no
25 640x480x256 SVGA graphics 307,200 2 no
26 800x600x256 SVGA graphics 480,000 2 no
27 1024x768x256 SVGA graphics 786,432 1+ no
Chapter 8: Video Pages and Virtual Buffers 149
28 800x600x16 SVGA graphics 240,000 4 no
29 1024x768x16 SVGA graphics 393,216 2 no
This table assumes the video adapter has 256K of video memory installed for
EGA and VGA modes, and 1MB of video memory for SVGA modes. For adapters with
less video memory, the number of physical pages is reduced proportionately. In
other words, a 64K EGA has two video pages available instead of eight in mode
13. Similarly, a 512K SVGA has one page instead of two in modes 25 and 26, and
wouldn't support mode 27. The next table summarizes the number of video pages
available in SVGA graphics modes for video cards with 256K, 512K, 768K, and
1MB of video memory installed.
Mode Number of pages with...
Number Resolution 256K 512K 768K 1MB
24 640x400x256 1+ 2 3 4
25 640x480x256 0 1+ 1+ 2
26 800x600x256 0 1+ 1+ 2
27 1024x768x256 0 0 1 1+
28 800x600x16 1+ 2 3 4
29 1024x768x16 0 1+ 1+ 2
In the preceding two tables, note that the number of physical pages in
some video modes is followed by a plus symbol. In these modes, there is an
additional partial video page available. For modes 17, 18, and 23, there is
one full page (page 0) plus one partial page of 320 pixel rows (page 1). For
mode 22, there are three full physical pages (numbered 0 to 2) plus one
partial page of 80 pixel rows (page 3). For mode 27, there is one full page
(page 0) plus one partial page of 256 pixel rows (page 1) on a 1MB SVGA card.
You can safely use the partial pages as long as you don't reference pixel rows
beyond their last available row. However, you cannot make a partial video page
the visual page.
In SVGA graphics modes (modes 24 to 29), video pages must begin on 256K
boundaries to maintain compatibility between different SVGA chipsets. This
results in unused video memory at the end of a page. For example, pages in
mode 26 require 480,000 bytes of video memory. On a 1MB SVGA card, the two
pages will begin at 0 and 524,288 (512K). Thus there are 44,288 (524,288 minus
480,000) unused video memory bytes at the end of each page. With 800 pixels
(and hence 800 bytes) per screen row, this means each page has an extra 55
pixel rows per page. The actual page size is therefore 800x655, with the first
600 rows displayed. Similarly, the actual page size in mode 25 is 640x819,
with the first 480 rows displayed.
Physical pages are numbered starting at zero. For example, there are four
physical video pages available in mode 3, and they are numbered 0 to 3.
Virtual pages are numbered n to 63, where n is the number of physical pages in
that mode. For example, there are two physical pages (numbered 0 and 1) and 62
virtual pages (numbered 2 to 63) in mode 11. Note only modes 4 through 12 and
mode 19 offer virtual pages, and the amount of conventional memory in the
user's system usually limits the number of virtual pages available (this is
especially true in mode 19 because of the large page size).
150 Fastgraph User's Guide
Pages With Special Meanings
There are three video pages that have special meanings to Fastgraph. The
visual page, as one might guess, is the video page visible on the user's
display. The active page is the video page to which Fastgraph writes text or
graphics information. The hidden page is meaningful only to a few Fastgraph
routines and will be discussed specifically within the context of those
routines. The fg_setmode routine sets all three of these pages to page 0, and
it does not matter if these pages are physical or virtual.
One of the most useful features of multiple video pages (either physical
or virtual) is the ability to build a text or graphics image off screen (that
is, on some video page besides the visual page). Then, once the image is
ready, we can either transfer it to the visual page, or make the page on which
the image resides the visual page. This feature is especially useful in
animation, for it displays an image instantaneously instead of visibly
updating the screen while producing the image.
Some Simple Examples
In this section, we'll present six variations of a simple program that
uses four video pages. The program fills each video page with a rectangle and
then displays text containing the video page number in the center of each
page. The first two examples run in a specific text or graphics video mode and
only use physical pages. The next two examples also run in a specific text or
graphics video mode, but they also use virtual pages. The final two examples
are more general and run in several video modes. You could of course write a
program that essentially does the same thing as the examples in this section
without using multiple video pages. However, to use Fastgraph's image display
and animation routines effectively, you must first understand the concept of
video pages.
Before proceeding, we must introduce the Fastgraph routines fg_setpage
and fg_setvpage. The fg_setpage routine defines the active video page, which
causes Fastgraph to put subsequent text and graphics output on that page. The
fg_setvpage routine defines the visual video page displayed on the screen.
Both routines take a single integer argument between 0 and 63 that specifies
the video page number. It does not matter if the referenced video page is a
physical page or a virtual page. As mentioned earlier, fg_setmode makes page 0
the active and visual video page.
Example 8-1 uses four video pages (numbered 0 to 3) in the 40-column
color text mode (mode 1). The program first calls fg_testmode to check the
availability of the requested video mode when used with four video pages. If
it is available, the program calls fg_setmode to establish that video mode.
The first for loop fills each of the four pages with different color
rectangles and then displays black text containing the video page number in
the center of each page. It does this by calling fg_setpage to define the
active video page, fg_setcolor and fg_rect to draw the colored rectangles, and
finally fg_setattr, fg_locate, and fg_text to display the text. The program
must call fg_locate inside the loop because each video page has its own text
cursor position. The second for loop successively makes each video page the
visual page; the page remains displayed until you press a key. After
Chapter 8: Video Pages and Virtual Buffers 151
displaying all four video pages, the program restores the original video mode
and screen attributes before returning to DOS.
Example 8-1.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
#define PAGES 4
void main()
{
int color;
int old_mode;
int page;
char string[8];
fg_initpm();
if (fg_testmode(1,PAGES) == 0) {
printf("This program requires color.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(1);
for (page = 0; page < PAGES; page++) {
fg_setpage(page);
color = page + 1;
fg_setcolor(color);
fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setattr(0,color,0);
fg_locate(12,17);
sprintf(string,"page %d",page);
fg_text(string,6);
}
for (page = 0; page < PAGES; page++) {
fg_setvpage(page);
fg_waitkey();
}
fg_setmode(old_mode);
fg_reset();
}
Example 8-2 is similar to example 8-1, but it uses the 320x200 EGA
graphics mode (mode 13) instead of a text mode. Note the only real difference
between this program and the text mode version is the use of fg_setcolor
instead of fg_setattr to make the text appear in black.
Example 8-2.
152 Fastgraph User's Guide
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
#define PAGES 4
void main()
{
int color;
int old_mode;
int page;
char string[8];
fg_initpm();
if (fg_testmode(13,PAGES) == 0) {
printf("This program requires a ");
printf("320 x 200 EGA graphics mode.\n");
exit(1);
}
old_mode = fg_getmode();
fg_setmode(13);
for (page = 0; page < PAGES; page++) {
fg_setpage(page);
color = page + 1;
fg_setcolor(color);
fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setcolor(0);
fg_locate(12,17);
sprintf(string,"page %d",page);
fg_text(string,6);
}
for (page = 0; page < PAGES; page++) {
fg_setvpage(page);
fg_waitkey();
}
fg_setmode(old_mode);
fg_reset();
}
Virtual video pages are created with Fastgraph's fg_allocate routine. The
fg_allocate routine reserves conventional random-access memory (RAM) which
Fastgraph then treats as a video page. The amount of memory required depends
on the current video mode. The fg_allocate routine takes a single integer
argument that specifies the page number by which the virtual page will be
referenced. This value must be between 1 and 63.
If you try to create a virtual page with a page number already assigned
to a physical page, fg_allocate does nothing. For example, in the Hercules
graphics modes (modes 11 and 12) there are two physical pages numbered 0 and
1. Virtual pages in the Hercules graphics modes must thus have page numbers
Chapter 8: Video Pages and Virtual Buffers 153
between 2 and 63. If you tell fg_allocate to create a Hercules virtual page
numbered 0 or 1, it does nothing because those video pages exist as physical
pages. Similarly, if you use fg_allocate in a video mode that does not support
virtual video pages, it simply returns without doing anything.
A possible problem with fg_allocate can occur when there is not enough
memory available for creating a virtual page in the current video mode. The
fg_allocate routine returns as its function value a status code indicating
whether or not it was successful. The possible values of the status code are:
value meaning
0 virtual page created
1 specified page number is a physical page
7 virtual page created, but memory control blocks were destroyed
8 insufficient memory to create the virtual page
If you use fg_testmode or fg_bestmode to check if the required number of video
pages are available when using the requested video mode, you should not need
to monitor the status code returned by fg_allocate.
The fg_freepage routine releases the memory for a virtual page created
with fg_allocate. It requires a single integer argument that identifies the
virtual page number to release. This value must be between 0 and 63. If you
try to release a physical video page, or release a virtual page that was never
created, fg_freepage does nothing. It is a good idea to use fg_freepage to
release all virtual video pages before a program returns control to DOS, or
just before a program selects a new video mode.
Example 8-3 is also similar to example 8-1, but it uses the monochrome
text mode (mode 7). Because the monochrome text mode only has one physical
video page, we must use virtual video pages for page numbers 1, 2, and 3. Note
how fg_allocate and fg_freepage are used to create and release the virtual
video pages in this example.
Example 8-3.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
#define PAGES 4
void main()
{
int old_mode;
int page;
char string[8];
fg_initpm();
if (fg_testmode(7,PAGES) == 0) {
printf("This program requires monochrome.\n");
exit(1);
}
154 Fastgraph User's Guide
old_mode = fg_getmode();
fg_setmode(7);
fg_cursor(0);
for (page = 0; page < PAGES; page++) {
fg_allocate(page);
fg_setpage(page);
fg_setcolor(7);
fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setattr(0,7,0);
fg_locate(12,37);
sprintf(string,"page %d",page);
fg_text(string,6);
}
for (page = 0; page < PAGES; page++) {
fg_setvpage(page);
fg_waitkey();
fg_freepage(page);
}
fg_setmode(old_mode);
fg_reset();
}
Example 8-4 is similar to example 8-3, but it uses the standard Hercules
graphics mode (mode 11) instead of the monochrome text mode. Because the
Hercules graphics modes have two physical video pages, we must use virtual
video pages for page numbers 2 and 3. Note the only real difference between
this program and the text mode version is the use of fg_setcolor instead of
fg_setattr to make the text appear in black.
Example 8-4.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
#define PAGES 4
void main()
{
int old_mode;
int page;
char string[8];
fg_initpm();
if (fg_testmode(11,PAGES) == 0) {
printf("This program requires Hercules ");
printf("monochrome graphics.\n");
exit(1);
}
old_mode = fg_getmode();
Chapter 8: Video Pages and Virtual Buffers 155
fg_setmode(11);
for (page = 0; page < PAGES; page++) {
fg_allocate(page);
fg_setpage(page);
fg_setcolor(7);
fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setcolor(0);
fg_locate(12,37);
sprintf(string,"page %d",page);
fg_text(string,6);
}
for (page = 0; page < PAGES; page++) {
fg_setvpage(page);
fg_waitkey();
fg_freepage(page);
}
fg_setmode(old_mode);
fg_reset();
}
Example 8-5 is a generalized version of examples 8-1 and 8-3 that runs in
any 80-column text video mode. To simplify the program, each video page is
filled with rectangles of the same color. Note that fg_allocate and
fg_freepage are used to manage the virtual video pages in case fg_bestmode
selects the monochrome text mode (mode 7). If fg_bestmode selects one of the
80-column color text modes (which have four physical video pages), fg_allocate
and fg_freepage will simply return without doing anything.
Example 8-5.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
#define PAGES 4
void main()
{
int old_mode, new_mode;
int page;
char string[8];
fg_initpm();
new_mode = fg_bestmode(80,25,PAGES);
if (new_mode < 0) {
printf("This program requires ");
printf("an 80-column display.\n");
exit(1);
}
old_mode = fg_getmode();
156 Fastgraph User's Guide
fg_setmode(new_mode);
fg_cursor(0);
for (page = 0; page < PAGES; page++) {
fg_allocate(page);
fg_setpage(page);
fg_setcolor(7);
fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setattr(0,7,0);
fg_locate(12,37);
sprintf(string,"page %d",page);
fg_text(string,6);
}
for (page = 0; page < PAGES; page++) {
fg_setvpage(page);
fg_waitkey();
fg_freepage(page);
}
fg_setmode(old_mode);
fg_reset();
}
Example 8-6 is a generalized version of examples 8-2 and 8-4 that runs in
any 320x200 graphics video mode. To simplify the program, each video page is
filled with rectangles of the same color. As in example 8-5, fg_allocate and
fg_freepage are used to manage the virtual video pages in case fg_bestmode
selects a video mode with fewer than four physical video pages. Note the only
real difference between this program and the text mode version is the use of
fg_setcolor instead of fg_setattr to make the text appear in black.
Example 8-6.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
#define PAGES 4
void main()
{
int old_mode, new_mode;
int page;
char string[8];
fg_initpm();
new_mode = fg_bestmode(320,200,PAGES);
if (new_mode < 0) {
printf("This program requires a ");
printf("320 x 200 graphics mode.\n");
exit(1);
}
Chapter 8: Video Pages and Virtual Buffers 157
old_mode = fg_getmode();
fg_setmode(new_mode);
for (page = 0; page < PAGES; page++) {
fg_allocate(page);
fg_setpage(page);
fg_setcolor(15);
fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setcolor(0);
fg_locate(12,17);
sprintf(string,"page %d",page);
fg_text(string,6);
}
for (page = 0; page < PAGES; page++) {
fg_setvpage(page);
fg_waitkey();
fg_freepage(page);
}
fg_setmode(old_mode);
fg_reset();
}
Text Cursors
As mentioned in the previous chapter, Fastgraph draws hardware characters
at the position defined by the text cursor. Like the graphics cursor, the text
cursor is not a cursor in the true sense, but is simply a pair of character
space (row,column) coordinates with a special meaning. The first 8 video pages
(that is, pages 0 through 7) each have their own text cursor. Each subsequent
group of 8 video pages (pages 8 through 15, pages 16 to 23, and so forth)
respectively share the same text cursor positions as the first 8 pages. This
means fg_locate will update one of 8 different text cursors depending on the
active video page. Similarly, fg_where returns the text cursor position for
the active page. The fg_setmode routine sets all 8 text cursor positions to
the character space coordinates (0,0).
Example 8-7 demonstrates the use of different text cursors in an 80-
column color text mode (mode 3). The program first displays the text "Page "
on video page 0 (the visible page) and waits for a keystroke. It then makes
page 1 the active video page, changes the text cursor location for that page,
and displays the text "Page 1" on video page 1. Next, it appends the character
"0" to the text originally displayed on page 0. Note that we don't need to
restore the text cursor position for page 0 because it is unaffected by
changing the text cursor for page 1. After waiting for another keystroke, the
program makes video page 1 the visual page and then waits for yet another
keystroke before returning to DOS.
Example 8-7.
#include <fastgraf.h>
void main(void);
158 Fastgraph User's Guide
void main()
{
int old_mode;
fg_initpm();
old_mode = fg_getmode();
fg_setmode(3);
fg_cursor(0);
fg_setattr(10,0,0);
fg_locate(1,0);
fg_text("Page ",5);
fg_waitkey();
fg_setpage(1);
fg_locate(23,0);
fg_text("Page 1",6);
fg_setpage(0);
fg_text("0",1);
fg_waitkey();
fg_setvpage(1);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
Obtaining Video Page Information
Fastgraph includes two routines, fg_getpage and fg_getvpage, that
respectively return the active or visual video page number. Each routine
returns the video page number as its function value, and neither routine
requires any arguments.
When creating virtual or logical pages, you must choose a page number
that does not reference a physical page or a previously created virtual or
logical page. While it's of course possible to keep track of which page
numbers will be available in a given video mode, Fastgraph's fg_findpage
function can make the job easier. It returns an unused page number, which you
can then pass to any of Fastgraph's virtual or logical page allocation
routines. If there are no more available (that is, all 64 entries in the
internal page tables are in use), fg_findpage returns zero.
The fg_getaddr routine is sometimes useful when using virtual pages. It
returns as its function value the segment address (in real mode) or segment
selector (in protected mode) for the start of the active video page. It does
not require any arguments. Although fg_getaddr is more useful when using
virtual video pages, it works equally well with physical video pages.
Example 8-9 illustrates the use of fg_getpage, fg_getvpage, fg_findpage,
and fg_getaddr in the standard VGA/MCGA 256-color graphics mode (mode 19).
This video mode offers only one physical page, so the program uses fg_findpage
Chapter 8: Video Pages and Virtual Buffers 159
to find an unused page number (which will be page 1 in mode 19), and then
calls fg_allocate to create a virtual video page. After creating the virtual
page, the program makes it the active video page; page 0 remains the visual
video page. The fg_getpage routine then returns the active page number,
followed by a call to fg_getvpage to return the visual page number (0). Next,
the program uses fg_getaddr to return the segment address/selector for the two
video pages. Finally, it restores the original video mode and screen
attributes, displays the returned values, and returns to DOS.
Example 8-9.
#include <fastgraf.h>
#include <stdio.h>
void main(void);
void main()
{
int old_mode;
int active, visual;
int page, page0, page1;
fg_initpm();
old_mode = fg_getmode();
fg_setmode(19);
page = fg_findpage();
fg_allocate(page);
fg_setpage(page);
active = fg_getpage();
visual = fg_getvpage();
fg_setpage(0);
page0 = fg_getaddr();
fg_setpage(page);
page1 = fg_getaddr();
fg_freepage(page);
fg_setmode(old_mode);
fg_reset();
printf("Active page is %d.\n",active);
printf("Visual page is %d.\n",visual);
printf("Page 0 address is %4X\n",page0);
printf("Page %d address is %4X\n",page,page1);
}
Considerations for Virtual Pages
If you're using Power C, any supported BASIC compiler, Borland Pascal, or
Turbo Pascal and need to create virtual pages, you must reduce the size of the
far heap. Normally, these compilers allocate all remaining memory for the
heap, which means fg_allocate will not be able to allocate memory for the
virtual page.
160 Fastgraph User's Guide
In BASIC programs, the SETMEM function reduces the size of the far heap.
The BASIC versions of the Fastgraph example programs include the statement
SetMemStatus& = SETMEM(-n)
before calling FGallocate. This reduces the size of the far heap by n bytes.
For a given video mode, the actual reduction needed is the number of virtual
pages multiplied by the page size in that mode. Page sizes are listed at the
beginning of this chapter, or you can use fg_pagesize to determine the page
size for the current video mode.
In Borland Pascal and Turbo Pascal, the $M compiler directive defines the
maximum heap size in bytes. The Pascal versions of the Fastgraph example
programs include the statement
{$M 16384,0,16384}
at the beginning of the examples that call fg_allocate. The third value in
this list defines the maximum heap size at 16K bytes. This is suitable for
most applications, but if your program uses the New or GetMem procedures to
create dynamic variables that require more heap space, you'll need to increase
the size beyond 16K.
The far heap size for Power C programs is defined at link time. You must
override the default heap size by including the option [,,16K] on the PCL
command when you link a Power C program that uses fg_allocate. The value 16K
is suitable for most applications, but if your program calls the farcalloc or
farmalloc functions (or the calloc or malloc functions when using the large
memory model), you may need to increase the far heap size beyond 16K.
When you are using virtual pages, you should avoid using the fg_setvpage
routine in sections of the program that require fast screen updates or
animation sequences. This is because the PC and PS/2 video BIOS are only
capable of displaying physical pages. To compensate for this restriction,
Fastgraph exchanges the contents of a physical page with the requested virtual
page. In other words, if page 1 is a virtual page and you make it the visual
page, Fastgraph will exchange the contents of page 1 with whatever page was
previously the visual page. This does not mean Fastgraph's page numbers change
because Fastgraph also maintains an internal table containing video page
addresses and exchanges the two corresponding table entries. As before, you
would make page 1 the active video page if you wanted to write something to
the visual page.
About the only other potential problem when using virtual pages is what
happens when you try to write to a non-existent video page (for example, if
you write to virtual video page 1 before creating it with fg_allocate). In
this case, Fastgraph simply redirects the video output to the visual page.
Considerations for SuperVGA Pages
If an program running in an SVGA graphics mode returns to text mode when
the visual page is not page 0, some SVGA chipsets have problems the next time
you try to run an SVGA application. We therefore recommend calling
fg_setvpage(0) just before restoring the original video mode if an application
performs page flipping in SVGA graphics modes. For example:
Chapter 8: Video Pages and Virtual Buffers 161
old_mode = fg_getmode();
fg_svgainit(0);
fg_setmode(25);
.
.
.
fg_setvpage(1);
.
.
.
fg_setvpage(0); /* add this line to be safe */
fg_setmode(old_mode);
A few SVGA chipsets cannot set the display start address beyond the 16-
bit capability provided by the CRT Controller, rendering fg_setvpage
meaningless. Please refer to the READ.ME file for details.
Logical Pages
In addition to physical and virtual video pages, Fastgraph offers another
class of video pages, called logical pages. You can create logical pages in
any video mode. They can exist in conventional memory, expanded memory (EMS),
or extended memory (XMS). However, they are not as versatile as physical or
virtual pages because the only operations you can perform with logical pages
are:
* Copy an entire physical or virtual page to a logical page
* Copy an entire logical page to a physical or virtual page
* Copy an entire logical page to another logical page
Three Fastgraph routines -- fg_alloccms, fg_allocems, and fg_allocxms --
create logical pages in conventional memory, expanded memory, and extended
memory, respectively. All three routines have a single integer argument that
specifies the page number by which the logical page will be referenced. The
page number must be between 1 and 63 and must not reference a physical or
virtual page. Their return value is 0 if the logical page is created, and
negative otherwise (refer to the descriptions of these routines in the
Fastgraph Reference Manual for a complete list of return values). As with
virtual pages, use fg_freepage to release a logical page.
Before you can create logical pages in expanded or extended memory, you
must initialize these resources for use with Fastgraph. The fg_initems routine
initializes expanded memory. To use expanded memory, you must have an Expanded
Memory Manager (EMM) that conforms to the Lotus/Intel/Microsoft Expanded
Memory Specification (LIM-EMS) version 3.2 or later. On 80386 and 80486
systems, the EMM386.EXE device driver supplied with DOS 5.0 can be used to
treat some or all of extended memory as expanded memory. The fg_initxms
routine initializes extended memory for use with Fastgraph. To use extended
memory, you must have an XMS driver that conforms to the
Lotus/Intel/Microsoft/AST eXtended Memory Specification version 2.0 or later,
such as HIMEM.SYS. XMS drivers require an 80286, 80386, or 80486 system. The
fg_initems and fg_initxms routines have no arguments and must be called after
fg_setmode. Their return value is 0 if successful, and -1 if the required
driver and resources are not present.
162 Fastgraph User's Guide
In protected mode, the distinction between conventional, expanded, and
extended memory disappears because DOS extenders essentially treat all system
memory as conventional memory. For this reason, fg_initems and fg_initxms are
not meaningful and thus always return -1 in the protected mode Fastgraph
libraries. This effectively disables the fg_allocems and fg_allocxms routines,
so you must create logical pages with fg_alloccms in protected mode.
Example 8-10 illustrates the use of logical pages in a 320x200 color
graphics mode. The program first tries to create a logical page in extended
memory by calling fg_initxms and fg_allocxms. If the initialization or page
creation fails, it then tries to create the page in expanded memory with
fg_initems and fg_allocems. Should that fail, the program calls fg_alloccms to
try to create the page in conventional memory. If it can't create the logical
page at all, the program displays an error message and exits.
Once the logical page is created, example 8-10 displays the word "test"
in the middle of the visual page (page 0) and then uses fg_copypage to
transfer the visual page contents to the logical page. Because this program
runs in one of several different graphics modes, we use fg_findpage to choose
the logical page number. After waiting for a keystroke, the program erases the
visual page, waits for another keystroke, and copies the logical page contents
back to the visual page. It then releases the logical page and exits.
Example 8-10.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int new_mode, old_mode;
int page, status;
fg_initpm();
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);
page = fg_findpage();
status = fg_initxms();
if (status == 0) status = fg_allocxms(page);
if (status < 0) {
status = fg_initems();
if (status == 0) status = fg_allocems(page);
}
if (status < 0) status = fg_alloccms(page);
if (status < 0) {
Chapter 8: Video Pages and Virtual Buffers 163
fg_setmode(old_mode);
fg_reset();
printf("Unable to create logical page.\n");
exit(1);
}
fg_setcolor(7);
fg_rect(0,319,0,199);
fg_setcolor(9);
fg_locate(12,18);
fg_text("test",4);
fg_waitkey();
fg_copypage(0,page);
fg_erase();
fg_waitkey();
fg_copypage(page,0);
fg_waitkey();
fg_freepage(page);
fg_setmode(old_mode);
fg_reset();
}
As mentioned before, the only functions you can perform with logical
pages are copying physical/virtual pages to logical pages, logical pages to
physical/virtual pages, or copying one logical page to another. The
fg_copypage routine provides the only way to do this for logical pages. See
Chapter 11 for more information about fg_copypage.
Extended Video Pages
One of the more frequent technical support questions we receive is "I
have one megabyte of memory on my video card, why can I only use the first
256K?". The answer is simple: the standard EGA and VGA graphics modes have no
way to address video memory beyond 256K. Accessing more memory requires SVGA
bank switching techniques. This is analogous to the fact that you might have
four megabytes of RAM on your system, but without an EMS/XMS memory manager, a
DOS extender, or the like, all that memory won't do much good.
Unfortunately, not all SVGA chipsets allow bank switching in non-SVGA
video modes. For those that do, however, Fastgraph includes a feature called
extended video pages. Extended pages provide access to all video memory in
modes 13 to 18 and modes 20 to 23 instead of restricting access to the first
256K. This means, for example, that a 1MB SVGA card will allow 32 physical
pages in mode 13 rather than the usual 8 pages. Extended pages are available
with the following SVGA chipsets:
* Ahead B
* ATI 28800/38800/68800/88800
* Avance Logic 2000 series
* NCR 77C22/77C32
* Oak OTI-067
164 Fastgraph User's Guide
* Oak OTI-077
* Oak OTI-087
* Paradise WD90C11/WD90C30/WD90C31/WD90C33
* Tseng ET4000
Although extended pages are used in non-SVGA graphics modes, the method
of accessing video memory above 256K is specific to each SVGA chipset. Thus,
you must initialize Fastgraph's SVGA kernel (with fg_svgainit) before you can
use extended pages. We haven't yet found a VESA implementation that supports
extended pages, so you'll need to initialize the SVGA kernel for chipset-
specific support.
When writing applications that use extended video pages, you should make
sure the user's SVGA chipset supports extended pages and that there is enough
video memory for the number of pages required. First, make sure fg_svgainit
successfully initializes the SVGA kernel. If so, check bit 2 of the
fg_svgastat return value to see if the chipset supports extended pages.
Finally, use fg_memory to insure that enough video memory is available for the
number of video pages needed.
The following table shows the number of video pages available in the
graphics modes that support extended pages.
Number of Pages With
Mode 256K 512K 1MB
13 8 16 32
14 4 8 16
15 2 4 8
16 2 4 8
17 2 4 8
18 2 4 8
20 4 8 16
21 2 4 8
22 4 8 16
23 2 4 8
Note that when extended pages are not enabled, the video mode has the number
of physical video pages listed in the 256K column.
Some video modes do not provide the listed number of full video pages.
For example, modes 17 and 18 normally have two video pages -- one full 640x480
page (page 0) and one partial 640x320 page (page 1). For extended pages,
Fastgraph uses a page numbering scheme that maintains consistency with its
standard page numbering. That is, when extended pages are available and mode
17 or 18 is used on a 1MB video card, the page numbers will range from 0 to 7,
with the even-numbered pages being full pages and the odd-numbered pages being
partial 640x320 pages. Similarly, in mode 22 pages 3, 7, 11, and 15 are
partial (320x80); in mode 23 odd-numbered pages are partial (320x320).
When you use Fastgraph's block transfer routines (fg_copypage,
fg_restore, fg_save, fg_tcxfer, and fg_transfer) with extended pages, you must
pass the source and destination page numbers to fg_defpages. This is needed
because the two pages may reside in different SVGA banks, and bank switching
is not performed in Fastgraph's non-SVGA code. The additional overhead of
having the block transfer routines determine the bank numbers would impact the
Chapter 8: Video Pages and Virtual Buffers 165
block transfer routines when extended pages are not being used. The
fg_defpages routine determines the SVGA bank numbers in which the source and
destination pages reside and then enables the corresponding banks for reading
and writing. These banks remain in effect until you define new ones with
fg_defpages or fg_setpage, so you may not need to call fg_defpages before
every call to a block transfer routine. The fg_defpages routine has no effect
unless extended pages are enabled. The following table shows the bank numbers
for each video page in each graphics mode that supports extended pages.
Bank 0 Bank 1 Bank 2 Bank 3
Mode Pages Pages Pages Pages
13 0-7 8-15 16-23 24-31
14 0-3 4-7 8-11 12-15
15 0-1 2-3 4-5 6-7
16 0-1 2-3 4-5 6-7
17 0-1 2-3 4-5 6-7
18 0-1 2-3 4-5 6-7
20 0-3 4-7 8-11 12-15
21 0-1 2-3 4-5 6-7
22 0-3 4-7 8-11 12-15
23 0-1 2-3 4-5 6-7
Next we'll present a short code sequence that calls fg_defpages only when
needed in mode 13, where each group of 8 pages resides in its own SVGA bank.
Calling fg_setmode enables bank 0 for reading and writing, so we don't need to
call fg_defpages until we reference a page in one of the other banks (that is,
a page numbered 8 or above).
fg_svgainit(0);
fg_setmode(13); /* enables bank 0 for reading and writing */
fg_copypage(0,1);
fg_copypage(0,2);
fg_defpages(0,1); /* page 10 is in bank 1 */
fg_copypage(2,10);
fg_defpages(1,1); /* page 15 is in bank 1 */
fg_copypage(10,15);
fg_setpage(0); /* enables bank 0 for reading and writing */
fg_erase();
fg_copypage(0,3);
fg_defpages(1,0); /* page 15 is in bank 1 */
fg_copypage(15,4);
Most mouse drivers know nothing about SVGA bank switching and non-
standard video modes (that's why Fastgraph must hook its own mouse cursor
control handlers into the mouse driver in XVGA and SVGA modes). As Fastgraph
relies on the mouse driver for cursor control in modes 13 to 18, it's only
possible to display the mouse cursor on video pages in the first SVGA bank
(bank 0) in these modes. Note that this does not apply to modes 20 to 23,
where Fastgraph controls the mouse cursor through its own handler.
Some SVGA chipsets do not reset the read and write bank numbers back to
zero when establishing a non-SVGA video mode. When a mode set operation clears
video memory, such chipsets will clear the first video page in the last write
bank selected. While fg_setmode does set the read and write banks to zero when
extended pages are available, it cannot do this before setting the video mode,
166 Fastgraph User's Guide
which is what normally would clear the screen. This may result in artifacts on
page 0 after calling fg_setmode. The easiest way around this problem is to
call fg_defpages(0,0) before restoring the original video mode in programs
that use extended pages. Even this, however, does not clear video memory after
a mode set when using extended pages with some SVGA chipsets. We therefore
recommend calling fg_erase immediately after restoring the original video mode
when using extended pages.
Video Page Resizing
Resizing is the process of changing the dimensions of a video page. It is
available only in the native EGA graphics modes (modes 13 to 16), native VGA
graphics modes (17 and 18), extended VGA modes (20 to 23), and SVGA modes (24
to 29). Resizing does not change the screen resolution, but instead increases
the video page size so only part of the page is visible. For now, we'll just
introduce resizing with a simple example, but in Chapter 13 we'll see its real
power when we perform smooth panning.
The Fastgraph routine fg_resize changes the dimensions of a video page.
Its two integer arguments define the page width and page height, both in
pixels. Example 8-11 runs in the 320x200 EGA graphics mode (mode 13). After
establishing the video mode, it displays the word "resize" starting in column
38 of row 0. Because the characters extend beyond the last column of the row,
they wrap to the next row. The program continues displaying this until you
press a key. Then, it clears the screen and calls fg_resize to make the page
size 640x200 pixels. Again the program displays the word "resize" starting in
column 38 of row 0, but this time it does not wrap to the next row. This is
because the resizing doubled the page width, which increased the number of
character cells per row from 40 to 80. The characters that formerly wrapped to
the next row now continue on an off-screen portion of the same row.
Example 8-11.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
void main(void);
void main()
{
int old_mode;
fg_initpm();
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(9);
fg_locate(0,38);
fg_text("resize",6);
Chapter 8: Video Pages and Virtual Buffers 167
fg_waitkey();
fg_erase();
fg_resize(640,200);
fg_setcolor(10);
fg_locate(0,38);
fg_text("resize",6);
fg_waitkey();
fg_setmode(old_mode);
fg_reset();
}
The size of a video page is constrained only by the amount of video
memory available and the addressability of the video mode. Increasing the
video page size reduces the number of physical pages available proportionally.
In mode 13, for example, increasing the page size from 320x200 to 640x400
reduces the number of video pages from 8 to 2. When you call fg_resize, the
visual page must be page 0. If you have created any logical video pages, you
must release them with fg_freepage before calling fg_resize, and then create
them again afterward. If you have initialized the mouse (with fg_mouseini),
joysticks (with fg_initjoy), expanded memory (with fg_initems), or extended
memory (with fg_initxms), you should re-initialize these resources after
calling fg_resize. In modes 13 to 18, most mouse drivers expect a fixed video
page width, so the mouse cursor may become distorted after resizing video
pages in these modes. When you call fg_resize, Fastgraph sets the clipping
region to the new page limits. The fg_setmode routine re-establishes the
dimensions of a video page to the default screen resolution for the selected
video mode. The fg_resize routine has no effect when a virtual buffer is
active.
Depending on the dimensions passed to fg_resize, you may end up with a
partial video page. Again, suppose we're using mode 13 and have changed the
page size to 960x400 (this is six times the default page size). The original
pages 0 to 5 now make up page 0, and original pages 6 and 7 now make up page
1. However, there is not enough video memory left on page 1 for a full 960x400
page. In this case, the number of pixel rows available on page 1 would be one-
third the full page size, or 133 rows. This is because the total storage
required by original pages 6 and 7 is one-third the total required for
original pages 0 through 5.
Extended video pages may be resized in modes 13-18 and 20-23, but the
resulting pages must not cross SVGA bank boundaries. In mode 20, for instance,
you normally have four 320x200 pages in each bank. You could change the video
page size to 640x400, thereby having four larger pages, one in each bank. You
could not, however, resize video memory to two 640x800 pages, as each page
would span two banks.
Preserving Video Page Contents Across Mode Switches
Sometimes a graphics program may temporarily need to switch to another
video mode. An example of this might be a graphical user interface (GUI)
menuing system that includes "shell to DOS" as one of its options. When the
user selects this option, the program must revert to a text video mode so the
168 Fastgraph User's Guide
user will see the familiar DOS prompt when the shell executes. On leaving the
DOS shell, the program returns to a graphics mode and should ideally restore
the screen to what it was originally.
When you establish a video mode with fg_setmode, Fastgraph clears all
physical video pages and initializes its internal page tables as if no virtual
or logical pages have been created. While it's not possible to preserve
physical page contents across video mode switches, you can use Fastgraph's
fg_getentry and fg_setentry routines to save virtual or logical page contents.
The trick, so to speak, is using fg_getentry to save the virtual or logical
page address and type before switching video modes. Then, when you return to
the same video mode, you can use fg_setentry to restore the internal page
tables to their previous state. This effectively makes the virtual or logical
page accessible again.
Example 8-12 illustrates this process. This program runs in video mode
18, the 640x480 16-color VGA graphics mode. After establishing this video
mode, the program calls fg_alloccms to create a logical page in conventional
memory. Next, it calls fg_getentry to save the address and type of the logical
page just created. The first argument to fg_getentry specifies the page number
(determined by fg_findpage); the next two arguments receive the page address
and type. Page type codes used by fg_getentry and fg_setentry are:
0 = unallocated page
1 = physical page
2 = virtual page
3 = logical page in expanded memory (EMS)
4 = logical page in extended memory (XMS)
5 = logical page in conventional memory
After this setup work, example 8-12 fills the screen with light blue
pixels, draws a white box around the edge, and then waits for a keystroke.
Before switching back to the original video mode (assumed to be mode 3), the
program uses fg_copypage to copy the visual page contents to the logical page.
This is necessary because we can only save virtual or logical page contents
across video mode changes, not physical pages. In mode 3, the program prompts
for a keystroke before returning to mode 18.
Now we're ready to restore the previous contents of the visual page.
Because the example program did not release the logical page, the memory is
still allocated; Fastgraph just cannot access it. To solve this, the program
calls fg_setentry to restore Fastgraph's internal page table entries for the
original logical page number to what they were previously. Note how we use the
same page address and type values in the call to fg_setentry that were
returned earlier by fg_getentry. Now that the logical page is once again
accessible, the program can use fg_copypage to copy its contents back to the
visual page. With that explanation behind us, here is example 8-12.
Example 8-12.
#include <fastgraf.h>
void main(void);
void main()
{
int old_mode;
Chapter 8: Video Pages and Virtual Buffers 169
int page, page_addr, page_type;
fg_initpm();
old_mode = fg_getmode();
fg_setmode(18);
page = fg_findpage();
fg_alloccms(page);
fg_getentry(page,&page_addr,&page_type);
fg_setcolor(9);
fg_fillpage();
fg_setcolor(15);
fg_box(0,639,0,479);
fg_waitkey();
fg_copypage(0,page);
fg_setmode(old_mode);
fg_cursor(0);
fg_setcolor(15);
fg_text("Press any key.",14);
fg_waitkey();
fg_setmode(18);
fg_setentry(page,page_addr,page_type);
fg_copypage(page,0);
fg_waitkey();
fg_freepage(page);
fg_setmode(old_mode);
fg_reset();
}
To keep the example as simple as possible, it does not test for
availability of video modes, nor does it check if the logical page creation
was successful. In a real application, of course, omitting these checks is not
recommended. See example 8-17 for a version of this program that uses virtual
buffers instead of logical pages.
Controlling Page Allocation
When Fastgraph creates virtual or logical pages in conventional memory
with fg_allocate or fg_alloccms, it uses the DOS allocate memory service
(function 48 hex of interrupt 21 hex). Some compilers allocate all or part of
available conventional memory to a data structure called the heap or far heap.
Memory allocation functions such as malloc handle their requests through an
associated heap manager instead of through DOS services. If the heap manager
controls all available memory, the DOS allocate memory service is essentially
disabled because there will be no memory available to satisfy allocation
requests. If the heap manager controls some but not all available memory, a
conflict may arise between the heap manager and the DOS allocate memory
service.
To solve this problem, you can use the compiler's allocate far memory
function to reserve memory for the virtual or logical page and then make the
170 Fastgraph User's Guide
page known to Fastgraph with fg_setentry. The easiest way to determine the
amount of memory to allocate is through the fg_pagesize function, which
returns the page size in bytes (as a long integer) for the current video mode.
To release the page, use fg_setentry with a page type of zero to mark the page
as unallocated before actually freeing the memory. Pages created this way are
not initially cleared because the allocated memory block contents are
undefined. We recommend using fg_erase to set the page contents to the
background color.
Example 8-13 shows how to create a virtual page in real mode programs
using these techniques instead of fg_allocate. It uses the farmalloc and
farfree functions from the C run-time library for Borland compilers (the
analogous Microsoft functions are _fmalloc and _ffree). Example 8-13 uses
fg_pagesize and the Borland run-time library function farmalloc to create a
virtual page in the 320x200 VGA/MCGA 256-color graphics mode. After allocating
the memory, the program calls fg_setentry, passing it the page number (1), the
segment portion of the memory block address (using the FP_SEG macro from the
run-time library), and the code for a virtual page (2). Once the virtual page
is set up, the program writes some text on the virtual page and then uses
fg_copypage to display the virtual page contents on the visual page. Finally,
it releases the page by calling fg_setentry (so Fastgraph knows the virtual
page is gone) and the farfree run-time library function (to actually free the
memory). The call to fg_setentry is not really needed in this instance because
no further references are made to page 1.
Example 8-13.
#include <fastgraf.h>
#include <dos.h>
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#define farfree(p) _ffree(p)
#define farmalloc(n) _fmalloc(n)
#endif
void main(void);
void main()
{
int old_mode;
unsigned page_addr;
char far *buffer;
old_mode = fg_getmode();
fg_setmode(19);
buffer = farmalloc(fg_pagesize()+16);
page_addr = FP_SEG(buffer) + (FP_OFF(buffer)+15)/16;
fg_setentry(1,page_addr,2);
fg_setpage(1);
fg_erase();
fg_setcolor(9);
fg_text("This is page 1.",15);
fg_waitkey();
Chapter 8: Video Pages and Virtual Buffers 171
fg_copypage(1,0);
fg_setentry(1,0,0);
fg_waitkey();
farfree(buffer);
fg_setmode(old_mode);
fg_reset();
}
Virtual Buffers
Virtual buffers are blocks of conventional memory that you can treat as
video memory. They are much more general than virtual pages, as they are
supported in all graphics video modes and can be smaller or larger than the
actual page size. An application may have up to 32 virtual buffers open
simultaneously. Each virtual buffer has its own independent clipping limits,
which default to the entire virtual buffer. Any program that uses virtual
buffers must initialize the virtual buffer environment by calling fg_vbinit
once, before it calls any of Fastgraph's other virtual buffer routines. The
fg_vbinit routine has no arguments and no return value.
In protected mode, and when using real mode compilers that support huge
arrays (far arrays whose size may exceed 64K), use fg_vbdefine to create
virtual buffers. The fg_vbdefine routine defines a block of previously
allocated memory as a virtual buffer. Usually this memory is allocated
dynamically with the malloc or farmalloc functions in C or C++, the
GlobalAllocPtr function in protected mode Pascal, or the ALLOCATE statement in
protected mode FORTRAN. The fg_vbdefine routine returns a handle by which the
virtual buffer is referenced in other Fastgraph routines. Two related virtual
buffer routines are fg_vbundef, which releases a virtual buffer handle, and
fg_vbhandle, which returns the active virtual buffer handle (or -1 if no
virtual buffer is active).
The number of bytes required for a virtual buffer is simply its width in
pixels multiplied by its height in pixels, regardless of the current video
mode. The virtual buffer layout is equally simple. For instance, a 320x200
virtual buffer requires 64,000 bytes. The first 320 bytes represent the first
row of the virtual buffer, the next 320 bytes represent the second row, and so
forth. Within each of the 200 such rows, each of the 320 bytes represents one
pixel. This means, for example, the (0,0) pixel in the virtual buffer would be
at offset 0, the (2,0) pixel would be at offset 2, and the (2,1) pixel would
be at offset 322. In general, the offset of the (x,y) pixel is given by the
formula y*virtual_buffer_width + x.
The method of dynamically allocating memory suitable for virtual buffers
is compiler and environment dependent. When using 32-bit protected mode, the
virtual buffer memory resides in the program's default data segment and is
referenced through a standard near pointer. In 16-bit environments, the
virtual buffer memory is a huge array and is referenced through a far pointer.
The following examples illustrate how to allocate memory for a 640x400 virtual
buffer for each compiler that supports dynamic allocation of huge memory
blocks.
172 Fastgraph User's Guide
For Borland C++ (16-bit), Turbo C++, Turbo C:
char huge *buffer;
buffer = (char huge *)farmalloc(640L*400L);
For Microsoft C/C++, QuickC, Visual C++, 16-bit WATCOM C/C++:
char huge *buffer;
buffer = (char huge *)halloc(640L*400L,1);
For 32-bit C/C++ compilers:
char *buffer;
buffer = (char *)malloc(640*400);
For Borland Pascal 7 (protected mode):
var buffer : pointer;
buffer := GlobalAllocPtr(gmem_Fixed,Longint(640)*Longint(400));
For Microsoft FORTRAN PowerStation:
INTEGER*1 BUFFER[ALLOCATABLE](:)
INTEGER STATUS
ALLOCATE(BUFFER(640*400),STAT=STATUS)
Real mode BASIC, Pascal, and FORTRAN compilers have limited, if any,
support for huge arrays. In these environments, use fg_vballoc to create
virtual buffers. The fg_vballoc routine uses the DOS allocate memory service
to reserve virtual buffer memory. The supported BASIC compilers and real mode
Turbo Pascal normally assign all unused conventional memory to an area called
the far heap. At best, this will cause DOS memory allocation requests to fail,
but more often it creates memory conflicts that manifest themselves later in
your application. To solve this problem, you must tell the compiler to reduce
the size of the far heap.
Real mode Pascal programmers must use the $M directive to reduce the far
heap size by the total space needed for all virtual buffers. If you wanted to
use a 640x400 virtual buffer, for example, the following $M directive would
reduce the far heap size by 256,000 bytes:
{$M 16384,0,256000}
BASIC programmers must use the SETMEM function to reduce the far heap
size by the total space needed for all virtual buffers, plus 16 bytes per
virtual buffer. If you wanted to use a 640x400 virtual buffer in a BASIC
program, the following SETMEM call would reduce the far heap size by 256,016
bytes:
SetMemStatus& = SETMEM(-256016)
After you're finished with a virtual buffer, its memory may be released
using fg_vbfree. You should use fg_vbfree only with virtual buffers created
with fg_vballoc and not those created with fg_vbdefine, and you cannot use it
on the active virtual buffer. As fg_vballoc and fg_vbfree are needed for real
mode only, they are not present in the Fastgraph protected mode libraries. For
Chapter 8: Video Pages and Virtual Buffers 173
virtual buffers created with fg_vbdefine, just use your compiler's standard
method for releasing dynamic memory blocks.
Once a virtual buffer is defined, you can activate it with fg_vbopen.
When a virtual buffer is active, most Fastgraph routines operate on that
virtual buffer instead of video memory. This will continue until you call
fg_vbclose, which redirects graphics operations back to the active video page.
If you later want to activate the virtual buffer again, or if you want to
switch to another virtual buffer previously created with fg_vbdefine, you can
use fg_vbopen for this purpose.
Two of Fastgraph's more important virtual buffer routines are fg_vbpaste
and fg_vbcut. These routines move rectangular areas between the active virtual
buffer and the active video page. The fg_vbcut routine copies an area from the
active video page to the active virtual buffer. Similarly, fg_vbpaste copies
an area from the active virtual buffer to the active video page. An especially
useful property of fg_vbcut and fg_vbpaste is that they each remember the most
recent active virtual buffer and video page. This feature makes it possible to
move areas back and forth between a virtual buffer and video memory without
continuously opening and closing the virtual buffer.
The fg_vbpaste routine performs a simple translation for pixel values
greater than the number of colors available in the current video mode. This
could happen, for example, if you used fg_vbcut in a 256-color graphics mode
and later used fg_vbpaste to display the virtual buffer contents in a 16-color
graphics mode. Should this occur, fg_vbpaste will display pixels of color c in
color c modulo n, where n is the number of colors available in the current
video mode.
At this point, some example programs should help clarify the use of
virtual buffers. Our first example, 8-14, runs in the standard VGA/MCGA
320x200 256-color graphics mode (mode 19) and creates a virtual buffer twice
as high and twice as wide as the screen size. This means we'll create a
640x400 virtual buffer requiring 256,000 bytes of conventional memory
(conditional compilation sequences show how to allocate the virtual buffer
memory for different compilers). If the virtual buffer was created
successfully, the program calls fg_vbopen to activate the virtual buffer and
then draws four 320x200 rectangles of different colors, one in each quadrant
of the virtual buffer. It then uses fg_vbpaste to copy each rectangle to the
active video page, followed by another call to show the center 320x200 portion
of the virtual buffer (this will display equal parts of the four rectangles).
Example 8-14.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#endif
#define WIDTH 640
#define HEIGHT 400
174 Fastgraph User's Guide
void main(void);
void main()
{
int handle;
int old_mode;
#ifdef FG32
char *buffer;
#else
char huge *buffer;
#endif
/* initialize the video environment */
fg_initpm();
old_mode = fg_getmode();
fg_setmode(19);
fg_vbinit();
/* set up a 640x400 virtual buffer */
#ifdef FG32
buffer = (char *)malloc(WIDTH*HEIGHT);
#elif defined(__TURBOC__)
buffer = (char huge *)farmalloc((long)WIDTH*(long)HEIGHT);
#else
buffer = (char huge *)halloc((long)WIDTH*(long)HEIGHT,1);
#endif
if (buffer == NULL) {
fg_setmode(old_mode);
fg_reset();
printf("Could not create the virtual buffer.\n");
exit(1);
}
handle = fg_vbdefine(buffer,WIDTH,HEIGHT);
fg_vbopen(handle);
/* draw a 320x200 rectangle in each virtual buffer quadrant */
fg_setcolor(9);
fg_rect(0,319,0,199);
fg_setcolor(10);
fg_rect(320,639,0,199);
fg_setcolor(11);
fg_rect(0,319,200,399);
fg_setcolor(12);
fg_rect(320,639,200,399);
/* paste each rectangle to the 320x200 active video page */
fg_vbpaste(0,319,0,199,0,199);
fg_waitkey();
fg_vbpaste(320,639,0,199,0,199);
fg_waitkey();
fg_vbpaste(0,319,200,399,0,199);
fg_waitkey();
Chapter 8: Video Pages and Virtual Buffers 175
fg_vbpaste(320,639,200,399,0,199);
fg_waitkey();
/* paste the center 320x200 subset of the virtual buffer */
fg_vbpaste(160,479,100,299,0,199);
fg_waitkey();
/* close the virtual buffer */
fg_vbclose();
/* restore original video mode and exit */
fg_setmode(old_mode);
fg_reset();
}
Calling fg_vbclose before the final fg_setmode call is necessary because
fg_setmode has no effect when a virtual buffer is active. If we didn't call
fg_vbclose, the program would return to DOS in mode 19 instead of the original
video mode.
If you instead wanted to allocate the virtual buffer memory with
fg_vballoc in example 8-14, the steps to create the virtual buffer would
change as follows:
/* set up a 640x400 virtual buffer */
handle = fg_vballoc(WIDTH,HEIGHT);
if (handle < 0) {
fg_setmode(old_mode);
fg_reset();
printf("Could not create the virtual buffer.\n");
exit(1);
}
fg_vbopen(handle);
If you create the virtual buffer with fg_vballoc, you also should use
fg_vbfree to release the virtual buffer memory when it's no longer needed:
/* close the virtual buffer */
fg_vbclose();
fg_vbfree(handle);
Again, we recommend using fg_vballoc and fg_vbfree only with 16-bit compilers
that do not provide easy methods for creating huge arrays.
Example 8-15 illustrates the use of the fg_vbcut routine, which
essentially performs the inverse operation of fg_vbpaste. That is, fg_vbcut
copies a rectangular area from the active video page to the active virtual
buffer. The program begins by drawing a 20x20 blue rectangle with a white
border in the upper left corner of the active video page. After a keystroke,
it sets up a 20x20 virtual buffer and calls fg_vbcut to copy the rectangle to
176 Fastgraph User's Guide
the virtual buffer. The program then calls fg_vbpaste in a loop to display 16
copies of the virtual buffer contents across the bottom of the screen. Note
that example 8-15 uses a virtual buffer that is just 20 pixels square, or 400
bytes total. Because it is so small, we chose to declare a 400-byte array for
the virtual buffer instead of allocating its memory dynamically as in the
previous example. Note also that because the virtual buffer array size is less
than 64K bytes, we can declare it far instead of huge in 16-bit environments
(huge arrays less than 64K are functionally equivalent to far arrays).
Example 8-15.
#include <fastgraf.h>
#define WIDTH 20
#define HEIGHT 20
void main(void);
#ifdef FG32
char buffer[WIDTH*HEIGHT];
#else
char far buffer[WIDTH*HEIGHT];
#endif
void main()
{
int handle;
int old_mode;
int x;
fg_initpm();
old_mode = fg_getmode();
fg_setmode(19);
fg_vbinit();
fg_setcolor(15);
fg_rect(0,WIDTH-1,0,HEIGHT-1);
fg_setcolor(9);
fg_rect(1,WIDTH-2,1,HEIGHT-2);
fg_waitkey();
handle = fg_vbdefine(buffer,WIDTH,HEIGHT);
fg_vbopen(handle);
fg_vbcut(0,WIDTH-1,0,HEIGHT-1,0,HEIGHT-1);
for (x = 0; x <= 320-WIDTH; x += WIDTH)
fg_vbpaste(0,WIDTH-1,0,HEIGHT-1,x,199);
fg_waitkey();
fg_vbclose();
fg_setmode(old_mode);
fg_reset();
}
Chapter 8: Video Pages and Virtual Buffers 177
If you create a virtual buffer that is taller or wider than the page size
(or perhaps both taller and wider), it's possible to perform virtual buffer
scrolling. To achieve a scrolling effect, you generally just call fg_vbpaste
iteratively such that the source region in the virtual buffer increments
gradually, while the destination region on the active video page stays the
same. Depending on the video mode and the size of the scrolling region, you
may need to include a delay factor between fg_vbpaste calls so the area being
scrolled doesn't appear to jump immediately to its ultimate destination.
Example 8-16 performs virtual buffer scrolling. This example runs in the
XVGA 320x200 256-color graphics mode (mode 20) and creates a 1000x50 virtual
buffer using the method of example 8-14. The program fills the virtual buffer
with a series of one-pixel wide rectangles, each 50 pixels high and in
alternating colors. The actual scrolling takes place in the loop containing
the two fg_vbpaste calls. We'll define a 100x50 area in the middle of the
visual page, with horizontal extremes between 110 and 209, and vertical
extremes between 75 and 124, as our scrolling region. We'll scroll the top
half (25 pixels) of the virtual buffer from right to left while scrolling the
bottom half from left to right. In other words, we'll be moving two 100x25
subsets of the virtual buffer through the scrolling region.
The first fg_vbpaste call scrolls the top half of the virtual buffer. The
starting x coordinate defining the region to transfer from the virtual buffer
ranges from 0 to 900 in one-pixel increments, and the width of the transfer
region is always 100 pixels. The height of the transfer region remains
constant at 25 pixels (virtual buffer rows 0 to 24). The destination position
is the upper half of the scrolling region on the visual page; its lower left
corner is at x=110 and y=99.
The second fg_vbpaste call, which scrolls the bottom half of the virtual
buffer but in the opposite direction, behaves similarly. In this case, the
starting x coordinate in the virtual buffer decreases from 900 to 0 in one-
pixel steps, and its width is always 100 pixels. The height of the transfer
region is again 25 pixels, but this time it uses rows 25 to 49 in the virtual
buffer. The destination position is the lower half of the scrolling region on
the visual page; its lower left corner is at x=110 and y=124.
Example 8-16.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#endif
#define WIDTH 1000
#define HEIGHT 50
void main(void);
void main()
{
int handle;
178 Fastgraph User's Guide
int old_mode;
int x;
#ifdef FG32
char *buffer;
#else
char huge *buffer;
#endif
/* initialize the video environment */
fg_initpm();
old_mode = fg_getmode();
fg_setmode(20);
fg_vbinit();
/* fill the screen with light blue pixels */
fg_setcolor(9);
fg_fillpage();
/* set up the virtual buffer */
#ifdef FG32
buffer = (char *)malloc(WIDTH*HEIGHT);
#elif defined(__TURBOC__)
buffer = (char huge *)farmalloc((long)WIDTH*(long)HEIGHT);
#else
buffer = (char huge *)halloc((long)WIDTH*(long)HEIGHT,1);
#endif
if (buffer == NULL) {
fg_setmode(old_mode);
fg_reset();
printf("Could not create the virtual buffer.\n");
exit(1);
}
handle = fg_vbdefine(buffer,WIDTH,HEIGHT);
fg_vbopen(handle);
/* fill the virtual buffer with a series of narrow rectangles */
for (x = 0; x < WIDTH; x++) {
fg_setcolor(x);
fg_rect(x,x,0,HEIGHT-1);
}
/* scroll the virtual buffer through a 100x50 window on the */
/* visual page, such that the top half scrolls left and the */
/* bottom half scrolls right */
for (x = 0; x < WIDTH-99; x++) {
fg_vbpaste(x,x+99,0,24,110,99);
fg_vbpaste(WIDTH-100-x,WIDTH-1-x,25,49,110,124);
}
fg_waitkey();
/* close the virtual buffer */
Chapter 8: Video Pages and Virtual Buffers 179
fg_vbclose();
/* restore original video mode and exit */
fg_setmode(old_mode);
fg_reset();
}
The last virtual buffer example program we'll present in this chapter is
a version of example 8-12 modified to work with virtual buffers. Example 8-12
used a logical page in conventional memory to preserve the visual page
contents across video mode switches, with some help from Fastgraph's
fg_getentry and fg_setentry routines. Example 8-17 illustrates how you can
accomplish the same thing with a virtual buffer. It runs in the 320x240 256-
color graphics mode (mode 22) and uses a virtual buffer whose size is
identical to the screen resolution. After creating the virtual buffer, the
program fills the visual page with blue pixels and draws a white border around
it. It then uses fg_vbcut to copy the screen contents to the virtual buffer.
Like example 8-12, the program temporarily switches back to the original video
mode and waits for a keystroke. It then reverts to mode 22 and uses fg_vbpaste
to restore the screen contents.
Example 8-17.
#include <fastgraf.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#endif
void main(void);
void main()
{
int handle;
int old_mode;
#ifdef FG32
char *buffer;
#else
char huge *buffer;
#endif
fg_initpm();
old_mode = fg_getmode();
fg_setmode(22);
fg_vbinit();
#ifdef FG32
buffer = (char *)malloc(320*240);
#elif defined(__TURBOC__)
buffer = (char huge *)farmalloc(320L*240L);
180 Fastgraph User's Guide
#else
buffer = (char huge *)halloc(320L*240L,1);
#endif
if (buffer == NULL) {
fg_setmode(old_mode);
fg_reset();
printf("Could not create the virtual buffer.\n");
exit(1);
}
handle = fg_vbdefine(buffer,320,240);
fg_setcolor(9);
fg_fillpage();
fg_setcolor(15);
fg_box(0,319,0,239);
fg_vbopen(handle);
fg_vbcut(0,319,0,239,0,239);
fg_vbclose();
fg_waitkey();
fg_setmode(old_mode);
fg_cursor(0);
fg_setcolor(15);
fg_text("Press any key.",14);
fg_waitkey();
fg_setmode(22);
fg_vbopen(handle);
fg_vbpaste(0,319,0,239,0,239);
fg_waitkey();
fg_vbclose();
fg_setmode(old_mode);
fg_reset();
}
Fastgraph includes other functions for working with virtual buffers, but
we'll defer our discussion of them until later chapters.
Summary of Video Page and Virtual Buffer 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_ALLOCATE creates a virtual video page. The amount of memory required
depends on the current video mode. This routine has no effect if it references
a physical or logical video page.
FG_ALLOCEMS creates a logical page in expanded memory (EMS). The amount
of memory required depends on the current video mode and video buffer
dimensions. This routine has no effect if it references a physical or virtual
Chapter 8: Video Pages and Virtual Buffers 181
video page. In protected mode, fg_initems always fails, so fg_allocems is
effectively disabled.
FG_ALLOCXMS creates a logical page in extended memory (XMS). The amount
of memory required depends on the current video mode and video buffer
dimensions. This routine has no effect if it references a physical or virtual
video page. In protected mode, fg_initxms always fails, so fg_allocxms is
effectively disabled.
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. This routine always
applies to video pages, even when a virtual buffer is active.
FG_DEFPAGES defines the SVGA banks for the source and destination page
numbers when using Fastgraph's block transfer routines with extended video
pages.
FG_FINDPAGE finds an available video page number for a virtual or logical
page.
FG_FREEPAGE releases a virtual or logical video page created with
fg_allocate, fg_alloccms, fg_allocems, or fg_allocxms. This routine has no
effect if it references a physical video page, or a virtual page that was
never created.
FG_GETADDR returns the real mode segment address or protected mode
segment selector for the active video page.
FG_GETENTRY retrieves the type and address of a physical, virtual, or
logical video page. This routine is useful for saving virtual or logical page
contents across video mode changes.
FG_GETPAGE returns the active video page number.
FG_GETVPAGE returns the visual video page number.
FG_INITEMS initializes expanded memory for use with Fastgraph's logical
pages. In protected mode, the expanded memory initialization will always fail.
FG_INITXMS initializes extended memory for use with Fastgraph's logical
pages. In protected mode, the extended memory initialization will always fail.
FG_PAGESIZE returns the video page size in bytes for the current video
mode. The page size is always the video page size, even when a virtual buffer
is active.
FG_RESIZE changes the dimensions of a video page in EGA and VGA graphics
modes. This function has no effect when a virtual buffer is active.
FG_SETENTRY specifies the type and address of a physical, virtual, or
logical video page. For logical pages, it further specifies if the page
resides in conventional, expanded, or extended memory. This routine is useful
for saving virtual or logical page contents across video mode changes, or for
manual creation of virtual and logical pages.
182 Fastgraph User's Guide
FG_SETPAGE establishes the active video page. It may be a physical or
virtual page.
FG_SETVPAGE establishes the visual video page. It may be a physical or
virtual page.
FG_VBALLOC creates a virtual buffer of the specified size. The memory for
the virtual buffer is allocated automatically. This routine should be used
instead of fg_vbdefine for real mode compilers that do not support huge memory
blocks (that is, far blocks larger than 64K bytes). The fg_vballoc routine is
not present in Fastgraph's protected mode libraries.
FG_VBCLOSE closes the active virtual buffer and directs graphics output
back to the active video page.
FG_VBCUT copies a rectangular region from the active video page to the
active virtual buffer.
FG_VBDEFINE creates a virtual buffer of the specified size.
FG_VBFREE releases a virtual buffer's handle and frees the memory
allocated to a virtual buffer created with fg_vballoc. The fg_vbfree routine
is not present in Fastgraph's protected mode libraries.
FG_VBHANDLE returns the handle for the active virtual buffer, or -1 if no
virtual buffer is active.
FG_VBINIT initializes Fastgraph's virtual buffer environment. This
routine must be called once, before any other routines that reference virtual
buffers.
FG_VBOPEN makes an existing virtual buffer the active virtual buffer.
FG_VBPASTE copies a rectangular region from the active virtual buffer to
the active video page.
FG_VBUNDEF releases the handle associated with a virtual buffer.