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