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

  1.  
  2.  
  3.  
  4.  
  5.  
  6. Chapter 11
  7.  
  8.  
  9.  
  10.  
  11.  
  12. Block Transfer Routines                                                        
  13. 256   Fastgraph User's Guide
  14.  
  15.  
  16. Overview
  17.  
  18.      The Fastgraph routines described in this chapter copy rectangular blocks
  19. between areas of video memory, between virtual buffers, between conventional
  20. memory and video memory, or between conventional memory and virtual buffers.
  21. Such routines are sometimes called Blit or BitBlt routines in other
  22. literature. Block transfers are useful in many graphics applications, but they
  23. are especially important in animation.
  24.  
  25.      Fastgraph provides several types of block transfer routines, each
  26. optimized for its specific purpose. Because these routines are often used in
  27. speed-critical contexts, they do not perform clipping. If needed, clipping can
  28. generally be done at the application level by adjusting the block coordinates
  29. to fit within the clipping region.
  30.  
  31.      This chapter will discuss Fastgraph's block transfer routines in detail.
  32. The information presented here, combined with the video page, virtual buffer,
  33. and image management routines of the previous three chapters, will provide the
  34. tools we need for the animation techniques presented in the next chapter.
  35.  
  36.  
  37. Full Page Transfer
  38.  
  39.      Fastgraph's simplest block transfer routine is fg_copypage, introduced in
  40. Chapter 8. The fg_copypage routine transfers the entire contents of one video
  41. page to another. The first argument is the number of the source video page,
  42. and the second argument is the number of the destination video page. The pages
  43. may be physical, virtual, or logical video pages. If both the source and
  44. destination pages are logical pages, the pages must exist in the same type of
  45. memory. For example, you cannot copy a logical page in extended memory to a
  46. logical page in conventional memory. The fg_copypage routine always works with
  47. video pages, even if a virtual buffer is active.
  48.  
  49.      Example 11-1 illustrates the use of fg_copypage in a 320x200 color
  50. graphics mode. The program displays the word "test" in the middle of the
  51. visual page (page 0) and then uses fg_allocate to create a virtual video page
  52. (page 1). The virtual page is needed in case the program is running in a video
  53. mode with only one physical page. Next, the program uses fg_copypage to
  54. transfer the visual page contents to page 1. After waiting for a keystroke,
  55. the program erases the visual page, waits for another keystroke, and copies
  56. the contents of page 1 back to the visual page. It then releases the virtual
  57. page and exits.
  58.  
  59.                                  Example 11-1.
  60.  
  61.                  #include <fastgraf.h>
  62.                  #include <stdio.h>
  63.                  #include <stdlib.h>
  64.                  void main(void);
  65.  
  66.                  void main()
  67.                  {
  68.                     int new_mode, old_mode;
  69.  
  70.                     fg_initpm();                                               
  71.                                     Chapter 11:  Block Transfer Routines   257
  72.  
  73.                     new_mode = fg_bestmode(320,200,2);
  74.                     if (new_mode < 0 || new_mode == 12) {
  75.                        printf("This program requires a 320 ");
  76.                        printf("x 200 color graphics mode.\n");
  77.                        exit(1);
  78.                        }
  79.                     old_mode = fg_getmode();
  80.                     fg_setmode(new_mode);
  81.  
  82.                     fg_setcolor(7);
  83.                     fg_rect(0,319,0,199);
  84.                     fg_setcolor(9);
  85.                     fg_locate(12,18);
  86.                     fg_text("test",4);
  87.                     fg_waitkey();
  88.  
  89.                     fg_allocate(1);
  90.                     fg_copypage(0,1);
  91.                     fg_erase();
  92.                     fg_waitkey();
  93.  
  94.                     fg_copypage(1,0);
  95.                     fg_waitkey();
  96.  
  97.                     fg_freepage(1);
  98.                     fg_setmode(old_mode);
  99.                     fg_reset();
  100.                  }
  101.  
  102.  
  103.  
  104. Byte Boundaries
  105.  
  106.      Video memory, like standard random-access memory, is divided into units
  107. called bytes. In text modes, each byte holds either a character or an
  108. attribute. In graphics modes, each byte of video memory holds one or more
  109. horizontally contiguous pixels. If two adjacent horizontal pixels are stored
  110. in different bytes, then we say a byte boundary exists between the two pixels.
  111.  
  112.      The number of pixels per byte depends on the video mode being used, so
  113. the location of the byte boundaries also depends on the video mode. That is, a
  114. byte boundary in a CGA graphics mode is not necessarily a byte boundary in a
  115. VGA graphics mode. The following table summarizes the number of pixels per
  116. byte of video memory and the byte boundary sequences for each supported
  117. graphics video mode. Notice that any horizontal coordinate whose value is a
  118. multiple of 8 is always a byte boundary, regardless of the video mode.
  119.  
  120.                        mode     pixels     horizontal coordinates
  121.                       number   per byte    of byte boundaries
  122.  
  123.                          4         4       0, 4,  8, 12, ... , 316
  124.                          5         4       0, 4,  8, 12, ... , 316
  125.                          6         8       0, 8, 16, 24, ... , 632
  126.                          9         2       0, 2,  4,  6, ... , 318
  127.                         11         8       0, 8, 16, 24, ... , 712
  128.                         12         4       0, 4,  8, 12, ... , 316             
  129. 258   Fastgraph User's Guide
  130.  
  131.                         13         8       0, 8, 16, 24, ... , 312
  132.                         14         8       0, 8, 16, 24, ... , 632
  133.                         15         8       0, 8, 16, 24, ... , 632
  134.                         16         8       0, 8, 16, 24, ... , 632
  135.                         17         8       0, 8, 16, 24, ... , 632
  136.                         18         8       0, 8, 16, 24, ... , 632
  137.                         19         1       0, 1,  2,  3, ... , 319
  138.                         20         1       0, 4,  8, 12, ... , 316
  139.                         21         1       0, 4,  8, 12, ... , 316
  140.                         22         1       0, 4,  8, 12, ... , 316
  141.                         23         1       0, 4,  8, 12, ... , 316
  142.                         24         1       0, 1,  2,  3, ... , 639
  143.                         25         1       0, 1,  2,  3, ... , 639
  144.                         26         1       0, 1,  2,  3, ... , 799
  145.                         27         1       0, 1,  2,  3, ... , 1023
  146.                         28         8       0, 8, 16, 24, ... , 792
  147.                         29         8       0, 8, 16, 24, ... , 1016
  148.  
  149.      Block transfer routines are often used in animation sequences requiring
  150. high-performance graphics, so these routines must be as efficient as possible.
  151. To this end, Fastgraph will force their horizontal pixel coordinates to byte
  152. boundaries, which eliminates the need to process any pixels individually.
  153. Fastgraph accomplishes this by reducing minimum horizontal coordinates to a
  154. byte boundary and extending maximum horizontal coordinates to the last pixel
  155. in a video memory byte. Since we are talking about pixel coordinates and not
  156. character cells, the coordinate adjustment only occurs in graphics video
  157. modes. Designing an application so block transfers occur on byte boundaries
  158. might take additional planning, but it will be time well spent.
  159.  
  160.      An example might best help explain this important feature. In the
  161. EGA/VGA/SVGA 16-color graphics modes (modes 13 to 18, 28, and 29),  byte
  162. boundaries occur at every eighth pixel. Thus, when you use the block transfer
  163. routines in these modes, Fastgraph reduces minimum x coordinates to the next
  164. lower multiple of eight. Similarly, it extends their maximum x coordinates to
  165. the next higher multiple of eight, less one pixel. That is, if a minimum x
  166. coordinate is 10 and a maximum x coordinate is 30, Fastgraph will adjust these
  167. values to 8 and 31 respectively. If the x coordinates were originally 8 and
  168. 31, Fastgraph would leave them unchanged.
  169.  
  170.      In the MCGA and SVGA 256-color graphics modes (modes 19 and 24 to 27)
  171. each pixel occupies a separate byte of video memory, so Fastgraph does not
  172. need to adjust horizontal coordinates. However, in the XVGA graphics modes
  173. (modes 20 to 23), some coordinate adjustment might be needed. The XVGA modes
  174. store four pixels at each video memory address, one in each of four bit
  175. planes. The bit plane number for a pixel whose horizontal coordinate is x is
  176. given by the quantity x modulo 4. In XVGA modes, the source and destination
  177. minimum x coordinates must reference pixels in the same bit plane. Put another
  178. way, the relation
  179.  
  180.                xmin_source modulo 4 = xmin_destination modulo 4
  181.  
  182. must be true. If it isn't, Fastgraph reduces the destination minimum x value
  183. to the same bit plane as the source minimum x value.                           
  184.                                     Chapter 11:  Block Transfer Routines   259
  185.  
  186.  
  187. Dual SVGA Banks
  188.  
  189.      Accessing video memory in SVGA graphics modes is controlled through a
  190. banking scheme that maps contiguous 64KB blocks of video memory into a
  191. segmented address space. In other words, referencing a specific byte in video
  192. memory requires a bank number and an address within that bank. Some SVGA
  193. chipsets provide separate read and write bank registers, while others perform
  194. both operations through the same bank register.
  195.  
  196.      If a chipset supports separate read and write banks, Fastgraph's block
  197. transfer routines can copy the source region directly to the destination
  198. region. However, chipsets that employ a single bank register require that
  199. these routines copy the source region to an intermediate buffer and then copy
  200. the buffer contents to the destination. This obviously makes a block transfer
  201. operation slower on single-bank chipsets. Bit 3 of the fg_svgastat return
  202. value will be set if the active SVGA chipset supports separate read and write
  203. banks.
  204.  
  205.  
  206. The "Hidden" Video Page
  207.  
  208.      Some of Fastgraph's block transfer routines reference a video page called
  209. the hidden page. The Fastgraph routine fg_sethpage defines which video page
  210. will be used as the hidden page. This routine takes as its only argument an
  211. integer value specifying the hidden page number. If you are using a virtual
  212. video page for the hidden page, you must call fg_sethpage after allocating
  213. that page. There is also a routine named fg_gethpage that returns the hidden
  214. page number, as specified in the most recent call to fg_sethpage, as its
  215. function value. The fg_gethpage routine takes no arguments.
  216.  
  217.  
  218. Saving and Restoring Blocks
  219.  
  220.      The next two block transfer routines we'll discuss are fg_save and
  221. fg_restore. The fg_save routine transfers a rectangular region from the active
  222. video page (as defined in the most recent call to fg_setpage) to the same
  223. position on the hidden video page (as defined in the most recent call to
  224. fg_sethpage). The fg_restore routine performs the complementary task -- it
  225. transfers a rectangular region from the hidden page to the active page. Each
  226. of these routines requires four arguments that define the coordinates of the
  227. block to transfer, in the order minimum x, maximum x, minimum y, and maximum
  228. y. In text modes, the coordinates are expressed as character space quantities
  229. (rows and columns). In graphics modes, they are expressed as screen space
  230. values (pixels), with the x coordinates extended to byte boundaries if
  231. required. There are also world space versions of these routines named fg_savew
  232. and fg_restorew available in graphics modes. The fg_restore, fg_restorew,
  233. fg_save, and fg_savew routines always work with video pages, even if a virtual
  234. buffer is active.
  235.  
  236.      Example 11-2 demonstrates the use of fg_save, fg_restore, and fg_sethpage
  237. in an 80-column text video mode. After establishing the video mode (note the
  238. calls to fg_testmode specify that two video pages are needed), the program
  239. fills the screen with text and then waits for a keystroke. Following this, the
  240. program displays a small pop-up window prompting for another keystroke. After
  241. waiting for the second keystroke, the program erases the pop-up window by      
  242. 260   Fastgraph User's Guide
  243.  
  244. restoring the original screen contents, and then waits for yet another
  245. keystroke before returning to DOS. We'll present the program now, and
  246. afterward analyze it in detail.
  247.  
  248.                                  Example 11-2.
  249.  
  250.                 #include <fastgraf.h>
  251.                 #include <stdio.h>
  252.                 #include <stdlib.h>
  253.                 void main(void);
  254.  
  255.                 void main()
  256.                 {
  257.                    int row;
  258.                    int old_mode;
  259.                    char string[17];
  260.  
  261.                    fg_initpm();
  262.                    old_mode = fg_getmode();
  263.  
  264.                    if (fg_testmode(3,2))
  265.                       fg_setmode(3);
  266.                    else if (fg_testmode(7,2))
  267.                       fg_setmode(7);
  268.                    else {
  269.                       printf("This program requires\n");
  270.                       printf("an 80-column display.\n");
  271.                       exit(1);
  272.                       }
  273.                    fg_cursor(0);
  274.                    fg_setattr(9,7,0);
  275.  
  276.                    for (row = 0; row < 25; row++) {
  277.                       sprintf(string," This is row %2d ",row);
  278.                       fg_locate(row,0);
  279.                       fg_text(string,16);
  280.                       fg_text(string,16);
  281.                       fg_text(string,16);
  282.                       fg_text(string,16);
  283.                       fg_text(string,16);
  284.                       }
  285.                    fg_waitkey();
  286.  
  287.                    fg_allocate(1);
  288.                    fg_sethpage(1);
  289.                    fg_save(32,47,11,13);
  290.                    fg_setcolor(1);
  291.                    fg_rect(32,47,11,13);
  292.                    fg_setattr(15,1,0);
  293.                    fg_locate(12,33);
  294.                    fg_text("Press any key.",14);
  295.                    fg_waitkey();
  296.  
  297.                    fg_restore(32,47,11,13);
  298.                    fg_waitkey();                                               
  299.                                     Chapter 11:  Block Transfer Routines   261
  300.  
  301.                    fg_freepage(1);
  302.                    fg_setmode(old_mode);
  303.                    fg_reset();
  304.                 }
  305.  
  306.  
  307.      Example 11-2 first establishes the video mode and uses fg_cursor to make
  308. the BIOS cursor invisible. It then executes a for loop that fills each row of
  309. the screen with the phrase "This is row n", where n is the row number (between
  310. 0 and 24). Next, the program uses fg_allocate to create video page 1 as a
  311. virtual video page. This is needed in case the program is running in mode 7,
  312. which has only one true page (if the program is running in mode 3, fg_allocate
  313. has no effect). The program then makes page 1 the hidden page by calling
  314. fg_sethpage.
  315.  
  316.      After setting up the hidden video page, but before displaying the pop-up
  317. window, example 11-2 uses fg_save to save the current contents of the area
  318. that the pop-up window will replace. The fg_save routine copies this region to
  319. the hidden page. The program then displays the pop-up window in the middle of
  320. the screen and leaves it there until a key is pressed. Following this, the
  321. program uses fg_restore to replace the pop-up window with the original
  322. contents of that region. This effectively erases the pop-up window and
  323. restores the original screen. The program then waits for another keystroke,
  324. after which it releases the virtual page and returns to DOS.
  325.  
  326.      The next example, 11-3, is similar to example 11-2, but it runs in a
  327. 320x200 color graphics mode instead of a text mode. The main differences
  328. between this program and example 11-2 are the use of 40-column text and the
  329. use of screen space coordinates instead of character space coordinates in the
  330. calls to fg_save, fg_restore, and fg_rect. Note that the call to fg_allocate
  331. creates a virtual page if the program is running in modes 4, 9, or 19. In
  332. modes 13 and 20, which respectively have four and eight physical pages,
  333. fg_allocate does nothing.
  334.  
  335.                                  Example 11-3.
  336.  
  337.               #include <fastgraf.h>
  338.               #include <stdio.h>
  339.               #include <stdlib.h>
  340.               void main(void);
  341.  
  342.               void main()
  343.               {
  344.                  int row;
  345.                  int new_mode, old_mode;
  346.                  char string[21];
  347.  
  348.                  fg_initpm();
  349.                  new_mode = fg_bestmode(320,200,2);
  350.                  if (new_mode < 0 || new_mode == 12) {
  351.                     printf("This program requires a 320 ");
  352.                     printf("x 200 color graphics mode.\n");
  353.                     exit(1);
  354.                     }
  355.                  old_mode = fg_getmode();
  356.                  fg_setmode(new_mode);                                         
  357. 262   Fastgraph User's Guide
  358.  
  359.  
  360.                  fg_setcolor(7);
  361.                  fg_rect(0,319,0,199);
  362.                  fg_setcolor(9);
  363.  
  364.                  for (row = 0; row < 25; row++) {
  365.                     sprintf(string,"   This is row %2d   ",row);
  366.                     fg_locate(row,0);
  367.                     fg_text(string,20);
  368.                     fg_text(string,20);
  369.                     }
  370.                  fg_waitkey();
  371.  
  372.                  fg_allocate(1);
  373.                  fg_sethpage(1);
  374.                  fg_save(96,223,88,111);
  375.                  fg_setcolor(1);
  376.                  fg_rect(96,223,88,111);
  377.                  fg_setcolor(15);
  378.                  fg_locate(12,13);
  379.                  fg_text("Press any key.",14);
  380.                  fg_waitkey();
  381.  
  382.                  fg_restore(96,223,88,111);
  383.                  fg_waitkey();
  384.  
  385.                  fg_freepage(1);
  386.                  fg_setmode(old_mode);
  387.                  fg_reset();
  388.               }
  389.  
  390.  
  391.  
  392. A More General Block Transfer Routine
  393.  
  394.      The fg_save and fg_restore routines each copy a rectangular region from
  395. one video page to the same position on another video page. What if you need to
  396. copy the region to a different position on another video page, or copy it
  397. elsewhere on the same video page? Fastgraph provides a more general block
  398. transfer routine named fg_transfer. The fg_transfer routine copies a
  399. rectangular region on any video page to any position on any video page
  400. (however, it cannot copy overlapping blocks on the same video page). Like
  401. fg_save and fg_restore, fg_transfer works in text and graphics video modes. In
  402. graphics modes, fg_transfer extends its x coordinates to byte boundaries if
  403. necessary. The fg_transfer routine always works with video pages, even if a
  404. virtual buffer is active (use fg_vbcut and fg_vbpaste to copy blocks between
  405. virtual buffers and video pages, or fg_vbcopy to copy blocks between virtual
  406. buffers).
  407.  
  408.      The fg_transfer routine requires eight integer arguments. The first four
  409. arguments define the region to copy, in the same order as expected by fg_save
  410. and fg_restore. The next two arguments define the lower left corner of the
  411. block destination, while the final two arguments respectively specify the
  412. source and destination video page numbers. In short, fg_transfer copies the
  413. specified region from the source page to the specified position on the
  414. destination page.                                                              
  415.                                     Chapter 11:  Block Transfer Routines   263
  416.  
  417.  
  418.      Example 11-4 is the same as example 11-2, but it uses fg_transfer rather
  419. than fg_save and fg_restore. We have arbitrarily chosen to copy the region
  420. overwritten by the pop-up window to the lower left corner of the hidden page
  421. (page 1). When we copy this region back to the visual page, we copy from the
  422. lower left corner of the hidden page back to the original position on the
  423. visual page (page 0). This sequence is shown in the following diagram.
  424.  
  425.               (11,32)    (11,47)               (22,0)     (22,15)
  426.                                  first call
  427.                 This is row 11   ------------>   This is row 11
  428.                 This is row 12                   This is row 12
  429.                 This is row 13   <------------   This is row 13
  430.                                    second call
  431.               (13,32)    (13,47)               (24,0)     (24,15)
  432.  
  433.                  visual page (0)                  hidden page (1)
  434.  
  435. To copy one region to a new position and then back to its original position,
  436. note how we make the fifth and sixth arguments in the first call to
  437. fg_transfer the same values as the first and fourth arguments in the second
  438. call. Similarly, the fifth and sixth arguments in the second call must be the
  439. same as the first and fourth arguments in the first call. With all that out of
  440. the way, here is example 11-4.
  441.  
  442.                                  Example 11-4.
  443.  
  444.                 #include <fastgraf.h>
  445.                 #include <stdio.h>
  446.                 #include <stdlib.h>
  447.                 void main(void);
  448.  
  449.                 void main()
  450.                 {
  451.                    int row;
  452.                    int old_mode;
  453.                    char string[17];
  454.  
  455.                    fg_initpm();
  456.                    old_mode = fg_getmode();
  457.  
  458.                    if (fg_testmode(3,2))
  459.                       fg_setmode(3);
  460.                    else if (fg_testmode(7,2))
  461.                       fg_setmode(7);
  462.                    else {
  463.                       printf("This program requires\n");
  464.                       printf("an 80-column display.\n");
  465.                       exit(1);
  466.                       }
  467.                    fg_cursor(0);
  468.                    fg_setattr(9,7,0);
  469.  
  470.                    for (row = 0; row < 25; row++) {
  471.                       sprintf(string," This is row %2d ",row);
  472.                       fg_locate(row,0);                                        
  473. 264   Fastgraph User's Guide
  474.  
  475.                       fg_text(string,16);
  476.                       fg_text(string,16);
  477.                       fg_text(string,16);
  478.                       fg_text(string,16);
  479.                       fg_text(string,16);
  480.                       }
  481.                    fg_waitkey();
  482.  
  483.                    fg_allocate(1);
  484.                    fg_transfer(32,47,11,13,0,24,0,1);
  485.                    fg_setcolor(1);
  486.                    fg_rect(32,47,11,13);
  487.                    fg_setattr(15,1,0);
  488.                    fg_locate(12,33);
  489.                    fg_text("Press any key.",14);
  490.                    fg_waitkey();
  491.  
  492.                    fg_transfer(0,15,22,24,32,13,1,0);
  493.                    fg_fg_waitkey();
  494.  
  495.                    fg_freepage(1);
  496.                    fg_setmode(old_mode);
  497.                    fg_reset();
  498.                 }
  499.  
  500.  
  501.      Example 11-5 illustrates another use of the fg_transfer routine. This
  502. example is functionally identical to example 10-10, but it uses fg_transfer
  503. instead of fg_getmap and fg_drawmap. With the fg_transfer routine, we
  504. eliminate the calls to fg_getmap and fg_drawmap, the two calls to fg_move, and
  505. the 32-byte array needed to retrieve the block. As an added bonus, using
  506. fg_transfer is much faster than the technique of example 10-10, although we
  507. probably won't notice this gain with such a small block.
  508.  
  509.      The block copied in example 11-5 is one row of four characters, so its
  510. width in screen space is 32 pixels and its height is 8 pixels. Because the
  511. block is in the upper left corner of the screen, the block boundaries are
  512. xmin=0, xmax=31, ymin=0, and ymax=7. We want to move the block one-half
  513. character cell (4 pixels) to the right and one row (8 pixels) down, so our
  514. destination coordinates are x=4 (xmin+4) and y=15 (ymax+8). Note how the
  515. program restricts itself to modes 19 and 20 to insure the block copy is not
  516. affected by byte boundaries. Also, we are copying the block from one position
  517. to another on the visual page, so both the source and destination pages are 0.
  518.  
  519.                                  Example 11-5.
  520.  
  521.                   #include <fastgraf.h>
  522.                   #include <stdio.h>
  523.                   #include <stdlib.h>
  524.                   void main(void);
  525.  
  526.                   void main()
  527.                   {
  528.                      int old_mode, new_mode;
  529.  
  530.                      fg_initpm();                                              
  531.                                     Chapter 11:  Block Transfer Routines   265
  532.  
  533.                      new_mode = fg_bestmode(320,200,1);
  534.                      if (new_mode < 19) {
  535.                         printf("This program requires a ");
  536.                         printf("256-color graphics mode.\n");
  537.                         exit(1);
  538.                         }
  539.  
  540.                      old_mode = fg_getmode();
  541.                      fg_setmode(new_mode);
  542.  
  543.                      fg_setcolor(9);
  544.                      fg_text("text",4);
  545.                      fg_waitkey();
  546.  
  547.                      fg_transfer(0,31,0,7,4,15,0,0);
  548.                      fg_waitkey();
  549.  
  550.                      fg_setmode(old_mode);
  551.                      fg_reset();
  552.                   }
  553.  
  554.  
  555.      Example 11-6 shows yet another application of fg_transfer in a graphics
  556. video mode. The program displays a rectangle in the upper left quadrant of the
  557. screen and then centers the word "quadrant" inside the rectangle. After
  558. waiting for a keystroke, the program uses fg_transfer to first copy the upper
  559. left quadrant to the upper right quadrant. It then uses fg_transfer again to
  560. copy the upper half of the screen to the lower half. The result of this is the
  561. screen being filled with what was originally in the upper left quadrant.
  562.  
  563.                                  Example 11-6.
  564.  
  565.                  #include <fastgraf.h>
  566.                  #include <stdio.h>
  567.                  #include <stdlib.h>
  568.                  void main(void);
  569.  
  570.                  void main()
  571.                  {
  572.                     int new_mode, old_mode;
  573.  
  574.                     fg_initpm();
  575.                     new_mode = fg_bestmode(320,200,1);
  576.                     if (new_mode < 0 || new_mode == 12) {
  577.                        printf("This program requires a 320 ");
  578.                        printf("x 200 color graphics mode.\n");
  579.                        exit(1);
  580.                        }
  581.                     old_mode = fg_getmode();
  582.                     fg_setmode(new_mode);
  583.  
  584.                     fg_setcolor(7);
  585.                     fg_rect(0,159,0,99);
  586.                     fg_setcolor(9);
  587.                     fg_locate(6,6);
  588.                     fg_text("quadrant",8);                                     
  589. 266   Fastgraph User's Guide
  590.  
  591.                     fg_waitkey();
  592.  
  593.                     fg_transfer(0,159,0,99,160, 99,0,0);
  594.                     fg_transfer(0,319,0,99,  0,199,0,0);
  595.                     fg_waitkey();
  596.  
  597.                     fg_setmode(old_mode);
  598.                     fg_reset();
  599.                  }
  600.  
  601.  
  602.  
  603. Block Transfer Routines for Virtual Buffers
  604.  
  605.      Fastgraph's fg_restore, fg_save, and fg_transfer routines copy blocks
  606. between physical or virtual video pages. Other routines are provided for block
  607. transfers between virtual buffers and video pages, or between virtual buffers.
  608. In our discussion of virtual buffers in Chapter 8, we described Fastgraph's
  609. fg_vbcut and fg_vbpaste routines. Recall that fg_vbcut copies a block from the
  610. active video page to the active virtual buffer, while fg_vbpaste copies a
  611. block from the active virtual buffer to the active video page.
  612.  
  613.      We'll now introduce another block transfer routine, fg_vbcopy, for
  614. copying blocks between two virtual buffers, or to a non-overlapping position
  615. in the same virtual buffer. The fg_vbcopy arguments are exactly the same as
  616. those of fg_transfer, except the last two arguments reference the source and
  617. destination virtual buffer handles instead of video page numbers. Example 11-7
  618. is similar to example 11-6, but it uses fg_vbcopy to perform the two block
  619. copy operations in a 320x200 virtual buffer (these were done with fg_transfer
  620. in example 11-6). After this, it calls fg_vbpaste to display the virtual
  621. buffer contents.
  622.  
  623.                                  Example 11-7.
  624.  
  625.                 #include <fastgraf.h>
  626.                 #include <stdio.h>
  627.                 #include <stdlib.h>
  628.                 void main(void);
  629.  
  630.                 #ifdef FG32
  631.                 char buffer[64000];
  632.                 #else
  633.                 char far buffer[64000];
  634.                 #endif
  635.  
  636.                 void main()
  637.                 {
  638.                    int handle;
  639.                    int new_mode, old_mode;
  640.  
  641.                    fg_initpm();
  642.                    new_mode = fg_bestmode(320,200,1);
  643.                    if (new_mode < 0 || new_mode == 12) {
  644.                       printf("This program requires a 320 ");
  645.                       printf("x 200 color graphics mode.\n");
  646.                       exit(1);                                                 
  647.                                     Chapter 11:  Block Transfer Routines   267
  648.  
  649.                       }
  650.                    old_mode = fg_getmode();
  651.                    fg_setmode(new_mode);
  652.  
  653.                    fg_vbinit();
  654.                    handle = fg_vbdefine(buffer,320,200);
  655.                    fg_vbopen(handle);
  656.  
  657.                    fg_setcolor(7);
  658.                    fg_rect(0,159,0,99);
  659.                    fg_setcolor(9);
  660.                    fg_locate(6,6);
  661.                    fg_text("quadrant",8);
  662.  
  663.                    fg_vbcopy(0,159,0,99,160, 99,handle,handle);
  664.                    fg_vbcopy(0,319,0,99,  0,199,handle,handle);
  665.                    fg_vbpaste(0,319,0,199,0,199);
  666.                    fg_waitkey();
  667.  
  668.                    fg_vbclose();
  669.                    fg_setmode(old_mode);
  670.                    fg_reset();
  671.  
  672.  
  673.  
  674. Blocks with Transparent Colors
  675.  
  676.      The next block transfer routines we'll discuss are fg_tcxfer, fg_tcmask,
  677. and fg_tcdefine. The fg_tcxfer routine is similar to fg_transfer in that it
  678. copies a rectangular region from one position to another, but fg_tcxfer allows
  679. you to treat one or more colors as transparent (the name fg_tcxfer stands for
  680. transparent color transfer). In other words, any pixel whose color value is
  681. defined to be transparent is not copied to the destination area. The fg_tcxfer
  682. routine's arguments are the same as for the fg_transfer routine, but fg_tcxfer
  683. has no effect in text video modes. Because fg_tcxfer must examine the color of
  684. individual pixels, it is not nearly as fast as fg_transfer. The fg_tcxfer
  685. routine always works with video pages, even if a virtual buffer is active (the
  686. fg_vbtcxfer routine, described in the next section, provides transparent color
  687. block transfers for virtual buffers).
  688.  
  689.      You can use either fg_tcmask or fg_tcdefine to define which colors are
  690. considered transparent in subsequent calls to fg_tcxfer. The fg_tcmask
  691. routine's argument is an integer bit mask (specifically, a 16-bit mask) where
  692. each bit indicates whether or not the color is transparent. For example, if
  693. bit 0 (the rightmost bit) is set in the mask, then color 0 will be
  694. transparent; if bit 0 is reset, color 0 will not be transparent. Because the
  695. bit mask size is 16 bits, only the first 16 color values may be defined as
  696. transparent using fg_tcmask.
  697.  
  698.      Example 11-8 illustrates the use of the fg_tcxfer and fg_tcmask routines.
  699. This program is similar to example 11-6, except the color of the word
  700. "quadrant" (color 9) is defined to be transparent, and fg_tcxfer is used in
  701. place of fg_transfer. Because color 9 maps to color 1 in the CGA four-color
  702. graphics mode (mode 4), we must define both colors 1 and 9 to be transparent
  703. (remember, fg_tcmask considers actual color values transparent, not color
  704. indices). The bit mask passed to fg_tcmask thus will be 0000 0010 0000 0010    
  705. 268   Fastgraph User's Guide
  706.  
  707. binary, or 0202 hex. This causes the word "quadrant" to appear in the
  708. background color (color 0) instead of color 9 in the upper right, lower left,
  709. and lower right quadrants.
  710.  
  711.                                  Example 11-8.
  712.  
  713.                  #include <fastgraf.h>
  714.                  #include <stdio.h>
  715.                  #include <stdlib.h>
  716.                  void main(void);
  717.  
  718.                  void main()
  719.                  {
  720.                     int new_mode, old_mode;
  721.  
  722.                     fg_initpm();
  723.                     new_mode = fg_bestmode(320,200,1);
  724.                     if (new_mode < 0 || new_mode == 12) {
  725.                        printf("This program requires a 320 ");
  726.                        printf("x 200 color graphics mode.\n");
  727.                        exit(1);
  728.                        }
  729.                     old_mode = fg_getmode();
  730.                     fg_setmode(new_mode);
  731.  
  732.                     fg_setcolor(7);
  733.                     fg_rect(0,159,0,99);
  734.                     fg_setcolor(9);
  735.                     fg_locate(6,6);
  736.                     fg_text("quadrant",8);
  737.                     fg_waitkey();
  738.  
  739.                     fg_tcmask(0x0202);
  740.                     fg_tcxfer(0,159,0,99,160, 99,0,0);
  741.                     fg_tcxfer(0,319,0,99,  0,199,0,0);
  742.                     fg_waitkey();
  743.  
  744.                     fg_setmode(old_mode);
  745.                     fg_reset();
  746.                  }
  747.  
  748.  
  749.      The fg_tcdefine routine expects two integer arguments -- one defining the
  750. color number (between 0 and 255) and another defining the transparency state
  751. associated with that color. If the state is zero, the specified color will be
  752. opaque (non-transparent). If it is any other value, the color will be
  753. transparent. In the previous example, we could use fg_tcdefine instead of
  754. fg_tcmask to make colors 1 and 9 transparent by replacing the call to
  755. fg_tcmask with the following:
  756.  
  757.  
  758.                                fg_tcdefine(1,1);
  759.                                fg_tcdefine(9,1);                               
  760.                                     Chapter 11:  Block Transfer Routines   269
  761.  
  762. If you don't call fg_tcmask or fg_tcdefine, the fg_tcxfer routine considers no
  763. colors transparent.
  764.  
  765.  
  766. Transparent Block Transfers for Virtual Buffers
  767.  
  768.      Fastgraph's fg_vbtcxfer routine transfers blocks with transparent colors
  769. from the active virtual buffer to the active video page. Its arguments the
  770. same as those of fg_vbpaste, but it does not copy any pixels whose colors are
  771. transparent. The fg_tcdefine or fg_tcmask routines define which colors are
  772. transparent, as when using fg_tcxfer.
  773.  
  774.      Example 11-9 achieves the same result as example 11-8, but it does so
  775. using virtual buffers. Rather than create a full-screen virtual buffer,
  776. however, this example creates a virtual buffer one-fourth the screen size and
  777. transfers the virtual buffer contents to each quadrant of the visual page in
  778. four separate operations. In the upper left quadrant, we simply call
  779. fg_vbpaste to display the virtual buffer contents. The three fg_vbtcxfer calls
  780. fill the other quadrants, but with color 9 pixels being transparent. This
  781. sequence of block copy operations from the virtual buffer creates the same
  782. resulting display as example 11-8. Note that this example uses fg_tcdefine to
  783. make color 9 transparent; we could just as well have used fg_tcmask.
  784.  
  785.                                  Example 11-9.
  786.  
  787.                  #include <fastgraf.h>
  788.                  #include <stdio.h>
  789.                  #include <stdlib.h>
  790.                  void main(void);
  791.  
  792.                  #ifdef FG32
  793.                  char buffer[16000];
  794.                  #else
  795.                  char far buffer[16000];
  796.                  #endif
  797.  
  798.                  void main()
  799.                  {
  800.                     int handle;
  801.                     int new_mode, old_mode;
  802.  
  803.                     fg_initpm();
  804.                     new_mode = fg_bestmode(320,200,1);
  805.                     if (new_mode < 0 || new_mode == 12) {
  806.                        printf("This program requires a 320 ");
  807.                        printf("x 200 color graphics mode.\n");
  808.                        exit(1);
  809.                        }
  810.                     old_mode = fg_getmode();
  811.                     fg_setmode(new_mode);
  812.  
  813.                     fg_vbinit();
  814.                     handle = fg_vbdefine(buffer,160,100);
  815.                     fg_vbopen(handle);
  816.  
  817.                     fg_setcolor(7);                                            
  818. 270   Fastgraph User's Guide
  819.  
  820.                     fg_fillpage();
  821.                     fg_setcolor(9);
  822.                     fg_locate(6,6);
  823.                     fg_text("quadrant",8);
  824.                     fg_vbpaste(0,159,0,99,0,99);
  825.                     fg_waitkey();
  826.  
  827.                     fg_tcdefine(9,1);
  828.                     fg_vbtcxfer(0,159,0,99,160,99);
  829.                     fg_vbtcxfer(0,159,0,99,0,199);
  830.                     fg_vbtcxfer(0,159,0,99,160,199);
  831.                     fg_waitkey();
  832.  
  833.                     fg_vbclose();
  834.                     fg_setmode(old_mode);
  835.                     fg_reset();
  836.                  }
  837.  
  838.  
  839.  
  840. Transferring Blocks to and from Conventional Memory
  841.  
  842.      The final two block transfer routines we'll discuss are fg_getblock and
  843. fg_putblock. The fg_getblock routine transfers a rectangular region from the
  844. active video page or virtual buffer to an array (you can use fg_imagesiz to
  845. determine the array size needed to store the block). The fg_putblock routine
  846. transfers a block previously retrieved with fg_getblock to the active page or
  847. virtual buffer. While these two routines are faster than fg_getimage and
  848. fg_putimage, they are not as fast as fg_restore, fg_save, and fg_transfer.
  849.  
  850.      Each of these routines requires five arguments. The first is the address
  851. of the array that will receive or that contains the block. The remaining four
  852. arguments define the position of the block on the active page or virtual
  853. buffer, in the order minimum x, maximum x, minimum y, and maximum y. In text
  854. modes, the coordinates are expressed as character space quantities (rows and
  855. columns). In graphics modes, they are expressed as screen space values
  856. (pixels), with the x coordinates extended to byte boundaries if required.
  857.  
  858.      Note that both fg_getblock and fg_putblock expect the array address to be
  859. passed by far reference except in BASIC. This means real mode Pascal programs
  860. must use the GetMem procedure to allocate storage for the buffer, as this is
  861. the only way to pass something by far reference in real mode Pascal. In 16-bit
  862. environments, the maximum size of a block is 64K bytes, regardless of which
  863. compiler you're using.
  864.  
  865.      Example 11-10 is similar to example 11-5 and shows fg_getblock and
  866. fg_putblock in action in a 320x200 graphics mode. The program displays the
  867. word "text" and retrieves it into a 32 by 8 pixel block. After a keystroke, it
  868. displays the block 8 pixels below and 8 pixels to the right of its original
  869. position. The size of the buffer was chosen to be 256 bytes to accommodate the
  870. largest size required for a 32 by 8 block (which occurs in the 256-color
  871. graphics modes). Note also how the source and destination horizontal block
  872. extremes were chosen for byte boundary alignment in case fg_bestmode selected
  873. a 16-color graphics mode.
  874.  
  875.                                 Example 11-10.                                 
  876.                                     Chapter 11:  Block Transfer Routines   271
  877.  
  878.  
  879.                  #include <fastgraf.h>
  880.                  #include <stdio.h>
  881.                  #include <stdlib.h>
  882.                  void main(void);
  883.  
  884.                  #ifdef FG32
  885.                  char buffer[256];
  886.                  #else
  887.                  char far buffer[256];
  888.                  #endif
  889.  
  890.                  void main()
  891.                  {
  892.                     int old_mode, new_mode;
  893.  
  894.                     fg_initpm();
  895.                     new_mode = fg_bestmode(320,200,1);
  896.                     if (new_mode < 0 || new_mode == 12) {
  897.                        printf("This program requires a 320 ");
  898.                        printf("x 200 color graphics mode.\n");
  899.                        exit(1);
  900.                        }
  901.  
  902.                     old_mode = fg_getmode();
  903.                     fg_setmode(new_mode);
  904.  
  905.                     fg_setcolor(9);
  906.                     fg_text("text",4);
  907.                     fg_getblock(buffer,0,31,0,7);
  908.                     fg_waitkey();
  909.  
  910.                     fg_putblock(buffer,8,39,8,15);
  911.                     fg_waitkey();
  912.  
  913.                     fg_setmode(old_mode);
  914.                     fg_reset();
  915.                  }
  916.  
  917.  
  918.  
  919. Summary of Block Transfer Routines
  920.  
  921.      This section summarizes the functional descriptions of the Fastgraph
  922. routines presented in this chapter. More detailed information about these
  923. routines, including their arguments and return values, may be found in the
  924. Fastgraph Reference Manual.
  925.  
  926.      For all block transfer routines, Fastgraph extends the horizontal pixel
  927. coordinates to a byte boundary when the routines are used in a graphics video
  928. mode.
  929.  
  930.      FG_COPYPAGE transfers the contents of one video page to another. The
  931. pages may be physical, virtual, or logical video pages. If both pages are
  932. logical pages, they must exist in the same type of memory. The fg_copypage
  933. routine does not work with virtual buffers.                                    
  934. 272   Fastgraph User's Guide
  935.  
  936.  
  937.      FG_GETBLOCK retrieves the block (for later display with fg_putblock) at
  938. the specified position on the active video page or virtual buffer. In text
  939. modes, the block extremes are defined in character space; in graphics modes,
  940. they are defined in screen space.
  941.  
  942.      FG_GETHPAGE returns the hidden page number, as defined in the most recent
  943. call to fg_sethpage.
  944.  
  945.      FG_PUTBLOCK displays the block (previously obtained with fg_getblock) at
  946. the specified position on the active video page or virtual buffer. In text
  947. modes, the block extremes are defined in character space; in graphics modes,
  948. they are defined in screen space.
  949.  
  950.      FG_RESTORE copies a block from the hidden video page to the same position
  951. on the active video page. The fg_restore routine does not work with virtual
  952. buffers.
  953.  
  954.      FG_RESTOREW is the same as fg_restore, but the block extremes are
  955. specified as world space coordinates. The fg_restorew routine does not work
  956. with virtual buffers.
  957.  
  958.      FG_SAVE copies a block from the active video page to the same position on
  959. the hidden video page. The fg_save routine does not work with virtual buffers.
  960.  
  961.      FG_SAVEW is the same as fg_save, but the block extremes are specified as
  962. world space coordinates. The fg_savew routine does not work with virtual
  963. buffers.
  964.  
  965.      FG_SETHPAGE defines the hidden video page (used by fg_restore,
  966. fg_restorew, fg_save, and fg_savew).
  967.  
  968.      FG_TCDEFINE defines the transparent attribute of a color index for use
  969. with the fg_tcxfer routine. This routine has no effect when used in a text
  970. video mode.
  971.  
  972.      FG_TCMASK defines which of the first 16 colors the fg_tcxfer routine will
  973. consider transparent. This routine has no effect when used in a text video
  974. mode.
  975.  
  976.      FG_TCXFER copies a block from any position on any video page to any
  977. position on any video page, excluding any pixels whose color value is
  978. transparent. This routine has no effect when used in a text video mode and
  979. does not work with virtual buffers.
  980.  
  981.      FG_TRANSFER copies a block from any position on any video page to any
  982. position on any video page. It is Fastgraph's most general block transfer
  983. routine. The fg_transfer routine does not work with virtual buffers.
  984.  
  985.      FG_VBCOPY copies a rectangular region from one virtual buffer to another,
  986. or to a non-overlapping position within the same virtual buffer.
  987.  
  988.      FG_VBTCXFER copies a rectangular region from the active virtual buffer to
  989. the active video page, excluding any transparent pixels.
  990.