home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / msc / chap_4 / black4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-30  |  46.4 KB  |  1,745 lines

  1.  
  2. // BLACK4.C - Library module
  3.  
  4. // I N C L U D E S ///////////////////////////////////////////////////////////
  5.  
  6. #include <io.h>
  7. #include <conio.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <dos.h>
  11. #include <bios.h>
  12. #include <fcntl.h>
  13. #include <memory.h>
  14. #include <malloc.h>
  15. #include <math.h>
  16. #include <string.h>
  17.  
  18. #include "black3.h"
  19. #include "black4.h"
  20.  
  21. // G L O B A L S  ////////////////////////////////////////////////////////////
  22.  
  23. // default sprite width and height
  24.  
  25. unsigned int sprite_width         = SPRITE_WIDTH;
  26.  
  27. unsigned int sprite_height        = SPRITE_HEIGHT;
  28.  
  29. unsigned char far *double_buffer  = NULL;  // the double buffer
  30.  
  31. // the default dimensions of the double buffer
  32.  
  33. unsigned int double_buffer_height = SCREEN_HEIGHT;
  34.  
  35. // size of double buffer in WORDS
  36.  
  37. unsigned int double_buffer_size   = SCREEN_WIDTH*SCREEN_HEIGHT/2;
  38.  
  39. unsigned char far *page_0_buffer  = (unsigned char far *)0xA0000000L;
  40.  
  41. unsigned char far *page_1_buffer  = (unsigned char far *)0xA0008000L;
  42.  
  43. int mode_z_page                   = PAGE_0;
  44.  
  45. // F U N C T I O N S /////////////////////////////////////////////////////////
  46.  
  47. int PCX_Init(pcx_picture_ptr image)
  48. {
  49. // this function allocates the buffer that the image data will be loaded into
  50. // when a PCX file is decompressed
  51.  
  52. if (!(image->buffer = (unsigned char far *)_fmalloc(SCREEN_WIDTH * SCREEN_HEIGHT + 1)))
  53.    {
  54.    printf("\nPCX SYSTEM - Couldn't allocate PCX image buffer");
  55.    return(0);
  56.    } // end if
  57.  
  58. // success
  59.  
  60. return(1);
  61.  
  62. } // end PCX_Init
  63.  
  64. //////////////////////////////////////////////////////////////////////////////
  65.  
  66. int PCX_Load(char *filename, pcx_picture_ptr image,int load_palette)
  67. {
  68.  
  69. // this function loads a PCX file into the image structure. The function
  70. // has three main parts: 1. load the PCX header, 2. load the image data and
  71. // decompress it and 3. load the palette data and update the VGA palette
  72. // note: the palette will only be loaded if the load_palette flag is 1
  73.  
  74. FILE *fp;                // the file pointer used to open the PCX file
  75.  
  76. int num_bytes,           // number of bytes in current RLE run
  77.     index;               // loop variable
  78.  
  79. long count;              // the total number of bytes decompressed
  80.  
  81. unsigned char data;      // the current pixel data
  82.  
  83. char far *temp_buffer;   // working buffer
  84.  
  85. // open the file, test if it exists
  86.  
  87. if ((fp = fopen(filename,"rb"))==NULL)
  88.    {
  89.    printf("\nPCX SYSTEM - Couldn't find file: %s",filename);
  90.    return(0);
  91.  
  92.    } // end if couldn't find file
  93.  
  94. // load the header
  95.  
  96. temp_buffer = (char far *)image;
  97.  
  98. for (index=0; index<128; index++)
  99.     {
  100.     temp_buffer[index] = (char)getc(fp);
  101.     } // end for index
  102.  
  103. // load the data and decompress into buffer, we need a total of 64,000 bytes
  104.  
  105. count=0;
  106.  
  107. // loop while 64,000 bytes haven't been decompressed
  108.  
  109. while(count<=SCREEN_WIDTH * SCREEN_HEIGHT)
  110.      {
  111.      // get the first piece of data
  112.  
  113.      data = (unsigned char)getc(fp);
  114.  
  115.      // is this a RLE run?
  116.  
  117.      if (data>=192 && data<=255)
  118.         {
  119.         // compute number of bytes in run
  120.  
  121.         num_bytes = data-192;
  122.  
  123.         // get the actual data for the run
  124.  
  125.         data  = (unsigned char)getc(fp);
  126.  
  127.         // replicate data in buffer num_bytes times
  128.  
  129.         while(num_bytes-->0)
  130.              {
  131.              image->buffer[count++] = data;
  132.  
  133.              } // end while
  134.  
  135.         } // end if rle
  136.      else
  137.         {
  138.         // actual data, just copy it into buffer at next location
  139.  
  140.         image->buffer[count++] = data;
  141.  
  142.         } // end else not rle
  143.  
  144.      } // end while
  145.  
  146. // load color palette
  147.  
  148. // move to end of file then back up 768 bytes i.e. to begining of palette
  149.  
  150. fseek(fp,-768L,SEEK_END);
  151.  
  152. // load the PCX pallete into the VGA color registers
  153.  
  154. for (index=0; index<256; index++)
  155.     {
  156.     // get the red component
  157.  
  158.     image->palette[index].red   = (unsigned char)(getc(fp) >> 2);
  159.  
  160.     // get the green component
  161.  
  162.     image->palette[index].green = (unsigned char)(getc(fp) >> 2);
  163.  
  164.     // get the blue component
  165.  
  166.     image->palette[index].blue  = (unsigned char)(getc(fp) >> 2);
  167.  
  168.     } // end for index
  169.  
  170. // time to close the file
  171.  
  172. fclose(fp);
  173.  
  174. // change the palette to newly loaded palette if commanded to do so
  175.  
  176. if (load_palette)
  177.    {
  178.  
  179.    // for each palette register set to the new color values
  180.  
  181.    for (index=0; index<256; index++)
  182.        {
  183.  
  184.        Write_Color_Reg(index,(RGB_color_ptr)&image->palette[index]);
  185.  
  186.        } // end for index
  187.  
  188.    } // end if load palette data into VGA
  189.  
  190. // success
  191.  
  192. return(1);
  193.  
  194. } // end PCX_Load
  195.  
  196. /////////////////////////////////////////////////////////////////////////////
  197.  
  198. void PCX_Delete(pcx_picture_ptr image)
  199. {
  200. // this function de-allocates the buffer region used for the pcx file load
  201.  
  202. _ffree(image->buffer);
  203.  
  204. } // end PCX_Delete
  205.  
  206. //////////////////////////////////////////////////////////////////////////////
  207.  
  208. void PCX_Show_Buffer(pcx_picture_ptr image)
  209. {
  210. // just copy he pcx buffer into the video buffer
  211.  
  212. char far *data; // temp variable used for aliasing
  213.  
  214. // alias image buffer
  215.  
  216. data = image->buffer;
  217.  
  218. // use inline assembly for speed
  219.  
  220. _asm
  221.    {
  222.    push ds               ; save the data segment
  223.    les di, video_buffer  ; point es:di to video buffer
  224.    lds si, data          ; point ds:si to data area
  225.    mov cx,320*200/2      ; move 32000 words
  226.    cld                   ; set direction to foward
  227.    rep movsw             ; do the string operation
  228.    pop ds                ; restore the data segment
  229.    }  // end inline
  230.  
  231. } // end PCX_Show_Buffer
  232.  
  233. ///////////////////////////////////////////////////////////////////////////////
  234.  
  235. void PCX_Copy_To_Buffer(pcx_picture_ptr image,unsigned char far *buffer)
  236. {
  237. // this function is used to copy the data in the PCX buffer to another buffer
  238. // usually the double buffer
  239.  
  240. // use the word copy function, note: double_buffer_size is in WORDS
  241.  
  242. fwordcpy((void far *)buffer,(void far *)image->buffer,double_buffer_size);
  243.  
  244. } // end PCX_Copy_To_Buffer
  245.  
  246. //////////////////////////////////////////////////////////////////////////////
  247.  
  248. void PCX_Get_Sprite(pcx_picture_ptr image,
  249.                      sprite_ptr sprite,
  250.                      int sprite_frame,
  251.                      int cell_x, int cell_y)
  252.  
  253. {
  254. // this function is used to load the images for a sprite into the sprite
  255. // frames array. It functions by using the size of the sprite and the
  256. // position of the requested cell to compute the proper location in the
  257. // pcx image buffer to extract the data from.
  258.  
  259. int x_off,  // position of sprite cell in PCX image buffer
  260.     y_off,
  261.     y,      // looping variable
  262.     width,  // size of sprite
  263.     height;
  264.  
  265. unsigned char far *sprite_data;
  266.  
  267. // extract width and height of sprite
  268.  
  269. width  = sprite->width;
  270. height = sprite->height;
  271.  
  272. // first allocate the memory for the sprite in the sprite structure
  273.  
  274. sprite->frames[sprite_frame] = (unsigned char far *)_fmalloc(width * height + 1);
  275.  
  276. // create an alias to the sprite frame for ease of access
  277.  
  278. sprite_data = sprite->frames[sprite_frame];
  279.  
  280. // now load the sprite data into the sprite frame array from the pcx picture
  281.  
  282. x_off = (width+1)  * cell_x + 1;
  283. y_off = (height+1) * cell_y + 1;
  284.  
  285. // compute starting y address
  286.  
  287. y_off = y_off * 320; // 320 bytes per line
  288.  
  289. // scan the data row by row
  290.  
  291. for (y=0; y<height; y++,y_off+=320)
  292.     {
  293.     // copy the row of pixels
  294.  
  295.     _fmemcpy((void far *)&sprite_data[y*width],
  296.  
  297.              (void far *)&(image->buffer[y_off + x_off]),
  298.              width);
  299.  
  300.     } // end for y
  301.  
  302. // increment number of frames
  303.  
  304. sprite->num_frames++;
  305.  
  306. // done!, let's bail!
  307.  
  308. } // end PCX_Get_Sprite
  309.  
  310. //////////////////////////////////////////////////////////////////////////////
  311.  
  312. void Sprite_Init(sprite_ptr sprite,int x,int y,int width,int height,
  313.                                    int c1,int c2,int c3,
  314.                                    int t1,int t2,int t3)
  315. {
  316. // this function initializes a sprite
  317.  
  318. int index;
  319.  
  320. sprite->x            = x;
  321. sprite->y            = y;
  322. sprite->width        = width;
  323. sprite->height       = height;
  324. sprite->visible      = 1;
  325. sprite->counter_1    = c1;
  326. sprite->counter_2    = c2;
  327. sprite->counter_3    = c3;
  328. sprite->threshold_1  = t1;
  329. sprite->threshold_2  = t2;
  330. sprite->threshold_3  = t3;
  331. sprite->curr_frame   = 0;
  332. sprite->state        = SPRITE_DEAD;
  333. sprite->num_frames   = 0;
  334. sprite->background   = (unsigned char far *)_fmalloc(width * height+1);
  335.  
  336. // set all bitmap pointers to null
  337.  
  338. for (index=0; index<MAX_SPRITE_FRAMES; index++)
  339.     sprite->frames[index] = NULL;
  340.  
  341. } // end Sprite_Init
  342.  
  343. //////////////////////////////////////////////////////////////////////////////
  344.  
  345. void Sprite_Delete(sprite_ptr sprite)
  346. {
  347. // this function deletes all the memory associated with a sprite
  348.  
  349. int index;
  350.  
  351. _ffree(sprite->background);
  352.  
  353. // now de-allocate all the animation frames
  354.  
  355. for (index=0; index<MAX_SPRITE_FRAMES; index++)
  356.     _ffree(sprite->frames[index]);
  357.  
  358. } // end Sprite_Delete
  359.  
  360. ////////////////////////////////////////////////////////////////////////////////
  361.  
  362. void Sprite_Under(sprite_ptr sprite, unsigned char far *buffer)
  363. {
  364.  
  365. // this function scans the background under a sprite so that when the sprite
  366. // is drawn the background isn't obliterated
  367.  
  368. unsigned char far *back_buffer; // background buffer for sprite
  369.  
  370. int y,                          // current line being scanned
  371.     width,                      // size of sprite
  372.     height;
  373.  
  374. // alias a pointer to sprite background for ease of access
  375.  
  376. back_buffer = sprite->background;
  377.  
  378. // alias width and height
  379.  
  380. width  = sprite->width;
  381. height = sprite->height;
  382.  
  383. // compute offset of background in source buffer
  384.  
  385. buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  386.  
  387. for (y=0; y<height; y++)
  388.     {
  389.     // copy the next row out off image buffer into sprite background buffer
  390.  
  391.     _fmemcpy((void far *)back_buffer,
  392.              (void far *)buffer,
  393.              width);
  394.  
  395.     // move to next line in source buffer and in sprite background buffer
  396.  
  397.     buffer      += SCREEN_WIDTH;
  398.     back_buffer += width;
  399.  
  400.     } // end for y
  401.  
  402. } // end Sprite_Under
  403.  
  404. //////////////////////////////////////////////////////////////////////////////
  405.  
  406. void Sprite_Erase(sprite_ptr sprite,unsigned char far *buffer)
  407. {
  408. // replace the background that was behind the sprite
  409. // this function replaces the background that was saved from where a sprite
  410. // was going to be placed
  411.  
  412. unsigned char far *back_buffer; // background buffer for sprite
  413.  
  414. int y,                          // current line being scanned
  415.     width,                      // size of sprite
  416.     height;
  417.  
  418. // alias a pointer to sprite background for ease of access
  419.  
  420. back_buffer = sprite->background;
  421.  
  422. // alias width and height
  423.  
  424. width  = sprite->width;
  425. height = sprite->height;
  426.  
  427. // compute offset in destination buffer
  428.  
  429. buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  430.  
  431. for (y=0; y<height; y++)
  432.     {
  433.     // copy the next from sprite background buffer to destination buffer
  434.  
  435.     _fmemcpy((void far *)buffer,
  436.              (void far *)back_buffer,
  437.              width);
  438.  
  439.     // move to next line in destination buffer and in sprite background buffer
  440.  
  441.     buffer      += SCREEN_WIDTH;
  442.     back_buffer += width;
  443.  
  444.     } // end for y
  445.  
  446. } // end Sprite_Erase
  447.  
  448. //////////////////////////////////////////////////////////////////////////////
  449.  
  450. void Sprite_Draw(sprite_ptr sprite, unsigned char far *buffer,int transparent)
  451. {
  452.  
  453. // this function draws a sprite on the screen row by row very quickly
  454. // note the use of shifting to implement multplication
  455. // if the transparent flag is true then pixels wil be draw one by one
  456. // else a memcpy will be used to draw each line
  457.  
  458. unsigned char far *sprite_data; // pointer to sprite data
  459. unsigned char far *dest_buffer; // pointer to destination buffer
  460.  
  461. int x,y,                        // looping variables
  462.     width,                      // width of sprite
  463.     height;                     // height of sprite
  464.  
  465. unsigned char pixel;            // the current pixel being processed
  466.  
  467. // alias a pointer to sprite for ease of access
  468.  
  469. sprite_data = sprite->frames[sprite->curr_frame];
  470.  
  471. // alias a variable to sprite size
  472.  
  473. width  = sprite->width;
  474. height = sprite->height;
  475.  
  476. // compute number of bytes between adjacent video lines after a row of pixels
  477. // has been drawn
  478.  
  479. // compute offset of sprite in destination buffer
  480.  
  481. dest_buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  482.  
  483. // copy each line of the sprite data into destination buffer
  484.  
  485.  
  486. if (transparent)
  487.    {
  488.    for (y=0; y<height; y++)
  489.        {
  490.        // copy the next row into the destination buffer
  491.  
  492.        for (x=0; x<width; x++)
  493.            {
  494.  
  495.            // test for transparent pixel i.e. 0, if not transparent then draw
  496.  
  497.            if ((pixel=sprite_data[x]))
  498.                 dest_buffer[x] = pixel;
  499.  
  500.            } // end for x
  501.  
  502.        // move to next line in desintation buffer and sprite image buffer
  503.  
  504.        dest_buffer += SCREEN_WIDTH;
  505.        sprite_data += width;
  506.  
  507.        } // end for y
  508.  
  509.    } // end if transparent
  510. else
  511.    {
  512.    // draw sprite with transparency off
  513.  
  514.    for (y=0; y<height; y++)
  515.        {
  516.        // copy the next row into the destination buffer
  517.  
  518.        _fmemcpy((void far *)dest_buffer,(void far *)sprite_data,width);
  519.  
  520.        // move to next line in desintation buffer and sprite image buffer
  521.  
  522.        dest_buffer += SCREEN_WIDTH;
  523.        sprite_data += width;
  524.  
  525.        } // end for y
  526.  
  527.    } // end else
  528.  
  529. } // end Sprite_Draw
  530.  
  531.  
  532. ////////////////////////////////////////////////////////////////////////////////
  533.  
  534. void Sprite_Under_Clip(sprite_ptr sprite, unsigned char far *buffer)
  535. {
  536.  
  537. // this function scans the background under a sprite, but only those
  538. // portions that are visible
  539.  
  540. unsigned char far *back_buffer;   // pointer to sprite background buffer
  541. unsigned char far *source_buffer; // pointer to source buffer
  542.  
  543. int x,y,                        // looping variables
  544.     sx,sy,                      // position of sprite
  545.     width,                      // width of sprite
  546.     bitmap_width  =0,           // width and height of sub-bitmap
  547.     bitmap_height =0;
  548.  
  549. unsigned char pixel;            // the current pixel being processed
  550.  
  551. // alias a variable to sprite size
  552.  
  553. width         = sprite->width;
  554. bitmap_width  = width;
  555. bitmap_height = sprite->height;
  556. sx            = sprite->x;
  557. sy            = sprite->y;
  558.  
  559. // perform trivial rejection tests
  560.  
  561. if (sx >= (int)SCREEN_WIDTH || sy >= (int)double_buffer_height ||
  562.    (sx+width) <= 0          || (sy+bitmap_height) <= 0)
  563.    {
  564.    // sprite is totally invisible therefore don't scan
  565.  
  566.    // set invisible flag in strucuture so that the draw sub-function
  567.    // doesn't do anything
  568.  
  569.    sprite->visible = 0;
  570.  
  571.    return;
  572.  
  573.    } // end if invisible
  574.  
  575. // the sprite background region must be clipped before scanning
  576. // therefore compute visible portion
  577.  
  578. // first compute upper left hand corner of clipped sprite background
  579.  
  580. if (sx<0)
  581.    {
  582.  
  583.    bitmap_width += sx;
  584.    sx            = 0;
  585.  
  586.  
  587.    } // end off left edge
  588. else
  589. if (sx+width>=(int)SCREEN_WIDTH)
  590.    {
  591.  
  592.    bitmap_width  = (int)SCREEN_WIDTH-sx;
  593.  
  594.    } // end off right edge
  595.  
  596. // now process y
  597.  
  598. if (sy<0)
  599.    {
  600.  
  601.    bitmap_height += sy;
  602.    sy             = 0;
  603.  
  604.    } // end off top edge
  605. else
  606. if (sy+bitmap_height>=(int)double_buffer_height)
  607.    {
  608.  
  609.    bitmap_height  = (int)double_buffer_height - sy;
  610.  
  611.    } // end off lower edge
  612.  
  613. // this point we know were to start scanning the bitmap i.e.
  614. // sx,sy
  615. // and we know the size of the bitmap to be scanned i.e.
  616. // width,height, so plug it all into the rest of function
  617.  
  618. // compute number of bytes between adjacent video lines after a row of pixels
  619. // has been drawn
  620.  
  621. // compute offset of sprite background in source buffer
  622.  
  623. source_buffer = buffer + (sy << 8) + (sy << 6) + sx;
  624.  
  625. // alias a pointer to sprite background
  626.  
  627. back_buffer = sprite->background;
  628.  
  629. for (y=0; y<bitmap_height; y++)
  630.     {
  631.     // copy the next row into the destination buffer
  632.  
  633.     _fmemcpy((void far *)back_buffer,(void far *)source_buffer,bitmap_width);
  634.  
  635.     // move to next line in desintation buffer and sprite image buffer
  636.  
  637.     source_buffer += SCREEN_WIDTH;
  638.     back_buffer   += width;  // note this width is the actual width of the
  639.                              // entire bitmap NOT the visible portion
  640.     } // end for y
  641.  
  642. // set variables in strucuture so that the erase sub-function can operate
  643. // faster
  644.  
  645. sprite->x_clip      = sx;
  646. sprite->y_clip      = sy;
  647. sprite->width_clip  = bitmap_width;
  648. sprite->height_clip = bitmap_height;
  649. sprite->visible     = 1;
  650.  
  651. } // end Sprite_Under_Clip
  652.  
  653. //////////////////////////////////////////////////////////////////////////////
  654.  
  655. void Sprite_Erase_Clip(sprite_ptr sprite,unsigned char far *buffer)
  656. {
  657. // replace the background that was behind the sprite
  658. // this function replaces the background that was saved from where a sprite
  659. // was going to be placed
  660.  
  661. unsigned char far *back_buffer; // background buffer for sprite
  662.  
  663. int y,                          // current line being scanned
  664.     width,                      // size of sprite background buffer
  665.     bitmap_height,              // size of clipped bitmap
  666.     bitmap_width;
  667.  
  668. // make sure sprite was visible
  669.  
  670. if (!sprite->visible)
  671.    return;
  672.  
  673. // alias a pointer to sprite background for ease of access
  674.  
  675. back_buffer = sprite->background;
  676.  
  677. // alias width and height
  678.  
  679. bitmap_width  = sprite->width_clip;
  680. bitmap_height = sprite->height_clip;
  681. width         = sprite->width;
  682.  
  683. // compute offset in destination buffer
  684.  
  685. buffer = buffer + (sprite->y_clip << 8) + (sprite->y_clip << 6)
  686.                 + sprite->x_clip;
  687.  
  688. for (y=0; y<bitmap_height; y++)
  689.     {
  690.     // copy the next row from sprite background buffer to destination buffer
  691.  
  692.     _fmemcpy((void far *)buffer,
  693.              (void far *)back_buffer,
  694.              bitmap_width);
  695.  
  696.     // move to next line in destination buffer and in sprite background buffer
  697.  
  698.     buffer      += SCREEN_WIDTH;
  699.     back_buffer += width;
  700.  
  701.     } // end for y
  702.  
  703. } // end Sprite_Erase_Clip
  704.  
  705. //////////////////////////////////////////////////////////////////////////////
  706.  
  707. void Sprite_Draw_Clip(sprite_ptr sprite, unsigned char far *buffer,int transparent)
  708. {
  709.  
  710. // this function draws a sprite on the screen row by row very quickly
  711. // note the use of shifting to implement multplication
  712. // if the transparent flag is true then pixels wil be draw one by one
  713. // else a memcpy will be used to draw each line
  714. // this function also performs clipping. It will test if the sprite
  715. // is totally visible/invisible and will only draw the portions that are visible
  716.  
  717. unsigned char far *sprite_data; // pointer to sprite data
  718. unsigned char far *dest_buffer; // pointer to destination buffer
  719.  
  720. int x,y,                        // looping variables
  721.     sx,sy,                      // position of sprite
  722.     width,                      // width of sprite
  723.     bitmap_x      =0,           // starting upper left corner of sub-bitmap
  724.     bitmap_y      =0,           // to be drawn after clipping
  725.     bitmap_width  =0,           // width and height of sub-bitmap
  726.     bitmap_height =0;
  727.  
  728. unsigned char pixel;            // the current pixel being processed
  729.  
  730. // alias a variable to sprite size
  731.  
  732. width         = sprite->width;
  733. bitmap_width  = width;
  734. bitmap_height = sprite->height;
  735. sx            = sprite->x;
  736. sy            = sprite->y;
  737.  
  738. // perform trivial rejection tests
  739.  
  740. if (sx >= (int)SCREEN_WIDTH || sy >= (int)double_buffer_height ||
  741.    (sx+width) <= 0          || (sy+bitmap_height) <= 0 || !sprite->visible)
  742.    {
  743.    // sprite is totally invisible therefore don't draw
  744.  
  745.    // set invisible flag in strucuture so that the erase sub-function
  746.    // doesn't do anything
  747.  
  748.    sprite->visible = 0;
  749.  
  750.    return;
  751.  
  752.    } // end if invisible
  753.  
  754. // the sprite needs some clipping or no clipping at all, so compute
  755. // visible portion of sprite rectangle
  756.  
  757. // first compute upper left hand corner of clipped sprite
  758.  
  759. if (sx<0)
  760.    {
  761.  
  762.    bitmap_x      = -sx;
  763.    sx            = 0;
  764.    bitmap_width -= bitmap_x;
  765.  
  766.    } // end off left edge
  767. else
  768. if (sx+width>=(int)SCREEN_WIDTH)
  769.    {
  770.  
  771.    bitmap_x      = 0;
  772.    bitmap_width  = (int)SCREEN_WIDTH-sx;
  773.  
  774.    } // end off right edge
  775.  
  776. // now process y
  777.  
  778. if (sy<0)
  779.    {
  780.  
  781.    bitmap_y       = -sy;
  782.    sy             = 0;
  783.    bitmap_height -= bitmap_y;
  784.  
  785.    } // end off top edge
  786. else
  787. if (sy+bitmap_height>=(int)double_buffer_height)
  788.    {
  789.  
  790.    bitmap_y       = 0;
  791.    bitmap_height  = (int)double_buffer_height - sy;
  792.  
  793.    } // end off lower edge
  794.  
  795. // this point we know were to start drawing the bitmap i.e.
  796. // sx,sy
  797. // and we know were in the data to extract the bitmap i.e.
  798. // bitmap_x, bitmap_y,
  799. // and finaly we know the size of the bitmap to be drawn i.e.
  800. // width,height, so plug it all into the rest of function
  801.  
  802. // compute number of bytes between adjacent video lines after a row of pixels
  803. // has been drawn
  804.  
  805. // compute offset of sprite in destination buffer
  806.  
  807. dest_buffer = buffer + (sy << 8) + (sy << 6) + sx;
  808.  
  809. // alias a pointer to sprite for ease of access and locate starting sub
  810. // bitmap that will be drawn
  811.  
  812. sprite_data = sprite->frames[sprite->curr_frame] + (bitmap_y*width) + bitmap_x;
  813.  
  814. // copy each line of the sprite data into destination buffer
  815.  
  816. if (transparent)
  817.    {
  818.    for (y=0; y<bitmap_height; y++)
  819.        {
  820.        // copy the next row into the destination buffer
  821.  
  822.        for (x=0; x<bitmap_width; x++)
  823.            {
  824.  
  825.            // test for transparent pixel i.e. 0, if not transparent then draw
  826.  
  827.            if ((pixel=sprite_data[x]))
  828.                 dest_buffer[x] = pixel;
  829.  
  830.            } // end for x
  831.  
  832.        // move to next line in desintation buffer and sprite image buffer
  833.  
  834.        dest_buffer += SCREEN_WIDTH;
  835.        sprite_data += width;   // note this width is the actual width of the
  836.                                // entire bitmap NOT the visible portion
  837.        } // end for y
  838.  
  839.    } // end if transparent
  840. else
  841.    {
  842.    // draw sprite with transparency off
  843.  
  844.    for (y=0; y<bitmap_height; y++)
  845.        {
  846.        // copy the next row into the destination buffer
  847.  
  848.        _fmemcpy((void far *)dest_buffer,(void far *)sprite_data,bitmap_width);
  849.  
  850.        // move to next line in desintation buffer and sprite image buffer
  851.  
  852.        dest_buffer += SCREEN_WIDTH;
  853.        sprite_data += width;  // note this width is the actual width of the
  854.                               // entire bitmap NOT the visible portion
  855.        } // end for y
  856.  
  857.    } // end else
  858.  
  859. // set variables in strucuture so that the erase sub-function can operate
  860. // faster
  861.  
  862. sprite->x_clip      = sx;
  863. sprite->y_clip      = sy;
  864. sprite->width_clip  = bitmap_width;
  865. sprite->height_clip = bitmap_height;
  866. sprite->visible     = 1;
  867.  
  868. } // end Sprite_Draw_Clip
  869.  
  870.  
  871. //////////////////////////////////////////////////////////////////////////////
  872.  
  873. int Sprites_Collide(sprite_ptr sprite_1, sprite_ptr sprite_2)
  874. {
  875. // this function tests if two sprites have intersected by testing their
  876. // bounding boxes for collision
  877.  
  878. return(0);
  879.  
  880. } // end Sprites_Collide
  881.  
  882. ///////////////////////////////////////////////////////////////////////////////
  883.  
  884. void Display_Double_Buffer(unsigned char far *buffer,int y)
  885. {
  886. // this functions copies the double buffer into the video buffer at the
  887. // starting y location
  888.  
  889. _asm
  890.    {
  891.    push ds                     ; save DS on stack
  892.    mov cx,double_buffer_size   ; this is the size of buffer in WORDS
  893.    les di,video_buffer         ; es:di is destination of memory move
  894.  
  895.    mov ax,320                  ; multiply y by 320 i.e. screen width
  896.    mul y
  897.    add di,ax                   ; add result to es:di
  898.  
  899.    lds si,buffer               ; ds:si is source of memory move
  900.    rep movsw                   ; move all the words
  901.    pop ds                      ; restore the data segment
  902.    } // end asm
  903.  
  904. } // end Display_Double_Buffer
  905.  
  906. //////////////////////////////////////////////////////////////////////////////
  907.  
  908. int Create_Double_Buffer(int num_lines)
  909. {
  910.  
  911. // allocate enough memory to hold the double buffer
  912.  
  913. if ((double_buffer = (unsigned char far *)_fmalloc(SCREEN_WIDTH * (num_lines + 1)))==NULL)
  914.    {
  915.    printf("\nCouldn't allocate double buffer.");
  916.    return(0);
  917.    } // end if couldn't allocate
  918.  
  919. // set the height of the buffer and compute it's size
  920.  
  921. double_buffer_height = num_lines;
  922.  
  923. double_buffer_size = SCREEN_WIDTH * num_lines/2;
  924.  
  925. // fill the buffer with black
  926.  
  927. _fmemset(double_buffer, 0, SCREEN_WIDTH * num_lines);
  928.  
  929. // everything was ok
  930.  
  931. return(1);
  932.  
  933. } // end Init_Double_Buffer
  934.  
  935. ///////////////////////////////////////////////////////////////////////////////
  936.  
  937. void Fill_Double_Buffer(int color)
  938. {
  939. // this function fills in the double buffer with the sent color a WORD at
  940. // a time
  941.  
  942. _asm
  943.    {
  944.    mov cx,double_buffer_size ; this is the size of buffer in WORDS
  945.    mov al, BYTE PTR color    ; move the color into al
  946.    mov ah,al                 ; move the color in ah
  947.    les di,double_buffer      ; es:di points to the double buffer
  948.    rep stosw                 ; fill all the words
  949.    } // end asm
  950.  
  951. } // end Fill_Double_Buffer
  952.  
  953. //////////////////////////////////////////////////////////////////////////////
  954.  
  955. void Delete_Double_Buffer(void)
  956. {
  957. // this function free's up the memory allocated by the double buffer
  958. // make sure to use FAR version
  959.  
  960. if (double_buffer)
  961.   _ffree(double_buffer);
  962.  
  963. } // end Delete_Double_Buffer
  964.  
  965. ///////////////////////////////////////////////////////////////////////////////
  966.  
  967. void Screen_Transition(int effect)
  968. {
  969. // this function can be called to perform a myraid of screen transitions
  970. // to the video buffer, note I have left one for you to create!
  971.  
  972. int pal_reg;       //  used as loop counter
  973. long index;        // used as loop counter
  974. RGB_color color;   // temporary color
  975.  
  976. // test which screen effect is being selected
  977.  
  978. switch(effect)
  979.       {
  980.  
  981.       case SCREEN_DARKNESS:
  982.            {
  983.            // fade to black
  984.  
  985.            for (index=0; index<20; index++)
  986.                {
  987.                // loop thru all palette registers
  988.  
  989.                for (pal_reg=1; pal_reg<255; pal_reg++)
  990.                    {
  991.                    // get the next color to fade
  992.  
  993.                    Read_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  994.  
  995.                    // test if this color regisyer is already black
  996.  
  997.                    if (color.red > 4) color.red-=3;
  998.                    else
  999.                       color.red = 0;
  1000.  
  1001.                    if (color.green > 4) color.green-=3;
  1002.                    else
  1003.                       color.green = 0;
  1004.  
  1005.                    if (color.blue  > 4) color.blue-=3;
  1006.                    else
  1007.                       color.blue = 0;
  1008.  
  1009.                    // set the color to a diminished intensity
  1010.  
  1011.                    Write_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  1012.  
  1013.                    } // end for pal_reg
  1014.  
  1015.                // wait a bit
  1016.  
  1017.                Time_Delay(1);
  1018.  
  1019.                } // end for index
  1020.  
  1021.            } break;
  1022.  
  1023.       case SCREEN_WHITENESS:
  1024.            {
  1025.            // fade to white
  1026.  
  1027.            for (index=0; index<20; index++)
  1028.                {
  1029.  
  1030.                // loop thru all palette registers
  1031.  
  1032.                for (pal_reg=0; pal_reg<255; pal_reg++)
  1033.                    {
  1034.                    // get the color to fade
  1035.  
  1036.                    Read_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  1037.  
  1038.                    color.red+=4;
  1039.  
  1040.                    if (color.red > 63)
  1041.                       color.red = 63;
  1042.  
  1043.                    color.green+=4;
  1044.  
  1045.                    if (color.green > 63)
  1046.                       color.green = 63;
  1047.  
  1048.                    color.blue+=4;
  1049.  
  1050.                    if (color.blue >63)
  1051.                       color.blue = 63;
  1052.  
  1053.                    // set the color to a brightend intensity
  1054.  
  1055.                    Write_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  1056.  
  1057.                    } // end for pal_reg
  1058.  
  1059.                // wait a bit
  1060.  
  1061.                Time_Delay(1);
  1062.  
  1063.                } // end for index
  1064.  
  1065.            } break;
  1066.  
  1067.  
  1068.       case SCREEN_WARP:
  1069.            {
  1070.  
  1071.            // this one you do!!!!
  1072.  
  1073.            } break;
  1074.  
  1075.       case SCREEN_SWIPE_X:
  1076.            {
  1077.            // do a screen wipe from right to left, left to right
  1078.  
  1079.            for (index=0; index<160; index+=2)
  1080.                {
  1081.  
  1082.                // use this as a 1/70th of second time delay
  1083.  
  1084.                Wait_For_Vertical_Retrace();
  1085.  
  1086.                // draw two vertical lines at opposite ends of the screen
  1087.  
  1088.                Line_V(0,199,319-index,0);
  1089.                Line_V(0,199,index,0);
  1090.                Line_V(0,199,319-(index+1),0);
  1091.                Line_V(0,199,index+1,0);
  1092.  
  1093.                } // end for index
  1094.  
  1095.            } break;
  1096.  
  1097.       case SCREEN_SWIPE_Y:
  1098.            {
  1099.  
  1100.            // do a screen wipe from top to bottom, bottom to top
  1101.  
  1102.            for (index=0; index<100; index+=2)
  1103.                {
  1104.  
  1105.                // use this as a 1/70th of second time delay
  1106.  
  1107.                Wait_For_Vertical_Retrace();
  1108.  
  1109.                // draw two horizontal lines at opposite ends of the screen
  1110.  
  1111.                Line_H(0,319,199-index,0);
  1112.                Line_H(0,319,index,0);
  1113.                Line_H(0,319,199-(index+1),0);
  1114.                Line_H(0,319,index+1,0);
  1115.  
  1116.                } // end for index
  1117.  
  1118.            } break;
  1119.  
  1120.  
  1121.       case SCREEN_DISOLVE:
  1122.            {
  1123.            // disolve the screen by plotting zillions of little black dots
  1124.  
  1125.            for (index=0; index<=300000; index++)
  1126.                 Write_Pixel(rand()%320,rand()%200, 0);
  1127.  
  1128.            } break;
  1129.  
  1130.       default:break;
  1131.  
  1132.       } // end switch
  1133.  
  1134. } // end Screen_Transition
  1135.  
  1136. //////////////////////////////////////////////////////////////////////////////////
  1137.  
  1138. void Wait_For_Vertical_Retrace(void)
  1139. {
  1140. // this function waits for the start of a vertical retrace, if a vertical
  1141. // retrace is in progress then it waits until the next one
  1142. // therefore the function can wait a maximum of 2/70 th's of a second
  1143. // before returning
  1144. // this function can be used to synchronize video updates to the vertical blank
  1145. // or as a high resolution time reference
  1146.  
  1147. while(_inp(VGA_INPUT_STATUS_1) & VGA_VRETRACE_MASK)
  1148.      {
  1149.      // do nothing, vga is already in retrace
  1150.      } // end while
  1151.  
  1152. // now wait for start of vertical retrace and exit
  1153.  
  1154. while(!(_inp(VGA_INPUT_STATUS_1) & VGA_VRETRACE_MASK))
  1155.      {
  1156.      // do nothing, wait for start of retrace
  1157.      } // end while
  1158.  
  1159. // at this point a vertical retrace is occuring, so return back to caller
  1160.  
  1161. } // end Wait_For_Vertical_Retrace
  1162.  
  1163. ///////////////////////////////////////////////////////////////////////////////
  1164.  
  1165. void fwordcpy(void far *destination, void far *source,int num_words)
  1166. {
  1167. // this function is similar to fmemcpy except that is moves data in words
  1168. // it is about 25% faster than memcpy which uses bytes
  1169.  
  1170. _asm
  1171.    {
  1172.    push ds              ; need to save segment registers i.e. ds
  1173.    les di,destination   ; point es:di to destination of memory move
  1174.    lds si,source        ; point ds:si to source of memory move
  1175.    mov cx,num_words     ; move into cx the number of words to be moved
  1176.    rep movsw            ; let the processor do the memory move
  1177.    pop ds               ; restore the ds segment register
  1178.  
  1179.    } // end inline asm
  1180.  
  1181. } // end fwordcpy
  1182.  
  1183. //////////////////////////////////////////////////////////////////////////////
  1184.  
  1185. void Bitmap_Put(bitmap_ptr image, unsigned char far *destination,int transparent)
  1186. {
  1187. // this fucntion will draw a bitmap on the destination buffer which could
  1188. // be a double buffer or the video buffer
  1189.  
  1190. int x,y,                        // looping variables
  1191.     width,height;               // size of bitmap
  1192.  
  1193. unsigned char far *bitmap_data; // pointer to bitmap buffer
  1194. unsigned char far *dest_buffer; // pointer to destination buffer
  1195.  
  1196. unsigned char pixel;            // current pixel value being processed
  1197.  
  1198. // compute offset of bitmap in destination buffer. note: all video or double
  1199. // buffers must be 320 bytes wide!
  1200.  
  1201. dest_buffer = destination + (image->y << 8) + (image->y << 6) + image->x;
  1202.  
  1203. // create aliases to variables so the strucuture doesn't need to be
  1204. // dereferenced continually
  1205.  
  1206. height      = image->height;
  1207. width       = image->width;
  1208. bitmap_data = image->buffer;
  1209.  
  1210. // test if transparency is on or off
  1211.  
  1212. if (transparent)
  1213.    {
  1214.    // use version that will draw a transparent bitmap(slighlty slower)
  1215.  
  1216.    // draw each line of the bitmap
  1217.  
  1218.    for (y=0; y<height; y++)
  1219.        {
  1220.        // copy the next row into the destination buffer
  1221.  
  1222.        for (x=0; x<width; x++)
  1223.            {
  1224.  
  1225.            // test for transparent pixel i.e. 0, if not transparent then draw
  1226.  
  1227.            if ((pixel=bitmap_data[x]))
  1228.                 dest_buffer[x] = pixel;
  1229.  
  1230.            } // end for x
  1231.  
  1232.        // move to next line in double buffer and in bitmap buffer
  1233.  
  1234.        dest_buffer += SCREEN_WIDTH;
  1235.        bitmap_data += width;
  1236.  
  1237.        } // end for y
  1238.  
  1239.    } // end if transparent
  1240. else
  1241.    {
  1242.  
  1243.    // draw each line of the bitmap, note how each pixel doesn't need to be
  1244.    // tested for transparency hence a memcpy can be used (very fast!)
  1245.  
  1246.    for (y=0; y<height; y++)
  1247.        {
  1248.        // copy the next row into the destination buffer using memcpy for speed
  1249.  
  1250.        _fmemcpy((void far *)dest_buffer,
  1251.                 (void far *)bitmap_data,width);
  1252.  
  1253.        // move to next line in destination buffer and in bitmap buffer
  1254.  
  1255.        dest_buffer += SCREEN_WIDTH;
  1256.        bitmap_data += width;
  1257.  
  1258.        } // end for y
  1259.  
  1260.    } // end else non-transparent version
  1261.  
  1262. } // end Bitmap_Put
  1263.  
  1264. //////////////////////////////////////////////////////////////////////////////
  1265.  
  1266. void Bitmap_Get(bitmap_ptr image, unsigned char far *source)
  1267. {
  1268. // this function will scan a bitmap fomr the source buffer
  1269. // could be a double buffer, video buffer or any other buffer with a
  1270. // logical row width of 320 bytes
  1271.  
  1272. unsigned int source_off,       // offsets into destination and source buffers
  1273.              bitmap_off;
  1274.  
  1275. int y,                         // looping variable
  1276.     width,height;              // size of bitmap
  1277.  
  1278. unsigned char far *bitmap_data; // pointer to bitmap buffer
  1279.  
  1280.  
  1281. // compute offset of bitmap in source buffer. note: all video or double
  1282. // buffers must be 320 bytes wide!
  1283.  
  1284. source_off   = (image->y << 8) + (image->y << 6) + image->x;
  1285.  
  1286. bitmap_off = 0;
  1287.  
  1288. // create aliases to variables so the strucuture doesn't need to be
  1289. // dereferenced continually
  1290.  
  1291. height      = image->height;
  1292. width       = image->width;
  1293. bitmap_data = image->buffer;
  1294.  
  1295. // draw each line of the bitmap, note how each pixel doesn't need to be
  1296. // tested for transparency hence a memcpy can be used (very fast!)
  1297.  
  1298. for (y=0; y<height; y++)
  1299.     {
  1300.     // copy the next row into the bitmap buffer using memcpy for speed
  1301.  
  1302.     _fmemcpy((void far *)&bitmap_data[bitmap_off],
  1303.              (void far *)&source[source_off],width);
  1304.  
  1305.     // move to next line in source buffer and in bitmap buffer
  1306.  
  1307.     source_off += SCREEN_WIDTH;
  1308.     bitmap_off += width;
  1309.  
  1310.     } // end for y
  1311.  
  1312. } // end Bitmap_Get
  1313.  
  1314. //////////////////////////////////////////////////////////////////////////////
  1315.  
  1316. int Bitmap_Allocate(bitmap_ptr image, int width, int height)
  1317. {
  1318. // this function can be used to allocate the memory needed for a bitmap
  1319.  
  1320. if ((image->buffer = (unsigned char far *)_fmalloc(width*height+1))==NULL)
  1321.    return(0);
  1322. else
  1323.    return(1);
  1324.  
  1325. } // end Bitmap_Allocate
  1326.  
  1327. //////////////////////////////////////////////////////////////////////////////
  1328.  
  1329. void Bitmap_Delete(bitmap_ptr the_bitmap)
  1330. {
  1331. // this function deletes the memory used by a bitmap
  1332.  
  1333. if (the_bitmap->buffer)
  1334.    _ffree(the_bitmap->buffer);
  1335.  
  1336. } // end Bitmap_Delete
  1337.  
  1338. //////////////////////////////////////////////////////////////////////////////
  1339.  
  1340. void Layer_Draw(layer_ptr source_layer, int source_x, int source_y,
  1341.                 unsigned char far *dest_buffer,int dest_y,int dest_height,
  1342.                 int transparent)
  1343. {
  1344. // this function will map down a section of the layer onto the destination
  1345. // buffer at the desired location, note the width of the destination buffer
  1346. // is always assumed to be 320 bytes width. Also, the function will always
  1347. // wrap around the layer
  1348.  
  1349. int x,y,                        // looping variables
  1350.     layer_width,                // the width of the layer
  1351.     right_width,                // the width of the right and left half of
  1352.     left_width;                 // the layer to be drawn
  1353.  
  1354. unsigned char far *layer_buffer_l; // pointers to the left and right halves
  1355. unsigned char far *dest_buffer_l;  // of the layer buffer and destination
  1356. unsigned char far *layer_buffer_r; // buffer
  1357. unsigned char far *dest_buffer_r;
  1358.  
  1359. unsigned char pixel;            // current pixel value being processed
  1360.  
  1361. layer_width = source_layer->width;
  1362.  
  1363. dest_buffer_l  = dest_buffer + (dest_y << 8) + (dest_y << 6);
  1364.  
  1365. layer_buffer_l = source_layer->buffer + layer_width*source_y + source_x;
  1366.  
  1367. // test if wraping is needed
  1368.  
  1369. if ( ( (layer_width-source_x)-(int)SCREEN_WIDTH ) >= 0)
  1370.    {
  1371.    // there's enough data in layer to draw a complete line, no wraping needed
  1372.  
  1373.    left_width  = SCREEN_WIDTH;
  1374.  
  1375.    right_width = 0; // no wraping flag
  1376.  
  1377.    }
  1378. else
  1379.    {
  1380.    // wrapping needed
  1381.  
  1382.    left_width  = layer_width - source_x;
  1383.  
  1384.    right_width = SCREEN_WIDTH - left_width;
  1385.  
  1386.    dest_buffer_r  = dest_buffer_l + left_width;
  1387.  
  1388.    layer_buffer_r = layer_buffer_l - source_x; // move to far left end of layer
  1389.  
  1390.    } // end else need to wrap
  1391.  
  1392. // test if transparency is on or off
  1393.  
  1394. if (transparent)
  1395.    {
  1396.    // use version that will draw a transparent bitmap(slighlty slower)
  1397.    // first draw left half then right half
  1398.  
  1399.    // draw each line of the bitmap
  1400.  
  1401.    for (y=0; y<dest_height; y++)
  1402.        {
  1403.        // copy the next row into the destination buffer
  1404.  
  1405.        for (x=0; x<left_width; x++)
  1406.            {
  1407.  
  1408.            // test for transparent pixel i.e. 0, if not transparent then draw
  1409.  
  1410.            if ((pixel=layer_buffer_l[x]))
  1411.                 dest_buffer_l[x] = pixel;
  1412.  
  1413.            } // end for x
  1414.  
  1415.        // move to next line in destination buffer and in layer buffer
  1416.  
  1417.        dest_buffer_l  += SCREEN_WIDTH;
  1418.        layer_buffer_l += layer_width;
  1419.  
  1420.        } // end for y
  1421.  
  1422.    // now right half
  1423.  
  1424.    // draw each line of the bitmap
  1425.  
  1426.    if (right_width)
  1427.       {
  1428.       for (y=0; y<dest_height; y++)
  1429.           {
  1430.           // copy the next row into the destination buffer
  1431.  
  1432.           for (x=0; x<right_width; x++)
  1433.               {
  1434.  
  1435.               // test for transparent pixel i.e. 0, if not transparent then draw
  1436.  
  1437.               if ((pixel=layer_buffer_r[x]))
  1438.                    dest_buffer_r[x] = pixel;
  1439.  
  1440.               } // end for x
  1441.  
  1442.           // move to next line in destination buffer and in layer buffer
  1443.  
  1444.           dest_buffer_r  += SCREEN_WIDTH;
  1445.           layer_buffer_r += layer_width;
  1446.  
  1447.           } // end for y
  1448.  
  1449.       } // end if right side needs to be drawn
  1450.  
  1451.    } // end if transparent
  1452. else
  1453.    {
  1454.  
  1455.    // draw each line of the bitmap, note how each pixel doesn't need to be
  1456.    // tested for transparency hence a memcpy can be used (very fast!)
  1457.  
  1458.    for (y=0; y<dest_height; y++)
  1459.        {
  1460.        // copy the next row into the destination buffer using memcpy for speed
  1461.  
  1462.        _fmemcpy((void far *)dest_buffer_l,
  1463.                 (void far *)layer_buffer_l,left_width);
  1464.  
  1465.        // move to next line in double buffer and in bitmap buffer
  1466.  
  1467.        dest_buffer_l  += SCREEN_WIDTH;
  1468.        layer_buffer_l += layer_width;
  1469.  
  1470.        } // end for y
  1471.  
  1472.    // now right half if needed
  1473.  
  1474.    if (right_width)
  1475.       {
  1476.  
  1477.       for (y=0; y<dest_height; y++)
  1478.           {
  1479.           // copy the next row into the destination buffer using memcpy for speed
  1480.  
  1481.           _fmemcpy((void far *)dest_buffer_r,
  1482.                    (void far *)layer_buffer_r,right_width);
  1483.  
  1484.           // move to next line in double buffer and in bitmap buffer
  1485.  
  1486.           dest_buffer_r  += SCREEN_WIDTH;
  1487.           layer_buffer_r += layer_width;
  1488.  
  1489.           } // end for y
  1490.  
  1491.       } // end if right half
  1492.  
  1493.    } // end else non-transparent version
  1494.  
  1495. } // end Layer_Draw
  1496.  
  1497. //////////////////////////////////////////////////////////////////////////////
  1498.  
  1499. void Layer_Build(layer_ptr dest_layer,int dest_x, int dest_y,
  1500.                  unsigned char far *source_buffer,int source_x,int source_y,
  1501.                  int width,int height)
  1502. {
  1503. // this function is used to build up the layer out of smaller pieces
  1504. // this allows a layer to be very long, tall etc. also the source data buffer
  1505. // must be constructed such that there are 320 bytes per row
  1506.  
  1507. int y,                       // looping variable
  1508.     layer_width;             // the width of the layer
  1509.  
  1510. unsigned char far *source_data;   // pointer to start of source bitmap image
  1511. unsigned char far *layer_buffer;  // pointer to layer buffer
  1512.  
  1513. // extract width of layer
  1514.  
  1515. layer_width  = dest_layer->width;
  1516.  
  1517. // compute starting location in layer buffer
  1518.  
  1519. layer_buffer = dest_layer->buffer + layer_width*dest_y + dest_x; ;
  1520.  
  1521. // compute starting location in source image buffer
  1522.  
  1523. source_data = source_buffer + (source_y << 8) + (source_y << 6) + source_x;
  1524.  
  1525. // scan each line of source image into layer buffer
  1526.  
  1527. for (y=0; y<height; y++)
  1528.     {
  1529.     // copy the next row into the layer buffer using memcpy for speed
  1530.  
  1531.     _fmemcpy((void far *)layer_buffer,
  1532.              (void far *)source_data,width);
  1533.  
  1534.     // move to next line in source buffer and in layer buffer
  1535.  
  1536.     source_data  += SCREEN_WIDTH;
  1537.     layer_buffer += layer_width;
  1538.  
  1539.     } // end for y
  1540.  
  1541. } // end Layer_Build
  1542.  
  1543. //////////////////////////////////////////////////////////////////////////////
  1544.  
  1545. int Layer_Create(layer_ptr dest_layer, int width, int height)
  1546. {
  1547. // this function can be used to allocate the memory needed for a layer
  1548. // the width must be divisible by two.
  1549.  
  1550. if ((dest_layer->buffer = (unsigned char far *)_fmalloc(width*height+2))==NULL)
  1551.    return(0);
  1552. else
  1553.    {
  1554.    // save the dimensions of layer
  1555.  
  1556.    dest_layer->width  = width;
  1557.    dest_layer->height = height;
  1558.  
  1559.    return(1);
  1560.  
  1561.    } // end else
  1562.  
  1563. } // end Layer_Create
  1564.  
  1565. //////////////////////////////////////////////////////////////////////////////
  1566.  
  1567. void Layer_Delete(layer_ptr the_layer)
  1568. {
  1569. // this function deletes the memory used by a layer
  1570.  
  1571. if (the_layer->buffer)
  1572.    _ffree(the_layer->buffer);
  1573.  
  1574. } // end Layer_Delete
  1575.  
  1576. //////////////////////////////////////////////////////////////////////////////
  1577.  
  1578. void Print_Char_DB(int xc,int yc,char c,int color,int transparent)
  1579. {
  1580. // this function is used to print a character on the double buffer. It uses the
  1581. // internal 8x8 character set to do this. Note that each character is
  1582. // 8 bytes where each byte represents the 8 pixels that make up the row
  1583. // of pixels
  1584.  
  1585. int offset,               // offset into video memory
  1586.          x,               // loop variable
  1587.          y;               // loop variable
  1588.  
  1589. unsigned char far *work_char; // pointer to character being printed
  1590.  
  1591. unsigned char bit_mask;       // bitmask used to extract proper bit
  1592.  
  1593. // compute starting offset in rom character lookup table
  1594. // multiple the character by 8 and add the result to the starting address
  1595. // of the ROM character set
  1596.  
  1597. work_char = rom_char_set + c * ROM_CHAR_HEIGHT;
  1598.  
  1599. // compute offset of character in double buffer, use shifting to multiply
  1600.  
  1601. offset = (yc << 8) + (yc << 6) + xc;
  1602.  
  1603. // draw the character row by row
  1604.  
  1605. for (y=0; y<ROM_CHAR_HEIGHT; y++)
  1606.     {
  1607.     // reset bit mask
  1608.  
  1609.     bit_mask = 0x80;
  1610.  
  1611.     // draw each pixel of this row
  1612.  
  1613.     for (x=0; x<ROM_CHAR_WIDTH; x++)
  1614.         {
  1615.         // test for transparent pixel i.e. 0, if not transparent then draw
  1616.  
  1617.         if ((*work_char & bit_mask))
  1618.              double_buffer[offset+x] = (unsigned char)color;
  1619.  
  1620.         else
  1621.         if (!transparent)               // takes care of transparency
  1622.             double_buffer[offset+x] = 0; // make black part opaque
  1623.  
  1624.         // shift bit mask
  1625.  
  1626.         bit_mask = (bit_mask>>1);
  1627.  
  1628.         } // end for x
  1629.  
  1630.     // move to next line in double buffer and in rom character data area
  1631.  
  1632.     offset      += MODE13_WIDTH;
  1633.     work_char++;
  1634.  
  1635.     } // end for y
  1636.  
  1637. } // end Print_Char_DB
  1638.  
  1639. //////////////////////////////////////////////////////////////////////////////
  1640.  
  1641. void Print_String_DB(int x,int y,int color, char *string,int transparent)
  1642. {
  1643. // this function prints an entire string into the double buffer with fixed
  1644. // spacing between each character by calling the Print_Char() function
  1645.  
  1646.  int index,   // loop index
  1647.      length;  // length of string
  1648.  
  1649. // compute length of string
  1650.  
  1651. length = strlen(string);
  1652.  
  1653. // print the string a character at a time
  1654.  
  1655. for (index=0; index<length; index++)
  1656.      Print_Char_DB(x+(index<<3),y,string[index],color,transparent);
  1657.  
  1658. } // end Print_String_DB
  1659.  
  1660. ///////////////////////////////////////////////////////////////////////////////
  1661.  
  1662. void Write_Pixel_DB(int x,int y,int color)
  1663. {
  1664.  
  1665. // plots the pixel in the desired color to the double buffer
  1666. // to accomplish the multiplications
  1667.  
  1668. // use the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  1669.  
  1670. double_buffer[((y<<8) + (y<<6)) + x] = (unsigned char )color;
  1671.  
  1672. } // end Write_Pixel_DB
  1673.  
  1674. ///////////////////////////////////////////////////////////////////////////////
  1675.  
  1676. int Read_Pixel_DB(int x,int y)
  1677. {
  1678. // this function read a pixel from the double buffer
  1679.  
  1680. // use the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  1681.  
  1682. return((int)(double_buffer[((y<<8) + (y<<6)) + x]));
  1683.  
  1684. } // end Read_Pixel_DB
  1685.  
  1686. //////////////////////////////////////////////////////////////////////////////
  1687.  
  1688. void Set_Visual_Page_Mode_Z(int page)
  1689. {
  1690. // this function sets the visual page that will be displayed by the VGA
  1691.  
  1692. if (page==PAGE_0)
  1693.    {
  1694.    // re-program the start address registers in the CRT controller
  1695.    // to point at page 0 @ 0xA000:0000
  1696.  
  1697.    // first low byte of address
  1698.  
  1699.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  1700.    _outp(CRT_CONTROLLER+1,0x00);
  1701.  
  1702.    // now high byte
  1703.  
  1704.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  1705.    _outp(CRT_CONTROLLER+1,0x00);
  1706.  
  1707.    } // end if page 0
  1708. else
  1709. if (page==PAGE_1)
  1710.    {
  1711.    // re-program the start address registers in the CRT controller
  1712.    // to point at page 1 @ 0xA000:8000
  1713.  
  1714.    // first low byte of address
  1715.  
  1716.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  1717.    _outp(CRT_CONTROLLER+1,0x00);
  1718.  
  1719.    // now high byte
  1720.  
  1721.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  1722.    _outp(CRT_CONTROLLER+1,0x80);
  1723.  
  1724.    } // end else page 1
  1725.  
  1726. // note: we could use WORD out's, but this is clearer, feel free to change them
  1727.  
  1728. } // end Set_Visual_Page_Mode_Z
  1729.  
  1730. ///////////////////////////////////////////////////////////////////////////////
  1731.  
  1732. void Set_Working_Page_Mode_Z(int page)
  1733. {
  1734. // this function sets the page that all mode Z functions will update when
  1735. // called
  1736.  
  1737. if (page==PAGE_0)
  1738.    video_buffer = page_0_buffer;
  1739. else
  1740.    video_buffer = page_1_buffer;
  1741.  
  1742. } // end Set_Working_Page_Mode_Z
  1743.  
  1744.  
  1745.