home *** CD-ROM | disk | FTP | other *** search
/ C++ Games Programming / CPPGAMES.ISO / fgl / fglight / manuals.arj / USER08.DOC < prev    next >
Text File  |  1995-02-06  |  90KB  |  2,009 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7. Chapter 8
  8.  
  9.  
  10.  
  11.  
  12.  
  13. Video Pages and
  14. Virtual Buffers                                                                
  15. 148   Fastgraph User's Guide
  16.  
  17.  
  18. Overview
  19.  
  20.      The amount of memory required to store one full screen of information is
  21. called a video page (or sometimes simply a page). Fastgraph offers a variety
  22. of page types, including physical pages, virtual pages, extended pages, and
  23. logical pages. In addition, virtual buffers let you define arbitrary blocks of
  24. conventional memory and treat them as if they were video memory. This chapter
  25. will discuss video pages and virtual buffers in detail, along with the
  26. Fastgraph routines to manage them.
  27.  
  28.  
  29. Physical Pages and Virtual Pages
  30.  
  31.      Pages that use the memory that resides on the video adapter are called
  32. physical pages or true pages. The number of physical pages available depends
  33. on the video mode and the amount of memory resident on the user's video
  34. adapter. All video modes have at least one physical page. In certain video
  35. modes, Fastgraph can allocate available random-access memory (RAM) and treat
  36. this memory as a video page. Pages that use standard RAM in this sense are
  37. called virtual pages. From a programmer's perspective, virtual pages are
  38. essentially identical to physical pages.
  39.  
  40.      The following table shows the number of physical pages in each video
  41. mode. It also indicates whether or not specific video modes support virtual
  42. pages.
  43.  
  44.       Mode                               Page Size Physical   Virtual
  45.      Number  Description                 in Bytes    Pages     Pages
  46.  
  47.        0     40 column color text           2,000      8        no
  48.        1     40 column color text           2,000      8        no
  49.        2     80 column color text           4,000      4        no
  50.        3     80 column color text           4,000      4        no
  51.        4     320x200x4 CGA graphics        16,000      1        yes
  52.        5     320x200x4 CGA graphics        16,000      1        yes
  53.        6     640x200x2 CGA graphics        16,000      1        yes
  54.        7     80 column monochrome text      4,000      1        yes
  55.        9     320x200x16 Tandy graphics     32,000      1        yes
  56.        11    720x348 Hercules graphics     31,320      2        yes
  57.        12    320x200 Hercules graphics     31,320      2        yes
  58.        13    320x200x16 EGA graphics       32,000      8        no
  59.        14    640x200x16 EGA graphics       64,000      4        no
  60.        15    640x350 EGA mono graphics     56,000      2        no
  61.        16    640x350x16 EGA graphics      112,000      2        no
  62.        17    640x480x2 MCGA/VGA graphics   38,400     1+        no
  63.        18    640x480x16 VGA graphics      153,600     1+        no
  64.        19    320x200x256 MCGA graphics     64,000      1        yes
  65.        20    320x200x256 XVGA graphics     64,000      4        no
  66.        21    320x400x256 XVGA graphics    128,000      2        no
  67.        22    320x240x256 XVGA graphics     76,800     3+        no
  68.        23    320x480x256 XVGA graphics    153,600     1+        no
  69.        24    640x400x256 SVGA graphics    256,000      4        no
  70.        25    640x480x256 SVGA graphics    307,200      2        no
  71.        26    800x600x256 SVGA graphics    480,000      2        no
  72.        27    1024x768x256 SVGA graphics   786,432     1+        no             
  73.                              Chapter 8:  Video Pages and Virtual Buffers   149
  74.  
  75.        28    800x600x16 SVGA graphics     240,000      4        no
  76.        29    1024x768x16 SVGA graphics    393,216      2        no
  77.  
  78. This table assumes the video adapter has 256K of video memory installed for
  79. EGA and VGA modes, and 1MB of video memory for SVGA modes. For adapters with
  80. less video memory, the number of physical pages is reduced proportionately. In
  81. other words, a 64K EGA has two video pages available instead of eight in mode
  82. 13. Similarly, a 512K SVGA has one page instead of two in modes 25 and 26, and
  83. wouldn't support mode 27. The next table summarizes the number of video pages
  84. available in SVGA graphics modes for video cards with 256K, 512K, 768K, and
  85. 1MB of video memory installed.
  86.  
  87.                        Mode              Number of pages with...
  88.                       Number  Resolution   256K 512K 768K 1MB
  89.  
  90.                         24    640x400x256   1+    2   3    4
  91.                         25    640x480x256    0   1+   1+   2
  92.                         26    800x600x256    0   1+   1+   2
  93.                         27    1024x768x256   0    0   1   1+
  94.                         28    800x600x16    1+    2   3    4
  95.                         29    1024x768x16    0   1+   1+   2
  96.  
  97.      In the preceding two tables, note that the number of physical pages in
  98. some video modes is followed by a plus symbol. In these modes, there is an
  99. additional partial video page available. For modes 17, 18, and 23, there is
  100. one full page (page 0) plus one partial page of 320 pixel rows (page 1). For
  101. mode 22, there are three full physical pages (numbered 0 to 2) plus one
  102. partial page of 80 pixel rows (page 3). For mode 27, there is one full page
  103. (page 0) plus one partial page of 256 pixel rows (page 1) on a 1MB SVGA card.
  104. You can safely use the partial pages as long as you don't reference pixel rows
  105. beyond their last available row. However, you cannot make a partial video page
  106. the visual page.
  107.  
  108.      In SVGA graphics modes (modes 24 to 29), video pages must begin on 256K
  109. boundaries to maintain compatibility between different SVGA chipsets. This
  110. results in unused video memory at the end of a page. For example, pages in
  111. mode 26 require 480,000 bytes of video memory. On a 1MB SVGA card, the two
  112. pages will begin at 0 and 524,288 (512K). Thus there are 44,288 (524,288 minus
  113. 480,000) unused video memory bytes at the end of each page. With 800 pixels
  114. (and hence 800 bytes) per screen row, this means each page has an extra 55
  115. pixel rows per page. The actual page size is therefore 800x655, with the first
  116. 600 rows displayed. Similarly, the actual page size in mode 25 is 640x819,
  117. with the first 480 rows displayed.
  118.  
  119.      Physical pages are numbered starting at zero. For example, there are four
  120. physical video pages available in mode 3, and they are numbered 0 to 3.
  121. Virtual pages are numbered n to 63, where n is the number of physical pages in
  122. that mode. For example, there are two physical pages (numbered 0 and 1) and 62
  123. virtual pages (numbered 2 to 63) in mode 11. Note only modes 4 through 12 and
  124. mode 19 offer virtual pages, and the amount of conventional memory in the
  125. user's system usually limits the number of virtual pages available (this is
  126. especially true in mode 19 because of the large page size).                    
  127. 150   Fastgraph User's Guide
  128.  
  129.  
  130. Pages With Special Meanings
  131.  
  132.      There are three video pages that have special meanings to Fastgraph. The
  133. visual page, as one might guess, is the video page visible on the user's
  134. display. The active page is the video page to which Fastgraph writes text or
  135. graphics information. The hidden page is meaningful only to a few Fastgraph
  136. routines and will be discussed specifically within the context of those
  137. routines. The fg_setmode routine sets all three of these pages to page 0, and
  138. it does not matter if these pages are physical or virtual.
  139.  
  140.      One of the most useful features of multiple video pages (either physical
  141. or virtual) is the ability to build a text or graphics image off screen (that
  142. is, on some video page besides the visual page). Then, once the image is
  143. ready, we can either transfer it to the visual page, or make the page on which
  144. the image resides the visual page. This feature is especially useful in
  145. animation, for it displays an image instantaneously instead of visibly
  146. updating the screen while producing the image.
  147.  
  148.  
  149. Some Simple Examples
  150.  
  151.      In this section, we'll present six variations of a simple program that
  152. uses four video pages. The program fills each video page with a rectangle and
  153. then displays text containing the video page number in the center of each
  154. page. The first two examples run in a specific text or graphics video mode and
  155. only use physical pages. The next two examples also run in a specific text or
  156. graphics video mode, but they also use virtual pages. The final two examples
  157. are more general and run in several video modes. You could of course write a
  158. program that essentially does the same thing as the examples in this section
  159. without using multiple video pages. However, to use Fastgraph's image display
  160. and animation routines effectively, you must first understand the concept of
  161. video pages.
  162.  
  163.      Before proceeding, we must introduce the Fastgraph routines fg_setpage
  164. and fg_setvpage. The fg_setpage routine defines the active video page, which
  165. causes Fastgraph to put subsequent text and graphics output on that page. The
  166. fg_setvpage routine defines the visual video page displayed on the screen.
  167. Both routines take a single integer argument between 0 and 63 that specifies
  168. the video page number. It does not matter if the referenced video page is a
  169. physical page or a virtual page. As mentioned earlier, fg_setmode makes page 0
  170. the active and visual video page.
  171.  
  172.      Example 8-1 uses four video pages (numbered 0 to 3) in the 40-column
  173. color text mode (mode 1). The program first calls fg_testmode to check the
  174. availability of the requested video mode when used with four video pages. If
  175. it is available, the program calls fg_setmode to establish that video mode.
  176. The first for loop fills each of the four pages with different color
  177. rectangles and then displays black text containing the video page number in
  178. the center of each page. It does this by calling fg_setpage to define the
  179. active video page, fg_setcolor and fg_rect to draw the colored rectangles, and
  180. finally fg_setattr, fg_locate, and fg_text to display the text. The program
  181. must call fg_locate inside the loop because each video page has its own text
  182. cursor position. The second for loop successively makes each video page the
  183. visual page; the page remains displayed until you press a key. After           
  184.                              Chapter 8:  Video Pages and Virtual Buffers   151
  185.  
  186. displaying all four video pages, the program restores the original video mode
  187. and screen attributes before returning to DOS.
  188.  
  189.                                  Example 8-1.
  190.  
  191.                 #include <fastgraf.h>
  192.                 #include <stdio.h>
  193.                 #include <stdlib.h>
  194.                 void main(void);
  195.  
  196.                 #define PAGES 4
  197.  
  198.                 void main()
  199.                 {
  200.                    int color;
  201.                    int old_mode;
  202.                    int page;
  203.                    char string[8];
  204.  
  205.                    fg_initpm();
  206.                    if (fg_testmode(1,PAGES) == 0) {
  207.                       printf("This program requires color.\n");
  208.                       exit(1);
  209.                       }
  210.  
  211.                    old_mode = fg_getmode();
  212.                    fg_setmode(1);
  213.  
  214.                    for (page = 0; page < PAGES; page++) {
  215.                       fg_setpage(page);
  216.                       color = page + 1;
  217.                       fg_setcolor(color);
  218.                       fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  219.                       fg_setattr(0,color,0);
  220.                       fg_locate(12,17);
  221.                       sprintf(string,"page %d",page);
  222.                       fg_text(string,6);
  223.                       }
  224.  
  225.                    for (page = 0; page < PAGES; page++) {
  226.                       fg_setvpage(page);
  227.                       fg_waitkey();
  228.                       }
  229.  
  230.                    fg_setmode(old_mode);
  231.                    fg_reset();
  232.                 }
  233.  
  234.  
  235.      Example 8-2 is similar to example 8-1, but it uses the 320x200 EGA
  236. graphics mode (mode 13) instead of a text mode. Note the only real difference
  237. between this program and the text mode version is the use of fg_setcolor
  238. instead of fg_setattr to make the text appear in black.
  239.  
  240.                                  Example 8-2.                                  
  241. 152   Fastgraph User's Guide
  242.  
  243.                 #include <fastgraf.h>
  244.                 #include <stdio.h>
  245.                 #include <stdlib.h>
  246.                 void main(void);
  247.  
  248.                 #define PAGES 4
  249.  
  250.                 void main()
  251.                 {
  252.                    int color;
  253.                    int old_mode;
  254.                    int page;
  255.                    char string[8];
  256.  
  257.                    fg_initpm();
  258.                    if (fg_testmode(13,PAGES) == 0) {
  259.                       printf("This program requires a ");
  260.                       printf("320 x 200 EGA graphics mode.\n");
  261.                       exit(1);
  262.                       }
  263.  
  264.                    old_mode = fg_getmode();
  265.                    fg_setmode(13);
  266.  
  267.                    for (page = 0; page < PAGES; page++) {
  268.                       fg_setpage(page);
  269.                       color = page + 1;
  270.                       fg_setcolor(color);
  271.                       fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  272.                       fg_setcolor(0);
  273.                       fg_locate(12,17);
  274.                       sprintf(string,"page %d",page);
  275.                       fg_text(string,6);
  276.                       }
  277.  
  278.                    for (page = 0; page < PAGES; page++) {
  279.                       fg_setvpage(page);
  280.                       fg_waitkey();
  281.                       }
  282.  
  283.                    fg_setmode(old_mode);
  284.                    fg_reset();
  285.                 }
  286.  
  287.  
  288.      Virtual video pages are created with Fastgraph's fg_allocate routine. The
  289. fg_allocate routine reserves conventional random-access memory (RAM) which
  290. Fastgraph then treats as a video page. The amount of memory required depends
  291. on the current video mode. The fg_allocate routine takes a single integer
  292. argument that specifies the page number by which the virtual page will be
  293. referenced. This value must be between 1 and 63.
  294.  
  295.      If you try to create a virtual page with a page number already assigned
  296. to a physical page, fg_allocate does nothing. For example, in the Hercules
  297. graphics modes (modes 11 and 12) there are two physical pages numbered 0 and
  298. 1. Virtual pages in the Hercules graphics modes must thus have page numbers    
  299.                              Chapter 8:  Video Pages and Virtual Buffers   153
  300.  
  301. between 2 and 63. If you tell fg_allocate to create a Hercules virtual page
  302. numbered 0 or 1, it does nothing because those video pages exist as physical
  303. pages. Similarly, if you use fg_allocate in a video mode that does not support
  304. virtual video pages, it simply returns without doing anything.
  305.  
  306.      A possible problem with fg_allocate can occur when there is not enough
  307. memory available for creating a virtual page in the current video mode. The
  308. fg_allocate routine returns as its function value a status code indicating
  309. whether or not it was successful. The possible values of the status code are:
  310.  
  311.         value  meaning
  312.  
  313.           0    virtual page created
  314.           1    specified page number is a physical page
  315.           7    virtual page created, but memory control blocks were destroyed
  316.           8    insufficient memory to create the virtual page
  317.  
  318. If you use fg_testmode or fg_bestmode to check if the required number of video
  319. pages are available when using the requested video mode, you should not need
  320. to monitor the status code returned by fg_allocate.
  321.  
  322.      The fg_freepage routine releases the memory for a virtual page created
  323. with fg_allocate. It requires a single integer argument that identifies the
  324. virtual page number to release. This value must be between 0 and 63. If you
  325. try to release a physical video page, or release a virtual page that was never
  326. created, fg_freepage does nothing. It is a good idea to use fg_freepage to
  327. release all virtual video pages before a program returns control to DOS, or
  328. just before a program selects a new video mode.
  329.  
  330.      Example 8-3 is also similar to example 8-1, but it uses the monochrome
  331. text mode (mode 7). Because the monochrome text mode only has one physical
  332. video page, we must use virtual video pages for page numbers 1, 2, and 3. Note
  333. how fg_allocate and fg_freepage are used to create and release the virtual
  334. video pages in this example.
  335.  
  336.                                  Example 8-3.
  337.  
  338.              #include <fastgraf.h>
  339.              #include <stdio.h>
  340.              #include <stdlib.h>
  341.              void main(void);
  342.  
  343.              #define PAGES 4
  344.  
  345.              void main()
  346.              {
  347.                 int old_mode;
  348.                 int page;
  349.                 char string[8];
  350.  
  351.                 fg_initpm();
  352.                 if (fg_testmode(7,PAGES) == 0) {
  353.                    printf("This program requires monochrome.\n");
  354.                    exit(1);
  355.                    }                                                           
  356. 154   Fastgraph User's Guide
  357.  
  358.                 old_mode = fg_getmode();
  359.                 fg_setmode(7);
  360.                 fg_cursor(0);
  361.  
  362.                 for (page = 0; page < PAGES; page++) {
  363.                    fg_allocate(page);
  364.                    fg_setpage(page);
  365.                    fg_setcolor(7);
  366.                    fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  367.                    fg_setattr(0,7,0);
  368.                    fg_locate(12,37);
  369.                    sprintf(string,"page %d",page);
  370.                    fg_text(string,6);
  371.                    }
  372.  
  373.                 for (page = 0; page < PAGES; page++) {
  374.                    fg_setvpage(page);
  375.                    fg_waitkey();
  376.                    fg_freepage(page);
  377.                    }
  378.  
  379.                 fg_setmode(old_mode);
  380.                 fg_reset();
  381.              }
  382.  
  383.  
  384.      Example 8-4 is similar to example 8-3, but it uses the standard Hercules
  385. graphics mode (mode 11) instead of the monochrome text mode. Because the
  386. Hercules graphics modes have two physical video pages, we must use virtual
  387. video pages for page numbers 2 and 3. Note the only real difference between
  388. this program and the text mode version is the use of fg_setcolor instead of
  389. fg_setattr to make the text appear in black.
  390.  
  391.                                  Example 8-4.
  392.  
  393.                #include <fastgraf.h>
  394.                #include <stdio.h>
  395.                #include <stdlib.h>
  396.                void main(void);
  397.  
  398.                #define PAGES 4
  399.  
  400.                void main()
  401.                {
  402.                   int old_mode;
  403.                   int page;
  404.                   char string[8];
  405.  
  406.                   fg_initpm();
  407.                   if (fg_testmode(11,PAGES) == 0) {
  408.                      printf("This program requires Hercules ");
  409.                      printf("monochrome graphics.\n");
  410.                      exit(1);
  411.                      }
  412.  
  413.                   old_mode = fg_getmode();                                     
  414.                              Chapter 8:  Video Pages and Virtual Buffers   155
  415.  
  416.                   fg_setmode(11);
  417.  
  418.                   for (page = 0; page < PAGES; page++) {
  419.                      fg_allocate(page);
  420.                      fg_setpage(page);
  421.                      fg_setcolor(7);
  422.                      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  423.                      fg_setcolor(0);
  424.                      fg_locate(12,37);
  425.                      sprintf(string,"page %d",page);
  426.                      fg_text(string,6);
  427.                      }
  428.  
  429.                   for (page = 0; page < PAGES; page++) {
  430.                      fg_setvpage(page);
  431.                      fg_waitkey();
  432.                      fg_freepage(page);
  433.                      }
  434.  
  435.                   fg_setmode(old_mode);
  436.                   fg_reset();
  437.                }
  438.  
  439.  
  440.      Example 8-5 is a generalized version of examples 8-1 and 8-3 that runs in
  441. any 80-column text video mode. To simplify the program, each video page is
  442. filled with rectangles of the same color. Note that fg_allocate and
  443. fg_freepage are used to manage the virtual video pages in case fg_bestmode
  444. selects the monochrome text mode (mode 7). If fg_bestmode selects one of the
  445. 80-column color text modes (which have four physical video pages), fg_allocate
  446. and fg_freepage will simply return without doing anything.
  447.  
  448.                                  Example 8-5.
  449.  
  450.                  #include <fastgraf.h>
  451.                  #include <stdio.h>
  452.                  #include <stdlib.h>
  453.                  void main(void);
  454.  
  455.                  #define PAGES 4
  456.  
  457.                  void main()
  458.                  {
  459.                     int old_mode, new_mode;
  460.                     int page;
  461.                     char string[8];
  462.  
  463.                     fg_initpm();
  464.                     new_mode = fg_bestmode(80,25,PAGES);
  465.                     if (new_mode < 0) {
  466.                        printf("This program requires ");
  467.                        printf("an 80-column display.\n");
  468.                        exit(1);
  469.                        }
  470.  
  471.                     old_mode = fg_getmode();                                   
  472. 156   Fastgraph User's Guide
  473.  
  474.                     fg_setmode(new_mode);
  475.                     fg_cursor(0);
  476.  
  477.                     for (page = 0; page < PAGES; page++) {
  478.                        fg_allocate(page);
  479.                        fg_setpage(page);
  480.                        fg_setcolor(7);
  481.                        fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  482.                        fg_setattr(0,7,0);
  483.                        fg_locate(12,37);
  484.                        sprintf(string,"page %d",page);
  485.                        fg_text(string,6);
  486.                        }
  487.  
  488.                     for (page = 0; page < PAGES; page++) {
  489.                        fg_setvpage(page);
  490.                        fg_waitkey();
  491.                        fg_freepage(page);
  492.                        }
  493.  
  494.                     fg_setmode(old_mode);
  495.                     fg_reset();
  496.                  }
  497.  
  498.  
  499.      Example 8-6 is a generalized version of examples 8-2 and 8-4 that runs in
  500. any 320x200 graphics video mode. To simplify the program, each video page is
  501. filled with rectangles of the same color. As in example 8-5, fg_allocate and
  502. fg_freepage are used to manage the virtual video pages in case fg_bestmode
  503. selects a video mode with fewer than four physical video pages. Note the only
  504. real difference between this program and the text mode version is the use of
  505. fg_setcolor instead of fg_setattr to make the text appear in black.
  506.  
  507.                                  Example 8-6.
  508.  
  509.                  #include <fastgraf.h>
  510.                  #include <stdio.h>
  511.                  #include <stdlib.h>
  512.                  void main(void);
  513.  
  514.                  #define PAGES 4
  515.  
  516.                  void main()
  517.                  {
  518.                     int old_mode, new_mode;
  519.                     int page;
  520.                     char string[8];
  521.  
  522.                     fg_initpm();
  523.                     new_mode = fg_bestmode(320,200,PAGES);
  524.                     if (new_mode < 0) {
  525.                        printf("This program requires a ");
  526.                        printf("320 x 200 graphics mode.\n");
  527.                        exit(1);
  528.                        }                                                       
  529.                              Chapter 8:  Video Pages and Virtual Buffers   157
  530.  
  531.                     old_mode = fg_getmode();
  532.                     fg_setmode(new_mode);
  533.  
  534.                     for (page = 0; page < PAGES; page++) {
  535.                        fg_allocate(page);
  536.                        fg_setpage(page);
  537.                        fg_setcolor(15);
  538.                        fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  539.                        fg_setcolor(0);
  540.                        fg_locate(12,17);
  541.                        sprintf(string,"page %d",page);
  542.                        fg_text(string,6);
  543.                        }
  544.  
  545.                     for (page = 0; page < PAGES; page++) {
  546.                        fg_setvpage(page);
  547.                        fg_waitkey();
  548.                        fg_freepage(page);
  549.                        }
  550.  
  551.                     fg_setmode(old_mode);
  552.                     fg_reset();
  553.                  }
  554.  
  555.  
  556.  
  557. Text Cursors
  558.  
  559.      As mentioned in the previous chapter, Fastgraph draws hardware characters
  560. at the position defined by the text cursor. Like the graphics cursor, the text
  561. cursor is not a cursor in the true sense, but is simply a pair of character
  562. space (row,column) coordinates with a special meaning. The first 8 video pages
  563. (that is, pages 0 through 7) each have their own text cursor. Each subsequent
  564. group of 8 video pages (pages 8 through 15, pages 16 to 23, and so forth)
  565. respectively share the same text cursor positions as the first 8 pages. This
  566. means fg_locate will update one of 8 different text cursors depending on the
  567. active video page. Similarly, fg_where returns the text cursor position for
  568. the active page. The fg_setmode routine sets all 8 text cursor positions to
  569. the character space coordinates (0,0).
  570.  
  571.      Example 8-7 demonstrates the use of different text cursors in an 80-
  572. column color text mode (mode 3). The program first displays the text "Page "
  573. on video page 0 (the visible page) and waits for a keystroke. It then makes
  574. page 1 the active video page, changes the text cursor location for that page,
  575. and displays the text "Page 1" on video page 1. Next, it appends the character
  576. "0" to the text originally displayed on page 0. Note that we don't need to
  577. restore the text cursor position for page 0 because it is unaffected by
  578. changing the text cursor for page 1. After waiting for another keystroke, the
  579. program makes video page 1 the visual page and then waits for yet another
  580. keystroke before returning to DOS.
  581.  
  582.                                  Example 8-7.
  583.  
  584.                           #include <fastgraf.h>
  585.                           void main(void);                                     
  586. 158   Fastgraph User's Guide
  587.  
  588.                           void main()
  589.                           {
  590.                              int old_mode;
  591.  
  592.                              fg_initpm();
  593.                              old_mode = fg_getmode();
  594.                              fg_setmode(3);
  595.                              fg_cursor(0);
  596.                              fg_setattr(10,0,0);
  597.  
  598.                              fg_locate(1,0);
  599.                              fg_text("Page ",5);
  600.                              fg_waitkey();
  601.  
  602.                              fg_setpage(1);
  603.                              fg_locate(23,0);
  604.                              fg_text("Page 1",6);
  605.  
  606.                              fg_setpage(0);
  607.                              fg_text("0",1);
  608.                              fg_waitkey();
  609.  
  610.                              fg_setvpage(1);
  611.                              fg_waitkey();
  612.  
  613.                              fg_setmode(old_mode);
  614.                              fg_reset();
  615.                           }
  616.  
  617.  
  618.  
  619. Obtaining Video Page Information
  620.  
  621.      Fastgraph includes two routines, fg_getpage and fg_getvpage, that
  622. respectively return the active or visual video page number. Each routine
  623. returns the video page number as its function value, and neither routine
  624. requires any arguments.
  625.  
  626.      When creating virtual or logical pages, you must choose a page number
  627. that does not reference a physical page or a previously created virtual or
  628. logical page. While it's of course possible to keep track of which page
  629. numbers will be available in a given video mode, Fastgraph's fg_findpage
  630. function can make the job easier. It returns an unused page number, which you
  631. can then pass to any of Fastgraph's virtual or logical page allocation
  632. routines. If there are no more available (that is, all 64 entries in the
  633. internal page tables are in use), fg_findpage returns zero.
  634.  
  635.      The fg_getaddr routine is sometimes useful when using virtual pages. It
  636. returns as its function value the segment address (in real mode) or segment
  637. selector (in protected mode) for the start of the active video page. It does
  638. not require any arguments. Although fg_getaddr is more useful when using
  639. virtual video pages, it works equally well with physical video pages.
  640.  
  641.      Example 8-9 illustrates the use of fg_getpage, fg_getvpage, fg_findpage,
  642. and fg_getaddr in the standard VGA/MCGA 256-color graphics mode (mode 19).
  643. This video mode offers only one physical page, so the program uses fg_findpage 
  644.                              Chapter 8:  Video Pages and Virtual Buffers   159
  645.  
  646. to find an unused page number (which will be page 1 in mode 19), and then
  647. calls fg_allocate to create a virtual video page. After creating the virtual
  648. page, the program makes it the active video page; page 0 remains the visual
  649. video page. The fg_getpage routine then returns the active page number,
  650. followed by a call to fg_getvpage to return the visual page number (0). Next,
  651. the program uses fg_getaddr to return the segment address/selector for the two
  652. video pages. Finally, it restores the original video mode and screen
  653. attributes, displays the returned values, and returns to DOS.
  654.  
  655.                                  Example 8-9.
  656.  
  657.                #include <fastgraf.h>
  658.                #include <stdio.h>
  659.                void main(void);
  660.  
  661.                void main()
  662.                {
  663.                   int old_mode;
  664.                   int active, visual;
  665.                   int page, page0, page1;
  666.  
  667.                   fg_initpm();
  668.                   old_mode = fg_getmode();
  669.                   fg_setmode(19);
  670.                   page = fg_findpage();
  671.                   fg_allocate(page);
  672.                   fg_setpage(page);
  673.  
  674.                   active = fg_getpage();
  675.                   visual = fg_getvpage();
  676.  
  677.                   fg_setpage(0);
  678.                   page0 = fg_getaddr();
  679.                   fg_setpage(page);
  680.                   page1 = fg_getaddr();
  681.  
  682.                   fg_freepage(page);
  683.                   fg_setmode(old_mode);
  684.                   fg_reset();
  685.  
  686.                   printf("Active page is %d.\n",active);
  687.                   printf("Visual page is %d.\n",visual);
  688.                   printf("Page 0 address is %4X\n",page0);
  689.                   printf("Page %d address is %4X\n",page,page1);
  690.                }
  691.  
  692.  
  693.  
  694. Considerations for Virtual Pages
  695.  
  696.      If you're using Power C, any supported BASIC compiler, Borland Pascal, or
  697. Turbo Pascal and need to create virtual pages, you must reduce the size of the
  698. far heap. Normally, these compilers allocate all remaining memory for the
  699. heap, which means fg_allocate will not be able to allocate memory for the
  700. virtual page.                                                                  
  701. 160   Fastgraph User's Guide
  702.  
  703.      In BASIC programs, the SETMEM function reduces the size of the far heap.
  704. The BASIC versions of the Fastgraph example programs include the statement
  705.  
  706.                           SetMemStatus& = SETMEM(-n)
  707.  
  708. before calling FGallocate. This reduces the size of the far heap by n bytes.
  709. For a given video mode, the actual reduction needed is the number of virtual
  710. pages multiplied by the page size in that mode. Page sizes are listed at the
  711. beginning of this chapter, or you can use fg_pagesize to determine the page
  712. size for the current video mode.
  713.  
  714.      In Borland Pascal and Turbo Pascal, the $M compiler directive defines the
  715. maximum heap size in bytes. The Pascal versions of the Fastgraph example
  716. programs include the statement
  717.  
  718.                               {$M 16384,0,16384}
  719.  
  720. at the beginning of the examples that call fg_allocate. The third value in
  721. this list defines the maximum heap size at 16K bytes. This is suitable for
  722. most applications, but if your program uses the New or GetMem procedures to
  723. create dynamic variables that require more heap space, you'll need to increase
  724. the size beyond 16K.
  725.  
  726.      The far heap size for Power C programs is defined at link time. You must
  727. override the default heap size by including the option [,,16K] on the PCL
  728. command when you link a Power C program that uses fg_allocate. The value 16K
  729. is suitable for most applications, but if your program calls the farcalloc or
  730. farmalloc functions (or the calloc or malloc functions when using the large
  731. memory model), you may need to increase the far heap size beyond 16K.
  732.  
  733.      When you are using virtual pages, you should avoid using the fg_setvpage
  734. routine in sections of the program that require fast screen updates or
  735. animation sequences. This is because the PC and PS/2 video BIOS are only
  736. capable of displaying physical pages. To compensate for this restriction,
  737. Fastgraph exchanges the contents of a physical page with the requested virtual
  738. page. In other words, if page 1 is a virtual page and you make it the visual
  739. page, Fastgraph will exchange the contents of page 1 with whatever page was
  740. previously the visual page. This does not mean Fastgraph's page numbers change
  741. because Fastgraph also maintains an internal table containing video page
  742. addresses and exchanges the two corresponding table entries. As before, you
  743. would make page 1 the active video page if you wanted to write something to
  744. the visual page.
  745.  
  746.      About the only other potential problem when using virtual pages is what
  747. happens when you try to write to a non-existent video page (for example, if
  748. you write to virtual video page 1 before creating it with fg_allocate). In
  749. this case, Fastgraph simply redirects the video output to the visual page.
  750.  
  751.  
  752. Considerations for SuperVGA Pages
  753.  
  754.      If an program running in an SVGA graphics mode returns to text mode when
  755. the visual page is not page 0, some SVGA chipsets have problems the next time
  756. you try to run an SVGA application. We therefore recommend calling
  757. fg_setvpage(0) just before restoring the original video mode if an application
  758. performs page flipping in SVGA graphics modes. For example:                    
  759.                              Chapter 8:  Video Pages and Virtual Buffers   161
  760.  
  761.  
  762.           old_mode = fg_getmode();
  763.           fg_svgainit(0);
  764.           fg_setmode(25);
  765.                   .
  766.                   .
  767.                   .
  768.           fg_setvpage(1);
  769.                   .
  770.                   .
  771.                   .
  772.           fg_setvpage(0);         /* add this line to be safe */
  773.           fg_setmode(old_mode);
  774.  
  775.      A few SVGA chipsets cannot set the display start address beyond the 16-
  776. bit capability provided by the CRT Controller, rendering fg_setvpage
  777. meaningless.  Please refer to the READ.ME file for details.
  778.  
  779.  
  780. Logical Pages
  781.  
  782.      In addition to physical and virtual video pages, Fastgraph offers another
  783. class of video pages, called logical pages. You can create logical pages in
  784. any video mode. They can exist in conventional memory, expanded memory (EMS),
  785. or extended memory (XMS). However, they are not as versatile as physical or
  786. virtual pages because the only operations you can perform with logical pages
  787. are:
  788.  
  789.      * Copy an entire physical or virtual page to a logical page
  790.      * Copy an entire logical page to a physical or virtual page
  791.      * Copy an entire logical page to another logical page
  792.  
  793. Three Fastgraph routines -- fg_alloccms, fg_allocems, and fg_allocxms --
  794. create logical pages in conventional memory, expanded memory, and extended
  795. memory, respectively. All three routines have a single integer argument that
  796. specifies the page number by which the logical page will be referenced. The
  797. page number must be between 1 and 63 and must not reference a physical or
  798. virtual page. Their return value is 0 if the logical page is created, and
  799. negative otherwise (refer to the descriptions of these routines in the
  800. Fastgraph Reference Manual for a complete list of return values). As with
  801. virtual pages, use fg_freepage to release a logical page.
  802.  
  803.      Before you can create logical pages in expanded or extended memory, you
  804. must initialize these resources for use with Fastgraph. The fg_initems routine
  805. initializes expanded memory. To use expanded memory, you must have an Expanded
  806. Memory Manager (EMM) that conforms to the Lotus/Intel/Microsoft Expanded
  807. Memory Specification (LIM-EMS) version 3.2 or later. On 80386 and 80486
  808. systems, the EMM386.EXE device driver supplied with DOS 5.0 can be used to
  809. treat some or all of extended memory as expanded memory. The fg_initxms
  810. routine initializes extended memory for use with Fastgraph. To use extended
  811. memory, you must have an XMS driver that conforms to the
  812. Lotus/Intel/Microsoft/AST eXtended Memory Specification version 2.0 or later,
  813. such as HIMEM.SYS. XMS drivers require an 80286, 80386, or 80486 system. The
  814. fg_initems and fg_initxms routines have no arguments and must be called after
  815. fg_setmode. Their return value is 0 if successful, and -1 if the required
  816. driver and resources are not present.                                          
  817. 162   Fastgraph User's Guide
  818.  
  819.  
  820.      In protected mode, the distinction between conventional, expanded, and
  821. extended memory disappears because DOS extenders essentially treat all system
  822. memory as conventional memory. For this reason, fg_initems and fg_initxms are
  823. not meaningful and thus always return -1 in the protected mode Fastgraph
  824. libraries. This effectively disables the fg_allocems and fg_allocxms routines,
  825. so you must create logical pages with fg_alloccms in protected mode.
  826.  
  827.      Example 8-10 illustrates the use of logical pages in a 320x200 color
  828. graphics mode. The program first tries to create a logical page in extended
  829. memory by calling fg_initxms and fg_allocxms. If the initialization or page
  830. creation fails, it then tries to create the page in expanded memory with
  831. fg_initems and fg_allocems. Should that fail, the program calls fg_alloccms to
  832. try to create the page in conventional memory. If it can't create the logical
  833. page at all, the program displays an error message and exits.
  834.  
  835.      Once the logical page is created, example 8-10 displays the word "test"
  836. in the middle of the visual page (page 0) and then uses fg_copypage to
  837. transfer the visual page contents to the logical page. Because this program
  838. runs in one of several different graphics modes, we use fg_findpage to choose
  839. the logical page number. After waiting for a keystroke, the program erases the
  840. visual page, waits for another keystroke, and copies the logical page contents
  841. back to the visual page. It then releases the logical page and exits.
  842.  
  843.                                  Example 8-10.
  844.  
  845.               #include <fastgraf.h>
  846.               #include <stdio.h>
  847.               #include <stdlib.h>
  848.               void main(void);
  849.  
  850.               void main()
  851.               {
  852.                  int new_mode, old_mode;
  853.                  int page, status;
  854.  
  855.                  fg_initpm();
  856.                  new_mode = fg_bestmode(320,200,1);
  857.                  if (new_mode < 0 || new_mode == 12) {
  858.                     printf("This program requires a 320 ");
  859.                     printf("x 200 color graphics mode.\n");
  860.                     exit(1);
  861.                     }
  862.                  old_mode = fg_getmode();
  863.                  fg_setmode(new_mode);
  864.  
  865.                  page = fg_findpage();
  866.                  status = fg_initxms();
  867.                  if (status == 0) status = fg_allocxms(page);
  868.                  if (status < 0) {
  869.                     status = fg_initems();
  870.                     if (status == 0) status = fg_allocems(page);
  871.                     }
  872.                  if (status < 0) status = fg_alloccms(page);
  873.  
  874.                  if (status < 0) {                                             
  875.                              Chapter 8:  Video Pages and Virtual Buffers   163
  876.  
  877.                     fg_setmode(old_mode);
  878.                     fg_reset();
  879.                     printf("Unable to create logical page.\n");
  880.                     exit(1);
  881.                     }
  882.  
  883.                  fg_setcolor(7);
  884.                  fg_rect(0,319,0,199);
  885.                  fg_setcolor(9);
  886.                  fg_locate(12,18);
  887.                  fg_text("test",4);
  888.                  fg_waitkey();
  889.  
  890.                  fg_copypage(0,page);
  891.                  fg_erase();
  892.                  fg_waitkey();
  893.  
  894.                  fg_copypage(page,0);
  895.                  fg_waitkey();
  896.  
  897.                  fg_freepage(page);
  898.                  fg_setmode(old_mode);
  899.                  fg_reset();
  900.               }
  901.  
  902.  
  903.      As mentioned before, the only functions you can perform with logical
  904. pages are copying physical/virtual pages to logical pages, logical pages to
  905. physical/virtual pages, or copying one logical page to another. The
  906. fg_copypage routine provides the only way to do this for logical pages. See
  907. Chapter 11 for more information about fg_copypage.
  908.  
  909.  
  910. Extended Video Pages
  911.  
  912.      One of the more frequent technical support questions we receive is "I
  913. have one megabyte of memory on my video card, why can I only use the first
  914. 256K?". The answer is simple: the standard EGA and VGA graphics modes have no
  915. way to address video memory beyond 256K. Accessing more memory requires SVGA
  916. bank switching techniques. This is analogous to the fact that you might have
  917. four megabytes of RAM on your system, but without an EMS/XMS memory manager, a
  918. DOS extender, or the like, all that memory won't do much good.
  919.  
  920.      Unfortunately, not all SVGA chipsets allow bank switching in non-SVGA
  921. video modes. For those that do, however, Fastgraph includes a feature called
  922. extended video pages. Extended pages provide access to all video memory in
  923. modes 13 to 18 and modes 20 to 23 instead of restricting access to the first
  924. 256K. This means, for example, that a 1MB SVGA card will allow 32 physical
  925. pages in mode 13 rather than the usual 8 pages. Extended pages are available
  926. with the following SVGA chipsets:
  927.  
  928.      * Ahead B
  929.      * ATI 28800/38800/68800/88800
  930.      * Avance Logic 2000 series
  931.      * NCR 77C22/77C32
  932.      * Oak OTI-067                                                             
  933. 164   Fastgraph User's Guide
  934.  
  935.      * Oak OTI-077
  936.      * Oak OTI-087
  937.      * Paradise WD90C11/WD90C30/WD90C31/WD90C33
  938.      * Tseng ET4000
  939.  
  940.      Although extended pages are used in non-SVGA graphics modes, the method
  941. of accessing video memory above 256K is specific to each SVGA chipset. Thus,
  942. you must initialize Fastgraph's SVGA kernel (with fg_svgainit) before you can
  943. use extended pages. We haven't yet found a VESA implementation that supports
  944. extended pages, so you'll need to initialize the SVGA kernel for chipset-
  945. specific support.
  946.  
  947.      When writing applications that use extended video pages, you should make
  948. sure the user's SVGA chipset supports extended pages and that there is enough
  949. video memory for the number of pages required. First, make sure fg_svgainit
  950. successfully initializes the SVGA kernel. If so, check bit 2 of the
  951. fg_svgastat return value to see if the chipset supports extended pages.
  952. Finally, use fg_memory to insure that enough video memory is available for the
  953. number of video pages needed.
  954.  
  955.      The following table shows the number of video pages available in the
  956. graphics modes that support extended pages.
  957.  
  958.                                    Number of Pages With
  959.                               Mode    256K 512K  1MB
  960.  
  961.                                13      8    16    32
  962.                                14      4     8    16
  963.                                15      2     4    8
  964.                                16      2     4    8
  965.                                17      2     4    8
  966.                                18      2     4    8
  967.                                20      4     8    16
  968.                                21      2     4    8
  969.                                22      4     8    16
  970.                                23      2     4    8
  971.  
  972. Note that when extended pages are not enabled, the video mode has the number
  973. of physical video pages listed in the 256K column.
  974.  
  975.      Some video modes do not provide the listed number of full video pages.
  976. For example, modes 17 and 18 normally have two video pages -- one full 640x480
  977. page (page 0) and one partial 640x320 page (page 1). For extended pages,
  978. Fastgraph uses a page numbering scheme that maintains consistency with its
  979. standard page numbering. That is, when extended pages are available and mode
  980. 17 or 18 is used on a 1MB video card, the page numbers will range from 0 to 7,
  981. with the even-numbered pages being full pages and the odd-numbered pages being
  982. partial 640x320 pages. Similarly, in mode 22 pages 3, 7, 11, and 15 are
  983. partial (320x80); in mode 23 odd-numbered pages are partial (320x320).
  984.  
  985.      When you use Fastgraph's block transfer routines (fg_copypage,
  986. fg_restore, fg_save, fg_tcxfer, and fg_transfer) with extended pages, you must
  987. pass the source and destination page numbers to fg_defpages. This is needed
  988. because the two pages may reside in different SVGA banks, and bank switching
  989. is not performed in Fastgraph's non-SVGA code. The additional overhead of
  990. having the block transfer routines determine the bank numbers would impact the 
  991.                              Chapter 8:  Video Pages and Virtual Buffers   165
  992.  
  993. block transfer routines when extended pages are not being used. The
  994. fg_defpages routine determines the SVGA bank numbers in which the source and
  995. destination pages reside and then enables the corresponding banks for reading
  996. and writing. These banks remain in effect until you define new ones with
  997. fg_defpages or fg_setpage, so you may not need to call fg_defpages before
  998. every call to a block transfer routine. The fg_defpages routine has no effect
  999. unless extended pages are enabled. The following table shows the bank numbers
  1000. for each video page in each graphics mode that supports extended pages.
  1001.  
  1002.                                 Bank 0 Bank 1 Bank 2 Bank 3
  1003.                            Mode Pages  Pages  Pages  Pages
  1004.  
  1005.                             13   0-7    8-15  16-23  24-31
  1006.                             14   0-3    4-7    8-11  12-15
  1007.                             15   0-1    2-3    4-5    6-7
  1008.                             16   0-1    2-3    4-5    6-7
  1009.                             17   0-1    2-3    4-5    6-7
  1010.                             18   0-1    2-3    4-5    6-7
  1011.                             20   0-3    4-7    8-11  12-15
  1012.                             21   0-1    2-3    4-5    6-7
  1013.                             22   0-3    4-7    8-11  12-15
  1014.                             23   0-1    2-3    4-5    6-7
  1015.  
  1016.      Next we'll present a short code sequence that calls fg_defpages only when
  1017. needed in mode 13, where each group of 8 pages resides in its own SVGA bank.
  1018. Calling fg_setmode enables bank 0 for reading and writing, so we don't need to
  1019. call fg_defpages until we reference a page in one of the other banks (that is,
  1020. a page numbered 8 or above).
  1021.  
  1022.      fg_svgainit(0);
  1023.      fg_setmode(13);     /* enables bank 0 for reading and writing */
  1024.      fg_copypage(0,1);
  1025.      fg_copypage(0,2);
  1026.      fg_defpages(0,1);   /* page 10 is in bank 1 */
  1027.      fg_copypage(2,10);
  1028.      fg_defpages(1,1);   /* page 15 is in bank 1 */
  1029.      fg_copypage(10,15);
  1030.      fg_setpage(0);      /* enables bank 0 for reading and writing */
  1031.      fg_erase();
  1032.      fg_copypage(0,3);
  1033.      fg_defpages(1,0);   /* page 15 is in bank 1 */
  1034.      fg_copypage(15,4);
  1035.  
  1036.      Most mouse drivers know nothing about SVGA bank switching and non-
  1037. standard video modes (that's why Fastgraph must hook its own mouse cursor
  1038. control handlers into the mouse driver in XVGA and SVGA modes). As Fastgraph
  1039. relies on the mouse driver for cursor control in modes 13 to 18, it's only
  1040. possible to display the mouse cursor on video pages in the first SVGA bank
  1041. (bank 0) in these modes. Note that this does not apply to modes 20 to 23,
  1042. where Fastgraph controls the mouse cursor through its own handler.
  1043.  
  1044.      Some SVGA chipsets do not reset the read and write bank numbers back to
  1045. zero when establishing a non-SVGA video mode. When a mode set operation clears
  1046. video memory, such chipsets will clear the first video page in the last write
  1047. bank selected. While fg_setmode does set the read and write banks to zero when
  1048. extended pages are available, it cannot do this before setting the video mode, 
  1049. 166   Fastgraph User's Guide
  1050.  
  1051. which is what normally would clear the screen. This may result in artifacts on
  1052. page 0 after calling fg_setmode. The easiest way around this problem is to
  1053. call fg_defpages(0,0) before restoring the original video mode in programs
  1054. that use extended pages. Even this, however, does not clear video memory after
  1055. a mode set when using extended pages with some SVGA chipsets. We therefore
  1056. recommend calling fg_erase immediately after restoring the original video mode
  1057. when using extended pages.
  1058.  
  1059.  
  1060. Video Page Resizing
  1061.  
  1062.      Resizing is the process of changing the dimensions of a video page. It is
  1063. available only in the native EGA graphics modes (modes 13 to 16), native VGA
  1064. graphics modes (17 and 18), extended VGA modes (20 to 23), and SVGA modes (24
  1065. to 29). Resizing does not change the screen resolution, but instead increases
  1066. the video page size so only part of the page is visible. For now, we'll just
  1067. introduce resizing with a simple example, but in Chapter 13 we'll see its real
  1068. power when we perform smooth panning.
  1069.  
  1070.      The Fastgraph routine fg_resize changes the dimensions of a video page.
  1071. Its two integer arguments define the page width and page height, both in
  1072. pixels. Example 8-11 runs in the 320x200 EGA graphics mode (mode 13). After
  1073. establishing the video mode, it displays the word "resize" starting in column
  1074. 38 of row 0. Because the characters extend beyond the last column of the row,
  1075. they wrap to the next row. The program continues displaying this until you
  1076. press a key. Then, it clears the screen and calls fg_resize to make the page
  1077. size 640x200 pixels. Again the program displays the word "resize" starting in
  1078. column 38 of row 0, but this time it does not wrap to the next row. This is
  1079. because the resizing doubled the page width, which increased the number of
  1080. character cells per row from 40 to 80. The characters that formerly wrapped to
  1081. the next row now continue on an off-screen portion of the same row.
  1082.  
  1083.                                  Example 8-11.
  1084.  
  1085.                  #include <fastgraf.h>
  1086.                  #include <stdio.h>
  1087.                  #include <stdlib.h>
  1088.                  void main(void);
  1089.  
  1090.                  void main()
  1091.                  {
  1092.                     int old_mode;
  1093.  
  1094.                     fg_initpm();
  1095.                     if (fg_testmode(13,1) == 0) {
  1096.                        printf("This program requires a 320 ");
  1097.                        printf("x 200 EGA graphics mode.\n");
  1098.                        exit(1);
  1099.                        }
  1100.  
  1101.                     old_mode = fg_getmode();
  1102.                     fg_setmode(13);
  1103.  
  1104.                     fg_setcolor(9);
  1105.                     fg_locate(0,38);
  1106.                     fg_text("resize",6);                                       
  1107.                              Chapter 8:  Video Pages and Virtual Buffers   167
  1108.  
  1109.                     fg_waitkey();
  1110.  
  1111.                     fg_erase();
  1112.                     fg_resize(640,200);
  1113.                     fg_setcolor(10);
  1114.                     fg_locate(0,38);
  1115.                     fg_text("resize",6);
  1116.                     fg_waitkey();
  1117.  
  1118.                     fg_setmode(old_mode);
  1119.                     fg_reset();
  1120.                  }
  1121.  
  1122.  
  1123.      The size of a video page is constrained only by the amount of video
  1124. memory available and the addressability of the video mode. Increasing the
  1125. video page size reduces the number of physical pages available proportionally.
  1126. In mode 13, for example, increasing the page size from 320x200 to 640x400
  1127. reduces the number of video pages from 8 to 2. When you call fg_resize, the
  1128. visual page must be page 0. If you have created any logical video pages, you
  1129. must release them with fg_freepage before calling fg_resize, and then create
  1130. them again afterward. If you have initialized the mouse (with fg_mouseini),
  1131. joysticks (with fg_initjoy), expanded memory (with fg_initems), or extended
  1132. memory (with fg_initxms), you should re-initialize these resources after
  1133. calling fg_resize. In modes 13 to 18, most mouse drivers expect a fixed video
  1134. page width, so the mouse cursor may become distorted after resizing video
  1135. pages in these modes. When you call fg_resize, Fastgraph sets the clipping
  1136. region to the new page limits. The fg_setmode routine re-establishes the
  1137. dimensions of a video page to the default screen resolution for the selected
  1138. video mode. The fg_resize routine has no effect when a virtual buffer is
  1139. active.
  1140.  
  1141.       Depending on the dimensions passed to fg_resize, you may end up with a
  1142. partial video page. Again, suppose we're using mode 13 and have changed the
  1143. page size to 960x400 (this is six times the default page size). The original
  1144. pages 0 to 5 now make up page 0, and original pages 6 and 7 now make up page
  1145. 1. However, there is not enough video memory left on page 1 for a full 960x400
  1146. page. In this case, the number of pixel rows available on page 1 would be one-
  1147. third the full page size, or 133 rows. This is because the total storage
  1148. required by original pages 6 and 7 is one-third the total required for
  1149. original pages 0 through 5.
  1150.  
  1151.      Extended video pages may be resized in modes 13-18 and 20-23, but the
  1152. resulting pages must not cross SVGA bank boundaries. In mode 20, for instance,
  1153. you normally have four 320x200 pages in each bank. You could change the video
  1154. page size to 640x400, thereby having four larger pages, one in each bank. You
  1155. could not, however, resize video memory to two 640x800 pages, as each page
  1156. would span two banks.
  1157.  
  1158.  
  1159. Preserving Video Page Contents Across Mode Switches
  1160.  
  1161.      Sometimes a graphics program may temporarily need to switch to another
  1162. video mode. An example of this might be a graphical user interface (GUI)
  1163. menuing system that includes "shell to DOS" as one of its options. When the
  1164. user selects this option, the program must revert to a text video mode so the  
  1165. 168   Fastgraph User's Guide
  1166.  
  1167. user will see the familiar DOS prompt when the shell executes. On leaving the
  1168. DOS shell, the program returns to a graphics mode and should ideally restore
  1169. the screen to what it was originally.
  1170.  
  1171.      When you establish a video mode with fg_setmode, Fastgraph clears all
  1172. physical video pages and initializes its internal page tables as if no virtual
  1173. or logical pages have been created. While it's not possible to preserve
  1174. physical page contents across video mode switches, you can use Fastgraph's
  1175. fg_getentry and fg_setentry routines to save virtual or logical page contents.
  1176. The trick, so to speak, is using fg_getentry to save the virtual or logical
  1177. page address and type before switching video modes. Then, when you return to
  1178. the same video mode, you can use fg_setentry to restore the internal page
  1179. tables to their previous state. This effectively makes the virtual or logical
  1180. page accessible again.
  1181.  
  1182.      Example 8-12 illustrates this process. This program runs in video mode
  1183. 18, the 640x480 16-color VGA graphics mode. After establishing this video
  1184. mode, the program calls fg_alloccms to create a logical page in conventional
  1185. memory. Next, it calls fg_getentry to save the address and type of the logical
  1186. page just created. The first argument to fg_getentry specifies the page number
  1187. (determined by fg_findpage); the next two arguments receive the page address
  1188. and type. Page type codes used by fg_getentry and fg_setentry are:
  1189.  
  1190.      0 = unallocated page
  1191.      1 = physical page
  1192.      2 = virtual page
  1193.      3 = logical page in expanded memory (EMS)
  1194.      4 = logical page in extended memory (XMS)
  1195.      5 = logical page in conventional memory
  1196.  
  1197.      After this setup work, example 8-12 fills the screen with light blue
  1198. pixels, draws a white box around the edge, and then waits for a keystroke.
  1199. Before switching back to the original video mode (assumed to be mode 3), the
  1200. program uses fg_copypage to copy the visual page contents to the logical page.
  1201. This is necessary because we can only save virtual or logical page contents
  1202. across video mode changes, not physical pages. In mode 3, the program prompts
  1203. for a keystroke before returning to mode 18.
  1204.  
  1205.      Now we're ready to restore the previous contents of the visual page.
  1206. Because the example program did not release the logical page, the memory is
  1207. still allocated; Fastgraph just cannot access it. To solve this, the program
  1208. calls fg_setentry to restore Fastgraph's internal page table entries for the
  1209. original logical page number to what they were previously. Note how we use the
  1210. same page address and type values in the call to fg_setentry that were
  1211. returned earlier by fg_getentry. Now that the logical page is once again
  1212. accessible, the program can use fg_copypage to copy its contents back to the
  1213. visual page. With that explanation behind us, here is example 8-12.
  1214.  
  1215.                                  Example 8-12.
  1216.  
  1217.                   #include <fastgraf.h>
  1218.                   void main(void);
  1219.  
  1220.                   void main()
  1221.                   {
  1222.                      int old_mode;                                             
  1223.                              Chapter 8:  Video Pages and Virtual Buffers   169
  1224.  
  1225.                      int page, page_addr, page_type;
  1226.  
  1227.                      fg_initpm();
  1228.                      old_mode = fg_getmode();
  1229.                      fg_setmode(18);
  1230.                      page = fg_findpage();
  1231.                      fg_alloccms(page);
  1232.                      fg_getentry(page,&page_addr,&page_type);
  1233.  
  1234.                      fg_setcolor(9);
  1235.                      fg_fillpage();
  1236.                      fg_setcolor(15);
  1237.                      fg_box(0,639,0,479);
  1238.                      fg_waitkey();
  1239.  
  1240.                      fg_copypage(0,page);
  1241.                      fg_setmode(old_mode);
  1242.                      fg_cursor(0);
  1243.                      fg_setcolor(15);
  1244.                      fg_text("Press any key.",14);
  1245.                      fg_waitkey();
  1246.  
  1247.                      fg_setmode(18);
  1248.                      fg_setentry(page,page_addr,page_type);
  1249.                      fg_copypage(page,0);
  1250.                      fg_waitkey();
  1251.  
  1252.                      fg_freepage(page);
  1253.                      fg_setmode(old_mode);
  1254.                      fg_reset();
  1255.                   }
  1256.  
  1257.  
  1258.      To keep the example as simple as possible, it does not test for
  1259. availability of video modes, nor does it check if the logical page creation
  1260. was successful. In a real application, of course, omitting these checks is not
  1261. recommended. See example 8-17 for a version of this program that uses virtual
  1262. buffers instead of logical pages.
  1263.  
  1264.  
  1265. Controlling Page Allocation
  1266.  
  1267.      When Fastgraph creates virtual or logical pages in conventional memory
  1268. with fg_allocate or fg_alloccms, it uses the DOS allocate memory service
  1269. (function 48 hex of interrupt 21 hex). Some compilers allocate all or part of
  1270. available conventional memory to a data structure called the heap or far heap.
  1271. Memory allocation functions such as malloc handle their requests through an
  1272. associated heap manager instead of through DOS services. If the heap manager
  1273. controls all available memory, the DOS allocate memory service is essentially
  1274. disabled because there will be no memory available to satisfy allocation
  1275. requests. If the heap manager controls some but not all available memory, a
  1276. conflict may arise between the heap manager and the DOS allocate memory
  1277. service.
  1278.  
  1279.      To solve this problem, you can use the compiler's allocate far memory
  1280. function to reserve memory for the virtual or logical page and then make the   
  1281. 170   Fastgraph User's Guide
  1282.  
  1283. page known to Fastgraph with fg_setentry. The easiest way to determine the
  1284. amount of memory to allocate is through the fg_pagesize function, which
  1285. returns the page size in bytes (as a long integer) for the current video mode.
  1286. To release the page, use fg_setentry with a page type of zero to mark the page
  1287. as unallocated before actually freeing the memory. Pages created this way are
  1288. not initially cleared because the allocated memory block contents are
  1289. undefined. We recommend using fg_erase to set the page contents to the
  1290. background color.
  1291.  
  1292.      Example 8-13 shows how to create a virtual page in real mode programs
  1293. using these techniques instead of fg_allocate. It uses the farmalloc and
  1294. farfree functions from the C run-time library for Borland compilers (the
  1295. analogous Microsoft functions are _fmalloc and _ffree). Example 8-13 uses
  1296. fg_pagesize and the Borland run-time library function farmalloc to create a
  1297. virtual page in the 320x200 VGA/MCGA 256-color graphics mode. After allocating
  1298. the memory, the program calls fg_setentry, passing it the page number (1), the
  1299. segment portion of the memory block address (using the FP_SEG macro from the
  1300. run-time library), and the code for a virtual page (2). Once the virtual page
  1301. is set up, the program writes some text on the virtual page and then uses
  1302. fg_copypage to display the virtual page contents on the visual page. Finally,
  1303. it releases the page by calling fg_setentry (so Fastgraph knows the virtual
  1304. page is gone) and the farfree run-time library function (to actually free the
  1305. memory). The call to fg_setentry is not really needed in this instance because
  1306. no further references are made to page 1.
  1307.  
  1308.                                  Example 8-13.
  1309.  
  1310.             #include <fastgraf.h>
  1311.             #include <dos.h>
  1312.             #ifdef __TURBOC__
  1313.             #include <alloc.h>
  1314.             #else
  1315.             #include <malloc.h>
  1316.             #define  farfree(p)   _ffree(p)
  1317.             #define  farmalloc(n) _fmalloc(n)
  1318.             #endif
  1319.  
  1320.             void main(void);
  1321.  
  1322.             void main()
  1323.             {
  1324.                int old_mode;
  1325.                unsigned page_addr;
  1326.                char far *buffer;
  1327.  
  1328.                old_mode = fg_getmode();
  1329.                fg_setmode(19);
  1330.                buffer = farmalloc(fg_pagesize()+16);
  1331.                page_addr = FP_SEG(buffer) + (FP_OFF(buffer)+15)/16;
  1332.                fg_setentry(1,page_addr,2);
  1333.  
  1334.                fg_setpage(1);
  1335.                fg_erase();
  1336.                fg_setcolor(9);
  1337.                fg_text("This is page 1.",15);
  1338.                fg_waitkey();                                                   
  1339.                              Chapter 8:  Video Pages and Virtual Buffers   171
  1340.  
  1341.  
  1342.                fg_copypage(1,0);
  1343.                fg_setentry(1,0,0);
  1344.                fg_waitkey();
  1345.  
  1346.                farfree(buffer);
  1347.                fg_setmode(old_mode);
  1348.                fg_reset();
  1349.             }
  1350.  
  1351.  
  1352.  
  1353. Virtual Buffers
  1354.  
  1355.      Virtual buffers are blocks of conventional memory that you can treat as
  1356. video memory. They are much more general than virtual pages, as they are
  1357. supported in all graphics video modes and can be smaller or larger than the
  1358. actual page size. An application may have up to 32 virtual buffers open
  1359. simultaneously. Each virtual buffer has its own independent clipping limits,
  1360. which default to the entire virtual buffer. Any program that uses virtual
  1361. buffers must initialize the virtual buffer environment by calling fg_vbinit
  1362. once, before it calls any of Fastgraph's other virtual buffer routines. The
  1363. fg_vbinit routine has no arguments and no return value.
  1364.  
  1365.      In protected mode, and when using real mode compilers that support huge
  1366. arrays (far arrays whose size may exceed 64K), use fg_vbdefine to create
  1367. virtual buffers. The fg_vbdefine routine defines a block of previously
  1368. allocated memory as a virtual buffer. Usually this memory is allocated
  1369. dynamically with the malloc or farmalloc functions in C or C++, the
  1370. GlobalAllocPtr function in protected mode Pascal, or the ALLOCATE statement in
  1371. protected mode FORTRAN. The fg_vbdefine routine returns a handle by which the
  1372. virtual buffer is referenced in other Fastgraph routines. Two related virtual
  1373. buffer routines are fg_vbundef, which releases a virtual buffer handle, and
  1374. fg_vbhandle, which returns the active virtual buffer handle (or -1 if no
  1375. virtual buffer is active).
  1376.  
  1377.      The number of bytes required for a virtual buffer is simply its width in
  1378. pixels multiplied by its height in pixels, regardless of the current video
  1379. mode. The virtual buffer layout is equally simple. For instance, a 320x200
  1380. virtual buffer requires 64,000 bytes. The first 320 bytes represent the first
  1381. row of the virtual buffer, the next 320 bytes represent the second row, and so
  1382. forth. Within each of the 200 such rows, each of the 320 bytes represents one
  1383. pixel. This means, for example, the (0,0) pixel in the virtual buffer would be
  1384. at offset 0, the (2,0) pixel would be at offset 2, and the (2,1) pixel would
  1385. be at offset 322. In general, the offset of the (x,y) pixel is given by the
  1386. formula y*virtual_buffer_width + x.
  1387.  
  1388.      The method of dynamically allocating memory suitable for virtual buffers
  1389. is compiler and environment dependent. When using 32-bit protected mode, the
  1390. virtual buffer memory resides in the program's default data segment and is
  1391. referenced through a standard near pointer. In 16-bit environments, the
  1392. virtual buffer memory is a huge array and is referenced through a far pointer.
  1393. The following examples illustrate how to allocate memory for a 640x400 virtual
  1394. buffer for each compiler that supports dynamic allocation of huge memory
  1395. blocks.                                                                        
  1396. 172   Fastgraph User's Guide
  1397.  
  1398. For Borland C++ (16-bit), Turbo C++, Turbo C:
  1399.  
  1400.      char huge *buffer;
  1401.      buffer = (char huge *)farmalloc(640L*400L);
  1402.  
  1403. For Microsoft C/C++, QuickC, Visual C++, 16-bit WATCOM C/C++:
  1404.  
  1405.      char huge *buffer;
  1406.      buffer = (char huge *)halloc(640L*400L,1);
  1407.  
  1408. For 32-bit C/C++ compilers:
  1409.  
  1410.      char *buffer;
  1411.      buffer = (char *)malloc(640*400);
  1412.  
  1413. For Borland Pascal 7 (protected mode):
  1414.  
  1415.      var buffer : pointer;
  1416.      buffer := GlobalAllocPtr(gmem_Fixed,Longint(640)*Longint(400));
  1417.  
  1418. For Microsoft FORTRAN PowerStation:
  1419.  
  1420.      INTEGER*1 BUFFER[ALLOCATABLE](:)
  1421.      INTEGER STATUS
  1422.      ALLOCATE(BUFFER(640*400),STAT=STATUS)
  1423.  
  1424.      Real mode BASIC, Pascal, and FORTRAN compilers have limited, if any,
  1425. support for huge arrays. In these environments, use fg_vballoc to create
  1426. virtual buffers. The fg_vballoc routine uses the DOS allocate memory service
  1427. to reserve virtual buffer memory. The supported BASIC compilers and real mode
  1428. Turbo Pascal normally assign all unused conventional memory to an area called
  1429. the far heap. At best, this will cause DOS memory allocation requests to fail,
  1430. but more often it creates memory conflicts that manifest themselves later in
  1431. your application. To solve this problem, you must tell the compiler to reduce
  1432. the size of the far heap.
  1433.  
  1434.      Real mode Pascal programmers must use the $M directive to reduce the far
  1435. heap size by the total space needed for all virtual buffers. If you wanted to
  1436. use a 640x400 virtual buffer, for example, the following $M directive would
  1437. reduce the far heap size by 256,000 bytes:
  1438.  
  1439.                               {$M 16384,0,256000}
  1440.  
  1441.      BASIC programmers must use the SETMEM function to reduce the far heap
  1442. size by the total space needed for all virtual buffers, plus 16 bytes per
  1443. virtual buffer. If you wanted to use a 640x400 virtual buffer in a BASIC
  1444. program, the following SETMEM call would reduce the far heap size by 256,016
  1445. bytes:
  1446.  
  1447.                         SetMemStatus& = SETMEM(-256016)
  1448.  
  1449.      After you're finished with a virtual buffer, its memory may be released
  1450. using fg_vbfree. You should use fg_vbfree only with virtual buffers created
  1451. with fg_vballoc and not those created with fg_vbdefine, and you cannot use it
  1452. on the active virtual buffer. As fg_vballoc and fg_vbfree are needed for real
  1453. mode only, they are not present in the Fastgraph protected mode libraries. For 
  1454.                              Chapter 8:  Video Pages and Virtual Buffers   173
  1455.  
  1456. virtual buffers created with fg_vbdefine, just use your compiler's standard
  1457. method for releasing dynamic memory blocks.
  1458.  
  1459.      Once a virtual buffer is defined, you can activate it with fg_vbopen.
  1460. When a virtual buffer is active, most Fastgraph routines operate on that
  1461. virtual buffer instead of video memory. This will continue until you call
  1462. fg_vbclose, which redirects graphics operations back to the active video page.
  1463. If you later want to activate the virtual buffer again, or if you want to
  1464. switch to another virtual buffer previously created with fg_vbdefine, you can
  1465. use fg_vbopen for this purpose.
  1466.  
  1467.      Two of Fastgraph's more important virtual buffer routines are fg_vbpaste
  1468. and fg_vbcut. These routines move rectangular areas between the active virtual
  1469. buffer and the active video page. The fg_vbcut routine copies an area from the
  1470. active video page to the active virtual buffer. Similarly, fg_vbpaste copies
  1471. an area from the active virtual buffer to the active video page. An especially
  1472. useful property of fg_vbcut and fg_vbpaste is that they each remember the most
  1473. recent active virtual buffer and video page. This feature makes it possible to
  1474. move areas back and forth between a virtual buffer and video memory without
  1475. continuously opening and closing the virtual buffer.
  1476.  
  1477.      The fg_vbpaste routine performs a simple translation for pixel values
  1478. greater than the number of colors available in the current video mode. This
  1479. could happen, for example, if you used fg_vbcut in a 256-color graphics mode
  1480. and later used fg_vbpaste to display the virtual buffer contents in a 16-color
  1481. graphics mode. Should this occur, fg_vbpaste will display pixels of color c in
  1482. color c modulo n, where n is the number of colors available in the current
  1483. video mode.
  1484.  
  1485.      At this point, some example programs should help clarify the use of
  1486. virtual buffers. Our first example, 8-14, runs in the standard VGA/MCGA
  1487. 320x200 256-color graphics mode (mode 19) and creates a virtual buffer twice
  1488. as high and twice as wide as the screen size. This means we'll create a
  1489. 640x400 virtual buffer requiring 256,000 bytes of conventional memory
  1490. (conditional compilation sequences show how to allocate the virtual buffer
  1491. memory for different compilers). If the virtual buffer was created
  1492. successfully, the program calls fg_vbopen to activate the virtual buffer and
  1493. then draws four 320x200 rectangles of different colors, one in each quadrant
  1494. of the virtual buffer. It then uses fg_vbpaste to copy each rectangle to the
  1495. active video page, followed by another call to show the center 320x200 portion
  1496. of the virtual buffer (this will display equal parts of the four rectangles).
  1497.  
  1498.                                  Example 8-14.
  1499.  
  1500.        #include <fastgraf.h>
  1501.        #include <stdio.h>
  1502.        #include <stdlib.h>
  1503.        #ifdef __TURBOC__
  1504.        #include <alloc.h>
  1505.        #else
  1506.        #include <malloc.h>
  1507.        #endif
  1508.  
  1509.        #define WIDTH  640
  1510.        #define HEIGHT 400                                                      
  1511. 174   Fastgraph User's Guide
  1512.  
  1513.        void main(void);
  1514.  
  1515.        void main()
  1516.        {
  1517.           int handle;
  1518.           int old_mode;
  1519.        #ifdef FG32
  1520.           char *buffer;
  1521.        #else
  1522.           char huge *buffer;
  1523.        #endif
  1524.  
  1525.           /* initialize the video environment */
  1526.  
  1527.           fg_initpm();
  1528.           old_mode = fg_getmode();
  1529.           fg_setmode(19);
  1530.           fg_vbinit();
  1531.  
  1532.           /* set up a 640x400 virtual buffer */
  1533.  
  1534.        #ifdef FG32
  1535.           buffer = (char *)malloc(WIDTH*HEIGHT);
  1536.        #elif defined(__TURBOC__)
  1537.           buffer = (char huge *)farmalloc((long)WIDTH*(long)HEIGHT);
  1538.        #else
  1539.           buffer = (char huge *)halloc((long)WIDTH*(long)HEIGHT,1);
  1540.        #endif
  1541.           if (buffer == NULL) {
  1542.              fg_setmode(old_mode);
  1543.              fg_reset();
  1544.              printf("Could not create the virtual buffer.\n");
  1545.              exit(1);
  1546.              }
  1547.           handle = fg_vbdefine(buffer,WIDTH,HEIGHT);
  1548.           fg_vbopen(handle);
  1549.  
  1550.           /* draw a 320x200 rectangle in each virtual buffer quadrant */
  1551.  
  1552.           fg_setcolor(9);
  1553.           fg_rect(0,319,0,199);
  1554.           fg_setcolor(10);
  1555.           fg_rect(320,639,0,199);
  1556.           fg_setcolor(11);
  1557.           fg_rect(0,319,200,399);
  1558.           fg_setcolor(12);
  1559.           fg_rect(320,639,200,399);
  1560.  
  1561.           /* paste each rectangle to the 320x200 active video page */
  1562.  
  1563.           fg_vbpaste(0,319,0,199,0,199);
  1564.           fg_waitkey();
  1565.           fg_vbpaste(320,639,0,199,0,199);
  1566.           fg_waitkey();
  1567.           fg_vbpaste(0,319,200,399,0,199);
  1568.           fg_waitkey();                                                        
  1569.                              Chapter 8:  Video Pages and Virtual Buffers   175
  1570.  
  1571.           fg_vbpaste(320,639,200,399,0,199);
  1572.           fg_waitkey();
  1573.  
  1574.           /* paste the center 320x200 subset of the virtual buffer */
  1575.  
  1576.           fg_vbpaste(160,479,100,299,0,199);
  1577.           fg_waitkey();
  1578.  
  1579.           /* close the virtual buffer */
  1580.  
  1581.           fg_vbclose();
  1582.  
  1583.           /* restore original video mode and exit */
  1584.  
  1585.           fg_setmode(old_mode);
  1586.           fg_reset();
  1587.        }
  1588.  
  1589.  
  1590.      Calling fg_vbclose before the final fg_setmode call is necessary because
  1591. fg_setmode has no effect when a virtual buffer is active. If we didn't call
  1592. fg_vbclose, the program would return to DOS in mode 19 instead of the original
  1593. video mode.
  1594.  
  1595.      If you instead wanted to allocate the virtual buffer memory with
  1596. fg_vballoc in example 8-14, the steps to create the virtual buffer would
  1597. change as follows:
  1598.  
  1599.   /* set up a 640x400 virtual buffer */
  1600.  
  1601.   handle = fg_vballoc(WIDTH,HEIGHT);
  1602.   if (handle < 0) {
  1603.      fg_setmode(old_mode);
  1604.      fg_reset();
  1605.      printf("Could not create the virtual buffer.\n");
  1606.      exit(1);
  1607.      }
  1608.   fg_vbopen(handle);
  1609.  
  1610. If you create the virtual buffer with fg_vballoc, you also should use
  1611. fg_vbfree to release the virtual buffer memory when it's no longer needed:
  1612.  
  1613.   /* close the virtual buffer */
  1614.  
  1615.   fg_vbclose();
  1616.   fg_vbfree(handle);
  1617.  
  1618. Again, we recommend using fg_vballoc and fg_vbfree only with 16-bit compilers
  1619. that do not provide easy methods for creating huge arrays.
  1620.  
  1621.      Example 8-15 illustrates the use of the fg_vbcut routine, which
  1622. essentially performs the inverse operation of fg_vbpaste. That is, fg_vbcut
  1623. copies a rectangular area from the active video page to the active virtual
  1624. buffer. The program begins by drawing a 20x20 blue rectangle with a white
  1625. border in the upper left corner of the active video page. After a keystroke,
  1626. it sets up a 20x20 virtual buffer and calls fg_vbcut to copy the rectangle to  
  1627. 176   Fastgraph User's Guide
  1628.  
  1629. the virtual buffer. The program then calls fg_vbpaste in a loop to display 16
  1630. copies of the virtual buffer contents across the bottom of the screen. Note
  1631. that example 8-15 uses a virtual buffer that is just 20 pixels square, or 400
  1632. bytes total. Because it is so small, we chose to declare a 400-byte array for
  1633. the virtual buffer instead of allocating its memory dynamically as in the
  1634. previous example. Note also that because the virtual buffer array size is less
  1635. than 64K bytes, we can declare it far instead of huge in 16-bit environments
  1636. (huge arrays less than 64K are functionally equivalent to far arrays).
  1637.  
  1638.                                  Example 8-15.
  1639.  
  1640.                  #include <fastgraf.h>
  1641.  
  1642.                  #define WIDTH  20
  1643.                  #define HEIGHT 20
  1644.  
  1645.                  void main(void);
  1646.  
  1647.                  #ifdef FG32
  1648.                  char buffer[WIDTH*HEIGHT];
  1649.                  #else
  1650.                  char far buffer[WIDTH*HEIGHT];
  1651.                  #endif
  1652.  
  1653.                  void main()
  1654.                  {
  1655.                     int handle;
  1656.                     int old_mode;
  1657.                     int x;
  1658.  
  1659.                     fg_initpm();
  1660.                     old_mode = fg_getmode();
  1661.                     fg_setmode(19);
  1662.                     fg_vbinit();
  1663.  
  1664.                     fg_setcolor(15);
  1665.                     fg_rect(0,WIDTH-1,0,HEIGHT-1);
  1666.                     fg_setcolor(9);
  1667.                     fg_rect(1,WIDTH-2,1,HEIGHT-2);
  1668.                     fg_waitkey();
  1669.  
  1670.                     handle = fg_vbdefine(buffer,WIDTH,HEIGHT);
  1671.                     fg_vbopen(handle);
  1672.                     fg_vbcut(0,WIDTH-1,0,HEIGHT-1,0,HEIGHT-1);
  1673.  
  1674.                     for (x = 0; x <= 320-WIDTH; x += WIDTH)
  1675.                        fg_vbpaste(0,WIDTH-1,0,HEIGHT-1,x,199);
  1676.                     fg_waitkey();
  1677.  
  1678.                     fg_vbclose();
  1679.                     fg_setmode(old_mode);
  1680.                     fg_reset();
  1681.                  }                                                             
  1682.                              Chapter 8:  Video Pages and Virtual Buffers   177
  1683.  
  1684.      If you create a virtual buffer that is taller or wider than the page size
  1685. (or perhaps both taller and wider), it's possible to perform virtual buffer
  1686. scrolling. To achieve a scrolling effect, you generally just call fg_vbpaste
  1687. iteratively such that the source region in the virtual buffer increments
  1688. gradually, while the destination region on the active video page stays the
  1689. same. Depending on the video mode and the size of the scrolling region, you
  1690. may need to include a delay factor between fg_vbpaste calls so the area being
  1691. scrolled doesn't appear to jump immediately to its ultimate destination.
  1692.  
  1693.      Example 8-16 performs virtual buffer scrolling. This example runs in the
  1694. XVGA 320x200 256-color graphics mode (mode 20) and creates a 1000x50 virtual
  1695. buffer using the method of example 8-14. The program fills the virtual buffer
  1696. with a series of one-pixel wide rectangles, each 50 pixels high and in
  1697. alternating colors. The actual scrolling takes place in the loop containing
  1698. the two fg_vbpaste calls. We'll define a 100x50 area in the middle of the
  1699. visual page, with horizontal extremes between 110 and 209, and vertical
  1700. extremes between 75 and 124, as our scrolling region. We'll scroll the top
  1701. half (25 pixels) of the virtual buffer from right to left while scrolling the
  1702. bottom half from left to right. In other words, we'll be moving two 100x25
  1703. subsets of the virtual buffer through the scrolling region.
  1704.  
  1705.      The first fg_vbpaste call scrolls the top half of the virtual buffer. The
  1706. starting x coordinate defining the region to transfer from the virtual buffer
  1707. ranges from 0 to 900 in one-pixel increments, and the width of the transfer
  1708. region is always 100 pixels. The height of the transfer region remains
  1709. constant at 25 pixels (virtual buffer rows 0 to 24). The destination position
  1710. is the upper half of the scrolling region on the visual page; its lower left
  1711. corner is at x=110 and y=99.
  1712.  
  1713.      The second fg_vbpaste call, which scrolls the bottom half of the virtual
  1714. buffer but in the opposite direction, behaves similarly. In this case, the
  1715. starting x coordinate in the virtual buffer decreases from 900 to 0 in one-
  1716. pixel steps, and its width is always 100 pixels. The height of the transfer
  1717. region is again 25 pixels, but this time it uses rows 25 to 49 in the virtual
  1718. buffer. The destination position is the lower half of the scrolling region on
  1719. the visual page; its lower left corner is at x=110 and y=124.
  1720.  
  1721.                                  Example 8-16.
  1722.  
  1723.       #include <fastgraf.h>
  1724.       #include <stdio.h>
  1725.       #include <stdlib.h>
  1726.       #ifdef __TURBOC__
  1727.       #include <alloc.h>
  1728.       #else
  1729.       #include <malloc.h>
  1730.       #endif
  1731.  
  1732.       #define WIDTH  1000
  1733.       #define HEIGHT   50
  1734.  
  1735.       void main(void);
  1736.  
  1737.       void main()
  1738.       {
  1739.          int handle;                                                           
  1740. 178   Fastgraph User's Guide
  1741.  
  1742.          int old_mode;
  1743.          int x;
  1744.       #ifdef FG32
  1745.          char *buffer;
  1746.       #else
  1747.          char huge *buffer;
  1748.       #endif
  1749.  
  1750.          /* initialize the video environment */
  1751.  
  1752.          fg_initpm();
  1753.          old_mode = fg_getmode();
  1754.          fg_setmode(20);
  1755.          fg_vbinit();
  1756.  
  1757.          /* fill the screen with light blue pixels */
  1758.  
  1759.          fg_setcolor(9);
  1760.          fg_fillpage();
  1761.  
  1762.          /* set up the virtual buffer */
  1763.  
  1764.       #ifdef FG32
  1765.          buffer = (char *)malloc(WIDTH*HEIGHT);
  1766.       #elif defined(__TURBOC__)
  1767.          buffer = (char huge *)farmalloc((long)WIDTH*(long)HEIGHT);
  1768.       #else
  1769.          buffer = (char huge *)halloc((long)WIDTH*(long)HEIGHT,1);
  1770.       #endif
  1771.          if (buffer == NULL) {
  1772.             fg_setmode(old_mode);
  1773.             fg_reset();
  1774.             printf("Could not create the virtual buffer.\n");
  1775.             exit(1);
  1776.             }
  1777.          handle = fg_vbdefine(buffer,WIDTH,HEIGHT);
  1778.          fg_vbopen(handle);
  1779.  
  1780.          /* fill the virtual buffer with a series of narrow rectangles */
  1781.  
  1782.          for (x = 0; x < WIDTH; x++) {
  1783.             fg_setcolor(x);
  1784.             fg_rect(x,x,0,HEIGHT-1);
  1785.             }
  1786.  
  1787.          /* scroll the virtual buffer through a 100x50 window on the */
  1788.          /* visual page, such that the top half scrolls left and the */
  1789.          /* bottom half scrolls right */
  1790.  
  1791.          for (x = 0; x < WIDTH-99; x++) {
  1792.             fg_vbpaste(x,x+99,0,24,110,99);
  1793.             fg_vbpaste(WIDTH-100-x,WIDTH-1-x,25,49,110,124);
  1794.             }
  1795.          fg_waitkey();
  1796.  
  1797.          /* close the virtual buffer */                                        
  1798.                              Chapter 8:  Video Pages and Virtual Buffers   179
  1799.  
  1800.  
  1801.          fg_vbclose();
  1802.  
  1803.          /* restore original video mode and exit */
  1804.  
  1805.          fg_setmode(old_mode);
  1806.          fg_reset();
  1807.       }
  1808.  
  1809.  
  1810.      The last virtual buffer example program we'll present in this chapter is
  1811. a version of example 8-12 modified to work with virtual buffers. Example 8-12
  1812. used a logical page in conventional memory to preserve the visual page
  1813. contents across video mode switches, with some help from Fastgraph's
  1814. fg_getentry and fg_setentry routines. Example 8-17 illustrates how you can
  1815. accomplish the same thing with a virtual buffer. It runs in the 320x240 256-
  1816. color graphics mode (mode 22) and uses a virtual buffer whose size is
  1817. identical to the screen resolution. After creating the virtual buffer, the
  1818. program fills the visual page with blue pixels and draws a white border around
  1819. it. It then uses fg_vbcut to copy the screen contents to the virtual buffer.
  1820. Like example 8-12, the program temporarily switches back to the original video
  1821. mode and waits for a keystroke. It then reverts to mode 22 and uses fg_vbpaste
  1822. to restore the screen contents.
  1823.  
  1824.                                  Example 8-17.
  1825.  
  1826.             #include <fastgraf.h>
  1827.             #include <stdio.h>
  1828.             #include <stdlib.h>
  1829.             #ifdef __TURBOC__
  1830.             #include <alloc.h>
  1831.             #else
  1832.             #include <malloc.h>
  1833.             #endif
  1834.  
  1835.             void main(void);
  1836.  
  1837.             void main()
  1838.             {
  1839.                int handle;
  1840.                int old_mode;
  1841.             #ifdef FG32
  1842.                char *buffer;
  1843.             #else
  1844.                char huge *buffer;
  1845.             #endif
  1846.  
  1847.                fg_initpm();
  1848.                old_mode = fg_getmode();
  1849.                fg_setmode(22);
  1850.                fg_vbinit();
  1851.  
  1852.             #ifdef FG32
  1853.                buffer = (char *)malloc(320*240);
  1854.             #elif defined(__TURBOC__)
  1855.                buffer = (char huge *)farmalloc(320L*240L);                     
  1856. 180   Fastgraph User's Guide
  1857.  
  1858.             #else
  1859.                buffer = (char huge *)halloc(320L*240L,1);
  1860.             #endif
  1861.                if (buffer == NULL) {
  1862.                   fg_setmode(old_mode);
  1863.                   fg_reset();
  1864.                   printf("Could not create the virtual buffer.\n");
  1865.                   exit(1);
  1866.                   }
  1867.                handle = fg_vbdefine(buffer,320,240);
  1868.  
  1869.                fg_setcolor(9);
  1870.                fg_fillpage();
  1871.                fg_setcolor(15);
  1872.                fg_box(0,319,0,239);
  1873.                fg_vbopen(handle);
  1874.                fg_vbcut(0,319,0,239,0,239);
  1875.                fg_vbclose();
  1876.                fg_waitkey();
  1877.  
  1878.                fg_setmode(old_mode);
  1879.                fg_cursor(0);
  1880.                fg_setcolor(15);
  1881.                fg_text("Press any key.",14);
  1882.                fg_waitkey();
  1883.  
  1884.                fg_setmode(22);
  1885.                fg_vbopen(handle);
  1886.                fg_vbpaste(0,319,0,239,0,239);
  1887.                fg_waitkey();
  1888.  
  1889.                fg_vbclose();
  1890.                fg_setmode(old_mode);
  1891.                fg_reset();
  1892.             }
  1893.  
  1894.  
  1895.      Fastgraph includes other functions for working with virtual buffers, but
  1896. we'll defer our discussion of them until later chapters.
  1897.  
  1898.  
  1899. Summary of Video Page and Virtual Buffer Routines
  1900.  
  1901.      This section summarizes the functional descriptions of the Fastgraph
  1902. routines presented in this chapter. More detailed information about these
  1903. routines, including their arguments and return values, may be found in the
  1904. Fastgraph Reference Manual.
  1905.  
  1906.      FG_ALLOCATE creates a virtual video page. The amount of memory required
  1907. depends on the current video mode. This routine has no effect if it references
  1908. a physical or logical video page.
  1909.  
  1910.      FG_ALLOCEMS creates a logical page in expanded memory (EMS). The amount
  1911. of memory required depends on the current video mode and video buffer
  1912. dimensions. This routine has no effect if it references a physical or virtual  
  1913.                              Chapter 8:  Video Pages and Virtual Buffers   181
  1914.  
  1915. video page. In protected mode, fg_initems always fails, so fg_allocems is
  1916. effectively disabled.
  1917.  
  1918.      FG_ALLOCXMS creates a logical page in extended memory (XMS). The amount
  1919. of memory required depends on the current video mode and video buffer
  1920. dimensions. This routine has no effect if it references a physical or virtual
  1921. video page. In protected mode, fg_initxms always fails, so fg_allocxms is
  1922. effectively disabled.
  1923.  
  1924.      FG_COPYPAGE transfers the contents of one video page to another. The
  1925. pages may be physical, virtual, or logical video pages. If both pages are
  1926. logical pages, they must exist in the same type of memory. This routine always
  1927. applies to video pages, even when a virtual buffer is active.
  1928.  
  1929.      FG_DEFPAGES defines the SVGA banks for the source and destination page
  1930. numbers when using Fastgraph's block transfer routines with extended video
  1931. pages.
  1932.  
  1933.      FG_FINDPAGE finds an available video page number for a virtual or logical
  1934. page.
  1935.  
  1936.      FG_FREEPAGE releases a virtual or logical video page created with
  1937. fg_allocate, fg_alloccms, fg_allocems, or fg_allocxms. This routine has no
  1938. effect if it references a physical video page, or a virtual page that was
  1939. never created.
  1940.  
  1941.      FG_GETADDR returns the real mode segment address or protected mode
  1942. segment selector for the active video page.
  1943.  
  1944.      FG_GETENTRY retrieves the type and address of a physical, virtual, or
  1945. logical video page. This routine is useful for saving virtual or logical page
  1946. contents across video mode changes.
  1947.  
  1948.      FG_GETPAGE returns the active video page number.
  1949.  
  1950.      FG_GETVPAGE returns the visual video page number.
  1951.  
  1952.      FG_INITEMS initializes expanded memory for use with Fastgraph's logical
  1953. pages. In protected mode, the expanded memory initialization will always fail.
  1954.  
  1955.      FG_INITXMS initializes extended memory for use with Fastgraph's logical
  1956. pages. In protected mode, the extended memory initialization will always fail.
  1957.  
  1958.      FG_PAGESIZE returns the video page size in bytes for the current video
  1959. mode. The page size is always the video page size, even when a virtual buffer
  1960. is active.
  1961.  
  1962.      FG_RESIZE changes the dimensions of a video page in EGA and VGA graphics
  1963. modes. This function has no effect when a virtual buffer is active.
  1964.  
  1965.      FG_SETENTRY specifies the type and address of a physical, virtual, or
  1966. logical video page. For logical pages, it further specifies if the page
  1967. resides in conventional, expanded, or extended memory. This routine is useful
  1968. for saving virtual or logical page contents across video mode changes, or for
  1969. manual creation of virtual and logical pages.                                  
  1970. 182   Fastgraph User's Guide
  1971.  
  1972.      FG_SETPAGE establishes the active video page. It may be a physical or
  1973. virtual page.
  1974.  
  1975.      FG_SETVPAGE establishes the visual video page. It may be a physical or
  1976. virtual page.
  1977.  
  1978.      FG_VBALLOC creates a virtual buffer of the specified size. The memory for
  1979. the virtual buffer is allocated automatically. This routine should be used
  1980. instead of fg_vbdefine for real mode compilers that do not support huge memory
  1981. blocks (that is, far blocks larger than 64K bytes). The fg_vballoc routine is
  1982. not present in Fastgraph's protected mode libraries.
  1983.  
  1984.      FG_VBCLOSE closes the active virtual buffer and directs graphics output
  1985. back to the active video page.
  1986.  
  1987.      FG_VBCUT copies a rectangular region from the active video page to the
  1988. active virtual buffer.
  1989.  
  1990.      FG_VBDEFINE creates a virtual buffer of the specified size.
  1991.  
  1992.      FG_VBFREE releases a virtual buffer's handle and frees the memory
  1993. allocated to a virtual buffer created with fg_vballoc. The fg_vbfree routine
  1994. is not present in Fastgraph's protected mode libraries.
  1995.  
  1996.      FG_VBHANDLE returns the handle for the active virtual buffer, or -1 if no
  1997. virtual buffer is active.
  1998.  
  1999.      FG_VBINIT initializes Fastgraph's virtual buffer environment. This
  2000. routine must be called once, before any other routines that reference virtual
  2001. buffers.
  2002.  
  2003.      FG_VBOPEN makes an existing virtual buffer the active virtual buffer.
  2004.  
  2005.      FG_VBPASTE copies a rectangular region from the active virtual buffer to
  2006. the active video page.
  2007.  
  2008.      FG_VBUNDEF releases the handle associated with a virtual buffer.
  2009.