home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / BATTLE.ZIP / INSTALL.ZIP / GRAPHICS.C < prev    next >
C/C++ Source or Header  |  1996-06-02  |  69KB  |  2,549 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15.  
  16. #include "graphics.h"   // the header file for this module
  17.  
  18. // G L O B A L S //////////////////////////////////////////////////////////////
  19.  
  20. unsigned char far *video_buffer = (unsigned char far *)0xA0000000L;
  21. unsigned char far *rom_char_set = (unsigned char far *)0xF000FA6EL;
  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. unsigned int far *clock = (unsigned int far *)0x0000046CL; // pointer to internal
  46.  
  47. sprite shell;
  48. pcx_picture background, shell_back, ships_back;
  49. bitmap tech_font[NUM_TECH_FONT];   // the tech font bitmaps
  50.  
  51. // F U N C T I O N S /////////////////////////////////////////////////////////
  52.  
  53. void Print_Char(int xc,int yc,char c,int color,int transparent)
  54. {
  55. // this function is used to print a character on the screen. It uses the
  56. // internal 8x8 character set to do this. Note that each character is
  57. // 8 bytes where each byte represents the 8 pixels that make up the row
  58. // of pixels
  59.  
  60. int offset,               // offset into video memory
  61.          x,               // loop variable
  62.          y;               // loop variable
  63.  
  64. unsigned char far *work_char; // pointer to character being printed
  65.  
  66. unsigned char bit_mask;       // bitmask used to extract proper bit
  67.  
  68. // compute starting offset in rom character lookup table
  69. // multiple the character by 8 and add the result to the starting address
  70. // of the ROM character set
  71.  
  72. work_char = rom_char_set + c * ROM_CHAR_HEIGHT;
  73.  
  74. // compute offset of character in video buffer, use shifting to multiply
  75.  
  76. offset = (yc << 8) + (yc << 6) + xc;
  77.  
  78. // draw the character row by row
  79.  
  80. for (y=0; y<ROM_CHAR_HEIGHT; y++)
  81.     {
  82.     // reset bit mask
  83.  
  84.     bit_mask = 0x80;
  85.  
  86.     // draw each pixel of this row
  87.  
  88.     for (x=0; x<ROM_CHAR_WIDTH; x++)
  89.         {
  90.         // test for transparent pixel i.e. 0, if not transparent then draw
  91.  
  92.         if ((*work_char & bit_mask))
  93.              video_buffer[offset+x] = (unsigned char)color;
  94.  
  95.         else
  96.         if (!transparent)               // takes care of transparency
  97.             video_buffer[offset+x] = 0; // make black part opaque
  98.  
  99.         // shift bit mask
  100.  
  101.         bit_mask = (bit_mask>>1);
  102.  
  103.         } // end for x
  104.  
  105.     // move to next line in video buffer and in rom character data area
  106.  
  107.     offset      += MODE13_WIDTH;
  108.     work_char++;
  109.  
  110.     } // end for y
  111.  
  112. } // end Print_Char
  113.  
  114. //////////////////////////////////////////////////////////////////////////////
  115.  
  116. void Print_String(int x,int y,int color, char *string,int transparent)
  117. {
  118. // this function prints an entire string on the screen with fixed spacing
  119. // between each character by calling the Print_Char() function
  120.  
  121.  int index,   // loop index
  122.      length;  // length of string
  123.  
  124. // compute length of string
  125.  
  126. length = strlen(string);
  127.  
  128. // print the string a character at a time
  129.  
  130. for (index=0; index<length; index++)
  131.      Print_Char(x+(index<<3),y,string[index],color,transparent);
  132.  
  133. } // end Print_String
  134.  
  135. ///////////////////////////////////////////////////////////////////////////////
  136.  
  137. void Write_Pixel(int x,int y,int color)
  138. {
  139.  
  140. // plots the pixel in the desired color a little quicker using binary shifting
  141. // to accomplish the multiplications
  142.  
  143. // use the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  144.  
  145. video_buffer[((y<<8) + (y<<6)) + x] = (unsigned char )color;
  146.  
  147. } // end Write_Pixel
  148.  
  149. ///////////////////////////////////////////////////////////////////////////////
  150.  
  151. int Read_Pixel(int x,int y)
  152. {
  153. // this function read a pixel from the screen buffer
  154.  
  155.  
  156. // use the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  157.  
  158. return((int)(video_buffer[((y<<8) + (y<<6)) + x]));
  159.  
  160. } // end Read_Pixel
  161.  
  162. //////////////////////////////////////////////////////////////////////////////
  163.  
  164. void Set_Graphics_Mode(int mode)
  165. {
  166.  
  167. // use the video interrupt 10h and the C interrupt function to set
  168. // the video mode
  169.  
  170. union REGS inregs,outregs;
  171.  
  172. inregs.h.ah = 0;                    // set video mode sub-function
  173. inregs.h.al = (unsigned char)mode;  // video mode to change to
  174.  
  175. int86(0x10, &inregs, &outregs);
  176.  
  177. } // end Set_Graphics_Mode
  178.  
  179. /////////////////////////////////////////////////////////////////////////////
  180.  
  181. void Time_Delay(int clicks)
  182. {
  183. // this function uses the internal timer to wait a specified number of "clicks"
  184. // the actual amount of real time is the number of clicks * (time per click)
  185. // usually the time per click is set to 1/18th of a second or 55ms
  186.  
  187. long far *clock = (long far *)0x0000046CL; // address of timer
  188.  
  189. long start_time; // starting time
  190.  
  191. // get current time
  192.  
  193. start_time = *clock;
  194.  
  195. // when the current time minus the starting time >= the requested delay then
  196. // the function can exit
  197.  
  198. while(labs(*clock - start_time) < (long)clicks){}
  199.  
  200. } // end Time_Delay
  201.  
  202. ////////////////////////////////////////////////////////////////////////////////
  203.  
  204. void Line_H(int x1,int x2,int y,int color)
  205. {
  206. // draw a horizontal line using the memset function
  207. // this function does not do clipping hence x1,x2 and y must all be within
  208. // the bounds of the screen
  209.  
  210. int temp; // used for temporary storage during endpoint swap
  211.  
  212. // sort x1 and x2, so that x2 > x1
  213.  
  214. if (x1>x2)
  215.    {
  216.    temp = x1;
  217.    x1   = x2;
  218.    x2   = temp;
  219.    } // end swap
  220.  
  221. // draw the row of pixels
  222.  
  223. _fmemset((char far *)(video_buffer + ((y<<8) + (y<<6)) + x1),
  224.          (unsigned char)color,x2-x1+1);
  225.  
  226. } // end Line_H
  227.  
  228. //////////////////////////////////////////////////////////////////////////////
  229.  
  230. void Line_V(int y1,int y2,int x,int color)
  231. {
  232. // draw a vertical line, note that a memset function can no longer be
  233. // used since the pixel addresses are no longer contiguous in memory
  234. // note that the end points of the line must be on the screen
  235.  
  236. unsigned char far *start_offset; // starting memory offset of line
  237.  
  238. int index, // loop index
  239.     temp;  // used for temporary storage during swap
  240.  
  241. // make sure y2 > y1
  242.  
  243. if (y1>y2)
  244.    {
  245.    temp = y1;
  246.    y1   = y2;
  247.    y2   = temp;
  248.    } // end swap
  249.  
  250. // compute starting position
  251.  
  252. start_offset = video_buffer + ((y1<<8) + (y1<<6)) + x;
  253.  
  254. for (index=0; index<=y2-y1; index++)
  255.     {
  256.     // set the pixel
  257.  
  258.     *start_offset = (unsigned char)color;
  259.  
  260.     // move downward to next line
  261.  
  262.     start_offset+=320;
  263.  
  264.     } // end for index
  265.  
  266. } // end Line_V
  267.  
  268. //////////////////////////////////////////////////////////////////////////////
  269.  
  270. void Write_Color_Reg(int index, RGB_color_ptr color)
  271. {
  272.  
  273. // this function is used to write a color register with the RGB value
  274. // within "color"
  275.  
  276. // tell vga card which color register to update
  277.  
  278. outp(COLOR_REGISTER_WR, index);
  279.  
  280. // update the color register RGB triple, note the same port is used each time
  281. // the hardware will make sure each of the components is stored in the
  282. // proper location
  283.  
  284. outp(COLOR_DATA,color->red);
  285. outp(COLOR_DATA,color->green);
  286. outp(COLOR_DATA,color->blue);
  287.  
  288. } // end Write_Color_Reg
  289.  
  290. ///////////////////////////////////////////////////////////////////////////////
  291.  
  292. RGB_color_ptr Read_Color_Reg(int index, RGB_color_ptr color)
  293. {
  294.  
  295. // this function reads the RGB triple out of a palette register and places it
  296. // into "color"
  297.  
  298. // tell vga card which register to read
  299.  
  300. outp(COLOR_REGISTER_RD, index);
  301.  
  302. // now extract the data
  303.  
  304. color->red   = (unsigned char)inp(COLOR_DATA);
  305. color->green = (unsigned char)inp(COLOR_DATA);
  306. color->blue  = (unsigned char)inp(COLOR_DATA);
  307.  
  308. // return a pointer to color so that the function can be used as an RVALUE
  309.  
  310. return(color);
  311.  
  312. } // end Read_Color_Reg
  313.  
  314. ///////////////////////////////////////////////////////////////////////////////
  315.  
  316. void Read_Palette(int start_reg,int end_reg, RGB_palette_ptr the_palette)
  317. {
  318. // this function will read the palette registers in the range start_reg to
  319. // end_reg and save them into the appropriate positions in colors
  320.  
  321. int index; // used for looping
  322.  
  323. RGB_color color;
  324.  
  325. // read all the registers
  326.  
  327. for (index=start_reg; index<=end_reg; index++)
  328.     {
  329.     // read the color register
  330.  
  331.     Read_Color_Reg(index,(RGB_color_ptr)&color);
  332.  
  333.     // save it in database
  334.  
  335.     the_palette->colors[index].red   = color.red;
  336.     the_palette->colors[index].green = color.green;
  337.     the_palette->colors[index].blue  = color.blue;
  338.  
  339.     } // end for index
  340.  
  341. // save the interval of registers that were saved
  342.  
  343. the_palette->start_reg = start_reg;
  344. the_palette->end_reg   = end_reg;
  345.  
  346. } // end Read_Palette
  347.  
  348. ///////////////////////////////////////////////////////////////////////////////
  349.  
  350. void Write_Palette(int start_reg,int end_reg, RGB_palette_ptr the_palette)
  351. {
  352. // this function will write to the color registers using the data in the
  353. // sen palette structure
  354.  
  355. int index; // used for looping
  356.  
  357. // write all the registers
  358.  
  359. for (index=start_reg; index<=end_reg; index++)
  360.     {
  361.     // write the color registers using the data from the sent palette
  362.  
  363.     Write_Color_Reg(index,(RGB_color_ptr)&(the_palette->colors[index]));
  364.  
  365.     } // end for index
  366.  
  367. } // end Write_Palette
  368.  
  369. ///////////////////////////////////////////////////////////////////////////////
  370.  
  371. void Draw_Rectangle(int x1,int y1,int x2,int y2,int color)
  372. {
  373. // this function will draw a rectangle from (x1,y1) - (x2,y2)
  374. // it is assumed that each endpoint is within the screen boundaries
  375. // and (x1,y1) is the upper left hand corner and (x2,y2) is the lower
  376. // right hand corner
  377.  
  378. unsigned char far *start_offset;   // starting memory offset of first row
  379.  
  380. int width;   // width of rectangle
  381.  
  382. // compute starting offset of first row
  383.  
  384. start_offset = video_buffer + ((y1<<8) + (y1<<6)) + x1;
  385.  
  386. // compute width of rectangle
  387.  
  388. width  = 1 + x2 - x1; // the "1" to reflect the true width in pixels
  389.  
  390. // draw the rectangle row by row
  391.  
  392. while(y1++<=y2)
  393.      {
  394.      // draw the line
  395.  
  396.      _fmemset((char far *)start_offset,(unsigned char)color,width);
  397.  
  398.      // move the memory pointer to the next line
  399.  
  400.      start_offset+=320;
  401.  
  402.      } // end while
  403.  
  404. } // end Draw_Rectangle
  405.  
  406. ////////////////////////////////////////////////////////////////////////////////
  407.  
  408. void Fill_Screen(int color)
  409. {
  410. // this function will fill the entire screen with the sent color
  411.  
  412. // use the inline assembler for speed
  413.  
  414. #pragma aux Fill_da_screen = \
  415.    "les di,video_buffer"   \
  416.    "mov al,BYTE PTR color" \
  417.    "mov ah,al"             \
  418.    "mov cx,32000"          \
  419.    "rep stosw"             \
  420.    modify [di ax cx];
  421.  
  422. Fill_da_screen();
  423.  
  424. /*
  425. _asm
  426.    {
  427.  
  428.    les di,video_buffer   ; point es:di to video buffer
  429.    mov al,BYTE PTR color ; move the color into al and ah
  430.    mov ah,al             ; replicate color into ah
  431.    mov cx,320*200/2      ; number of words to fill(using word is faster than bytes)
  432.    rep stosw             ; move the color into the video buffer really fast!
  433.  
  434.    } // end inline asm
  435. */
  436. } // end Fill_Screen
  437.  
  438. //////////////////////////////////////////////////////////////////////////////
  439. /*
  440. void Fill_Screen_Z(int color)
  441. {
  442. // this function will fill the mode Z video buffer with the sent color
  443.  
  444. // use the inline assembler for speed
  445.  
  446. _asm
  447.    {
  448.    mov dx,SEQUENCER          ; address the sequencer
  449.    mov al,SEQ_PLANE_ENABLE   ; select the plane enable register
  450.    mov ah,0fh                ; enable all four planes
  451.    out dx,ax                 ; do it baby!
  452.    les di,video_buffer   ; point es:di to video buffer
  453.    mov al,BYTE PTR color ; move the color into al and ah
  454.    mov ah,al             ; replicate color into ah
  455.    mov cx,320*400/8      ; number of words to fill(using word is faster than bytes)
  456.    rep stosw             ; move the color into the video buffer really fast!
  457.    } // end inline asm
  458.  
  459. } // end Fill_Screen_Z
  460.  
  461. ///////////////////////////////////////////////////////////////////////////////
  462.  
  463. void Write_Pixel_Z(int x,int y,int color)
  464. {
  465.  
  466. // this function will write a pixel to screen in mode Z
  467.  
  468. // first select the proper color plane use inline for speed
  469. // if we used C then there would be a function call and about 10-15 more
  470. // instructions!
  471.  
  472. _asm
  473.    {
  474.    mov dx,SEQUENCER          ; address the sequencer
  475.    mov al,SEQ_PLANE_ENABLE   ; select the plane enable register
  476.    mov cl,BYTE PTR x         ; extract lower byte from x
  477.    and cl,03h                ; extract the plane number = x MOD 4
  478.    mov ah,1                  ; a "1" selects the plane in the plane enable
  479.    shl ah,cl                 ; shift the "1" bit proper number of times
  480.    out dx,ax                 ; do it baby!
  481.    } // end asm
  482.  
  483. // write the pixel, offset = (y*320+x)/4
  484.  
  485. video_buffer[(y<<6)+(y<<4)+(x>>2)] = (unsigned char )color;
  486.  
  487. } // end Write_Pixel_Z
  488.  
  489. ///////////////////////////////////////////////////////////////////////////////
  490.  
  491. void Set_Mode_Z(void)
  492. {
  493. // this function will set the video mode to 320x400x256
  494.  
  495. int data;  // used to store data
  496.  
  497. // set system to mode 13h and use it as a foundation to base 320x400 mode on
  498.  
  499. _asm
  500.    {
  501.    mov ax,0013h  ; ah=function number 00(set graphics mode), al=13h
  502.    int 10h       ; video interrupt 10h
  503.    } // end asm
  504.  
  505. // make changes to the crt controller first
  506.  
  507. // set number of scanlines to 1
  508.  
  509. outp(CRT_CONTROLLER,CRT_MAX_SCANLINE);
  510. data=inp(CRT_CONTROLLER+1);
  511. outp(CRT_CONTROLLER+1,RESET_BITS(data,0x0f));
  512.  
  513. // use byte addressing instead of word
  514.  
  515. outp(CRT_CONTROLLER,CRT_ADDR_MODE);
  516. data=inp(CRT_CONTROLLER+1);
  517. outp(CRT_CONTROLLER+1,RESET_BITS(data,0x40));
  518.  
  519. // second register that needs to reflect byte addressing
  520.  
  521. outp(CRT_CONTROLLER,CRT_MODE_CONTROL);
  522. data=inp(CRT_CONTROLLER+1);
  523. outp(CRT_CONTROLLER+1,SET_BITS(data,0x40));
  524.  
  525. // make changes to graphics controller
  526.  
  527. // set addressing to not use odd/even memory writes
  528.  
  529. outp(GFX_CONTROLLER,GFX_WRITE_MODE);
  530. data=inp(GFX_CONTROLLER+1);
  531. outp(GFX_CONTROLLER+1,RESET_BITS(data,0x10));
  532.  
  533. // don't chain the memory maps together
  534.  
  535. outp(GFX_CONTROLLER,GFX_MISC);
  536. data=inp(GFX_CONTROLLER+1);
  537. outp(GFX_CONTROLLER+1,RESET_BITS(data,0x02));
  538.  
  539. // make changes to sequencer
  540.  
  541. // again we must select no chaining and no odd/even memory addressing
  542.  
  543. outp(SEQUENCER,SEQ_MEMORY_MODE);
  544. data =inp(SEQUENCER+1);
  545. data = RESET_BITS(data,0x08);
  546. data = SET_BITS(data,0x04);
  547. outp(SEQUENCER+1,data);
  548.  
  549. // now clear the screen
  550.  
  551. outp(SEQUENCER,SEQ_PLANE_ENABLE);
  552. outp(SEQUENCER+1,0x0f);
  553.  
  554. // clear the screen, remember it is 320x400, but that is divided into four
  555. // planes, hence we need only to clear 32k out since there will ne four planes
  556. // each being cleared in parallel for a total of 4*32k or 128 = 320x400
  557. // note: "k" in this example means 1000 not 1024
  558.  
  559. _asm
  560.    {
  561.  
  562.    les di,video_buffer   ; point es:di to video buffer, same addre for mode Z
  563.    xor ax,ax             ; move a zero into al and ah
  564.    mov cx,320*400/8      ; number of words to fill(using word is faster than bytes)
  565.    rep stosw             ; move the color into the video buffer really fast!
  566.  
  567.    } // end inline asm
  568.  
  569. } // end Set_Mode_Z
  570. */
  571.  
  572. //////////////////////////////////////////////////////////////////////////////
  573.  
  574. int PCX_Init(pcx_picture_ptr image)
  575. {
  576. // this function allocates the buffer that the image data will be loaded into
  577. // when a PCX file is decompressed
  578.  
  579. if (!(image->buffer = (unsigned char far *)_fmalloc(SCREEN_WIDTH * SCREEN_HEIGHT + 1)))
  580.    {
  581.    printf("\nPCX SYSTEM - Couldn't allocate PCX image buffer");
  582.    return(0);
  583.    } // end if
  584.  
  585. // success
  586.  
  587. return(1);
  588.  
  589. } // end PCX_Init
  590.  
  591. //////////////////////////////////////////////////////////////////////////////
  592.  
  593. int PCX_Load(char *filename, pcx_picture_ptr image,int load_palette)
  594. {
  595.  
  596. // this function loads a PCX file into the image structure. The function
  597. // has three main parts: 1. load the PCX header, 2. load the image data and
  598. // decompress it and 3. load the palette data and update the VGA palette
  599. // note: the palette will only be loaded if the load_palette flag is 1
  600.  
  601. FILE *fp;                // the file pointer used to open the PCX file
  602.  
  603. int num_bytes,           // number of bytes in current RLE run
  604.     index;               // loop variable
  605.  
  606. long count;              // the total number of bytes decompressed
  607.  
  608. unsigned char data;      // the current pixel data
  609.  
  610. char far *temp_buffer;   // working buffer
  611.  
  612. // open the file, test if it exists
  613.  
  614. if ((fp = fopen(filename,"rb"))==NULL)
  615.    {
  616.    printf("\nPCX SYSTEM - Couldn't find file: %s",filename);
  617.    return(0);
  618.  
  619.    } // end if couldn't find file
  620.  
  621. // load the header
  622.  
  623. temp_buffer = (char far *)image;
  624.  
  625. for (index=0; index<128; index++)
  626.     {
  627.     temp_buffer[index] = (char)getc(fp);
  628.     } // end for index
  629.  
  630. // load the data and decompress into buffer, we need a total of 64,000 bytes
  631.  
  632. count=0;
  633.  
  634. // loop while 64,000 bytes haven't been decompressed
  635.  
  636. while(count<=SCREEN_WIDTH * SCREEN_HEIGHT)
  637.      {
  638.      // get the first piece of data
  639.  
  640.      data = (unsigned char)getc(fp);
  641.  
  642.      // is this a RLE run?
  643.  
  644.      if (data>=192 && data<=255)
  645.         {
  646.         // compute number of bytes in run
  647.  
  648.         num_bytes = data-192;
  649.  
  650.         // get the actual data for the run
  651.  
  652.         data  = (unsigned char)getc(fp);
  653.  
  654.         // replicate data in buffer num_bytes times
  655.  
  656.         while(num_bytes-->0)
  657.              {
  658.              image->buffer[count++] = data;
  659.  
  660.              } // end while
  661.  
  662.         } // end if rle
  663.      else
  664.         {
  665.         // actual data, just copy it into buffer at next location
  666.  
  667.         image->buffer[count++] = data;
  668.  
  669.         } // end else not rle
  670.  
  671.      } // end while
  672.  
  673. // load color palette
  674.  
  675. // move to end of file then back up 768 bytes i.e. to begining of palette
  676.  
  677. fseek(fp,-768L,SEEK_END);
  678.  
  679. // load the PCX pallete into the VGA color registers
  680.  
  681. for (index=0; index<256; index++)
  682.     {
  683.     // get the red component
  684.  
  685.     image->palette[index].red   = (unsigned char)(getc(fp) >> 2);
  686.  
  687.     // get the green component
  688.  
  689.     image->palette[index].green = (unsigned char)(getc(fp) >> 2);
  690.  
  691.     // get the blue component
  692.  
  693.     image->palette[index].blue  = (unsigned char)(getc(fp) >> 2);
  694.  
  695.     } // end for index
  696.  
  697. // time to close the file
  698.  
  699. fclose(fp);
  700.  
  701. // change the palette to newly loaded palette if commanded to do so
  702.  
  703. if (load_palette)
  704.    {
  705.  
  706.    // for each palette register set to the new color values
  707.  
  708.    for (index=0; index<256; index++)
  709.        {
  710.  
  711.        Write_Color_Reg(index,(RGB_color_ptr)&image->palette[index]);
  712.  
  713.        } // end for index
  714.  
  715.    } // end if load palette data into VGA
  716.  
  717. // success
  718.  
  719. return(1);
  720.  
  721. } // end PCX_Load
  722.  
  723. /////////////////////////////////////////////////////////////////////////////
  724.  
  725. void PCX_Delete(pcx_picture_ptr image)
  726. {
  727. // this function de-allocates the buffer region used for the pcx file load
  728.  
  729. _ffree(image->buffer);
  730.  
  731. } // end PCX_Delete
  732.  
  733. //////////////////////////////////////////////////////////////////////////////
  734.  
  735. void PCX_Show_Buffer(pcx_picture_ptr image, int appear_from_black)
  736. {
  737.  
  738. char far * data = image->buffer;
  739. int pal_reg = 0, index = 0;
  740. RGB_color tmpColorBuffer[256];             //Buffer used to hold old palette if appear_from_black is
  741.                                            //true
  742. // just copy he pcx buffer into the video buffer
  743. /*
  744.         _fmemcpy((char far *)video_buffer,
  745.                 (char far *)image->buffer, 64000);
  746. */
  747. // use inline assembly for speed
  748. #pragma aux PCX_show_da_buffer = \
  749.    "push ds"               \
  750.    "les di, video_buffer"  \
  751.    "lds si, data"          \
  752.    "mov cx,32000"          \
  753.    "cld"                   \
  754.    "rep movsw"             \
  755.    "pop ds"                \
  756.    modify [es di si cx];                
  757.  
  758. PCX_show_da_buffer();
  759.  
  760. if(appear_from_black)
  761. {
  762.     for(index = 0; index < 256; index++)
  763.     {
  764.         tmpColorBuffer[index].red   = 0;
  765.         tmpColorBuffer[index].green = 0;
  766.         tmpColorBuffer[index].blue  = 0;
  767.     }
  768.  
  769.     index = 0;
  770.  
  771.     for (index=0; index<10; index++)
  772.     {
  773.         // loop thru all palette registers
  774.  
  775.         for (pal_reg=0; pal_reg<256; pal_reg++)
  776.         {
  777.             if(tmpColorBuffer[pal_reg].red < (image->palette[pal_reg].red - 6 ))
  778.                 tmpColorBuffer[pal_reg].red += 6;
  779.             else tmpColorBuffer[pal_reg].red = image->palette[pal_reg].red;
  780.  
  781.             if(tmpColorBuffer[pal_reg].green < (image->palette[pal_reg].green - 6 ))
  782.                tmpColorBuffer[pal_reg].green += 6;                
  783.             else tmpColorBuffer[pal_reg].green = image->palette[pal_reg].green;
  784.     
  785.             if(tmpColorBuffer[pal_reg].blue < (image->palette[pal_reg].blue - 6 ))
  786.                 tmpColorBuffer[pal_reg].blue += 6;
  787.             else tmpColorBuffer[pal_reg].blue = image->palette[pal_reg].blue;
  788.  
  789.             Write_Color_Reg(pal_reg,(RGB_color_ptr)&tmpColorBuffer[pal_reg]);
  790.  
  791.         } // end for pal_reg
  792.  
  793.         // wait a bit
  794.  
  795.         Time_Delay(1);
  796.  
  797.     } // end for index
  798.  
  799.  
  800. } //end if appear_from_black
  801. // success
  802.  
  803.         
  804.  
  805. } // end PCX_Show_Buffer
  806.  
  807. ///////////////////////////////////////////////////////////////////////////////
  808.  
  809. void PCX_Copy_To_Buffer(pcx_picture_ptr image,unsigned char far *buffer)
  810. {
  811. // this function is used to copy the data in the PCX buffer to another buffer
  812. // usually the double buffer
  813.  
  814. // use the word copy function, note: double_buffer_size is in WORDS
  815.  
  816. void far * destination = buffer;
  817. void far * source = image->buffer;
  818.  
  819.     _fmemcpy(destination, source, 64000);
  820.  
  821.  
  822. #pragma aux copy_da_fword = \
  823.    "push ds"              \
  824.    "les di,destination"   \
  825.    "lds si,source"        \
  826.    "mov cx,double_buffer_size"     \
  827.    "rep movsw"            \
  828.    "pop ds"               \
  829.    modify [es di si cx];
  830.  
  831. copy_da_fword();
  832.  
  833. //fwordcpy((void far *)buffer,(void far *)image->buffer,double_buffer_size);
  834.  
  835. } // end PCX_Copy_To_Buffer
  836.  
  837. //////////////////////////////////////////////////////////////////////////////
  838.  
  839. void PCX_Get_Sprite(pcx_picture_ptr image,
  840.                      sprite_ptr sprite,
  841.                      int sprite_frame,
  842.                      int cell_x, int cell_y)
  843.  
  844. {
  845. // this function is used to load the images for a sprite into the sprite
  846. // frames array. It functions by using the size of the sprite and the
  847. // position of the requested cell to compute the proper location in the
  848. // pcx image buffer to extract the data from.
  849.  
  850. int x_off,  // position of sprite cell in PCX image buffer
  851.     y_off,
  852.     y,      // looping variable
  853.     width,  // size of sprite
  854.     height;
  855.  
  856. unsigned char far *sprite_data;
  857.  
  858. // extract width and height of sprite
  859.  
  860. width  = sprite->width;
  861. height = sprite->height;
  862.  
  863. // first allocate the memory for the sprite in the sprite structure
  864.  
  865. if((sprite->frames[sprite_frame] = (unsigned char far *)_fmalloc(width * height + 1))==NULL)
  866.     exit(1);
  867.  
  868. // create an alias to the sprite frame for ease of access
  869.  
  870. sprite_data = sprite->frames[sprite_frame];
  871.  
  872. // now load the sprite data into the sprite frame array from the pcx picture
  873.  
  874. x_off = (width+1)  * cell_x + 1;
  875. y_off = (height+1) * cell_y + 1;
  876.  
  877. // compute starting y address
  878.  
  879. y_off = y_off * 320; // 320 bytes per line
  880.  
  881. // scan the data row by row
  882.  
  883. for (y=0; y<height; y++,y_off+=320)
  884.     {
  885.     // copy the row of pixels
  886.  
  887.     _fmemcpy((void far *)&sprite_data[y*width],
  888.  
  889.              (void far *)&(image->buffer[y_off + x_off]),
  890.              width);
  891.  
  892.     } // end for y
  893.  
  894. // increment number of frames
  895.  
  896. sprite->num_frames++;
  897.  
  898. // done!, let's bail!
  899.  
  900. } // end PCX_Get_Sprite
  901.  
  902. //////////////////////////////////////////////////////////////////////////////
  903.  
  904. void Sprite_Init(sprite_ptr sprite,int x,int y,int x_old,int y_old,
  905.                    int width,int height,
  906.                                    int c1,int c2,int c3,
  907.                                    int xGrid, int yGrid)
  908. {
  909. // this function initializes a sprite
  910.  
  911. int index;
  912.  
  913. sprite->x            = x;
  914. sprite->y            = y;
  915. sprite->x_old        = x_old;
  916. sprite->y_old        = y_old;
  917.  
  918. sprite->coveredSquare1.x = xGrid;
  919. sprite->coveredSquare1.y = yGrid;
  920.  
  921. sprite->width        = width;
  922. sprite->height       = height;
  923. sprite->visible      = 1;
  924. sprite->counter_1    = c1;
  925. sprite->counter_2    = c2;
  926. sprite->counter_3    = c3;
  927. /*
  928. sprite->threshold_1  = t1;
  929. sprite->threshold_2  = t2;
  930. sprite->threshold_3  = t3;
  931. */
  932.  
  933. /*sprite->coveredSquare1.x = covered1.x;
  934. sprite->coveredSquare1.y = covered1.y;
  935. sprite->coveredSquare2.x = covered2.x;
  936. sprite->coveredSquare2.y = covered2.y;
  937. sprite->coveredSquare3.x = covered3.x;
  938. sprite->coveredSquare3.y = covered3.y;
  939. sprite->coveredSquare1.hit = 0;
  940. sprite->coveredSquare2.hit = 0;
  941. sprite->coveredSquare3.hit = 0;
  942. */
  943. sprite->curr_frame   = 0;
  944. sprite->state        = SPRITE_DEAD;
  945. sprite->num_frames   = 0;
  946. sprite->background   = (unsigned char far *)_fmalloc(width * height+1);
  947.  
  948. // set all bitmap pointers to null
  949.  
  950. for (index=0; index<MAX_SPRITE_FRAMES; index++)
  951.     sprite->frames[index] = NULL;
  952.  
  953. } // end Sprite_Init
  954.  
  955. //////////////////////////////////////////////////////////////////////////////
  956.  
  957. void Sprite_Delete(sprite_ptr sprite)
  958. {
  959. // this function deletes all the memory associated with a sprite
  960.  
  961. int index;
  962.  
  963. _ffree(sprite->background);
  964.  
  965. // now de-allocate all the animation frames
  966.  
  967. for (index=0; index<MAX_SPRITE_FRAMES; index++)
  968.     _ffree(sprite->frames[index]);
  969.  
  970. } // end Sprite_Delete
  971.  
  972. ////////////////////////////////////////////////////////////////////////////////
  973.  
  974. void Sprite_Under(sprite_ptr sprite, unsigned char far *buffer)
  975. {
  976.  
  977. // this function scans the background under a sprite so that when the sprite
  978. // is drawn the background isn't obliterated
  979.  
  980. unsigned char far *back_buffer; // background buffer for sprite
  981.  
  982. int m,                          // current line being scanned
  983.     width,                      // size of sprite
  984.     height;
  985.  
  986. // alias a pointer to sprite background for ease of access
  987.  
  988. back_buffer = sprite->background;
  989.  
  990. // alias width and height
  991.  
  992. width  = sprite->width;
  993. height = sprite->height;
  994.  
  995. // compute offset of background in source buffer
  996.  
  997. buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  998.  
  999. for (m=0; m<height; m++)
  1000.     {
  1001.     // copy the next row out off image buffer into sprite background buffer
  1002.  
  1003.     _fmemcpy((unsigned char far *)back_buffer,
  1004.              (unsigned char far *)buffer,
  1005.              width);
  1006.  
  1007.     // move to next line in source buffer and in sprite background buffer
  1008.  
  1009.     buffer      += SCREEN_WIDTH;
  1010.     back_buffer += width;
  1011.  
  1012.     } // end for y
  1013.  
  1014. } // end Sprite_Under
  1015.  
  1016. //////////////////////////////////////////////////////////////////////////////
  1017.  
  1018. void Sprite_Erase(sprite_ptr sprite,unsigned char far *buffer)
  1019. {
  1020. // replace the background that was behind the sprite
  1021. // this function replaces the background that was saved from where a sprite
  1022. // was going to be placed
  1023.  
  1024. unsigned char far *back_buffer; // background buffer for sprite
  1025.  
  1026. int m,                          // current line being scanned
  1027.     width,                      // size of sprite
  1028.     height;
  1029.  
  1030. // alias a pointer to sprite background for ease of access
  1031.  
  1032. back_buffer = sprite->background;
  1033.  
  1034. // alias width and height
  1035.  
  1036. width  = sprite->width;
  1037. height = sprite->height;
  1038.  
  1039. // compute offset in destination buffer
  1040.  
  1041. buffer = buffer + (sprite->y_old << 8) + (sprite->y_old << 6) + sprite->x_old;
  1042.  
  1043. for (m=0; m<height; m++)
  1044.     {
  1045.     // copy the next from sprite background buffer to destination buffer
  1046.  
  1047.     _fmemcpy((unsigned char far *)buffer,
  1048.              (unsigned char far *)back_buffer,
  1049.              width);
  1050.  
  1051.     // move to next line in destination buffer and in sprite background buffer
  1052.  
  1053.     buffer      += SCREEN_WIDTH;
  1054.     back_buffer += width;
  1055.  
  1056.     } // end for y
  1057.  
  1058. } // end Sprite_Erase
  1059.  
  1060. //////////////////////////////////////////////////////////////////////////////
  1061.  
  1062. void Sprite_Draw(sprite_ptr sprite, unsigned char far *buffer,int transparent)
  1063. {
  1064.  
  1065. // this function draws a sprite on the screen row by row very quickly
  1066. // note the use of shifting to implement multplication
  1067. // if the transparent flag is true then pixels wil be draw one by one
  1068. // else a memcpy will be used to draw each line
  1069.  
  1070. unsigned char far *sprite_data; // pointer to sprite data
  1071. unsigned char far *dest_buffer; // pointer to destination buffer
  1072.  
  1073. int x,y,                        // looping variables
  1074.     width,                      // width of sprite
  1075.     height;                     // height of sprite
  1076.  
  1077. unsigned char pixel;            // the current pixel being processed
  1078.  
  1079. // alias a pointer to sprite for ease of access
  1080.  
  1081. sprite_data = sprite->frames[sprite->curr_frame];
  1082.  
  1083. // alias a variable to sprite size
  1084.  
  1085. width  = sprite->width;
  1086. height = sprite->height;
  1087.  
  1088. // compute number of bytes between adjacent video lines after a row of pixels
  1089. // has been drawn
  1090.  
  1091. // compute offset of sprite in destination buffer
  1092.  
  1093. dest_buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  1094.  
  1095. // copy each line of the sprite data into destination buffer
  1096.  
  1097.  
  1098. if (transparent)
  1099.    {
  1100.    for (y=0; y<height; y++)
  1101.        {
  1102.        // copy the next row into the destination buffer
  1103.  
  1104.        for (x=0; x<width; x++)
  1105.            {
  1106.  
  1107.            // test for transparent pixel i.e. 0, if not transparent then draw
  1108.  
  1109.            if ((pixel=sprite_data[x]))
  1110.                 dest_buffer[x] = pixel;
  1111.  
  1112.            } // end for x
  1113.  
  1114.        // move to next line in desintation buffer and sprite image buffer
  1115.  
  1116.        dest_buffer += SCREEN_WIDTH;
  1117.        sprite_data += width;
  1118.  
  1119.        } // end for y
  1120.  
  1121.    } // end if transparent
  1122. else
  1123.    {
  1124.    // draw sprite with transparency off
  1125.  
  1126.    for (y=0; y<height; y++)
  1127.        {
  1128.        // copy the next row into the destination buffer
  1129.  
  1130.        _fmemcpy((void far *)dest_buffer,(void far *)sprite_data,width);
  1131.  
  1132.        // move to next line in desintation buffer and sprite image buffer
  1133.  
  1134.        dest_buffer += SCREEN_WIDTH;
  1135.        sprite_data += width;
  1136.  
  1137.        } // end for y
  1138.  
  1139.    } // end else
  1140.  
  1141. } // end Sprite_Draw
  1142.  
  1143.  
  1144. ////////////////////////////////////////////////////////////////////////////////
  1145.  
  1146. void Sprite_Under_Clip(sprite_ptr sprite, unsigned char far *buffer)
  1147. {
  1148.  
  1149. // this function scans the background under a sprite, but only those
  1150. // portions that are visible
  1151.  
  1152. unsigned char far *back_buffer;   // pointer to sprite background buffer
  1153. unsigned char far *source_buffer; // pointer to source buffer
  1154.  
  1155. int y,                        // looping variables
  1156.     sx,sy,                      // position of sprite
  1157.     width,                      // width of sprite
  1158.     bitmap_width  =0,           // width and height of sub-bitmap
  1159.     bitmap_height =0;
  1160.  
  1161. //unsigned char pixel;            // the current pixel being processed
  1162.  
  1163. // alias a variable to sprite size
  1164.  
  1165. width         = sprite->width;
  1166. bitmap_width  = width;
  1167. bitmap_height = sprite->height;
  1168. sx            = sprite->x;
  1169. sy            = sprite->y;
  1170.  
  1171. // perform trivial rejection tests
  1172.  
  1173. if (sx >= (int)SCREEN_WIDTH || sy >= (int)double_buffer_height ||
  1174.    (sx+width) <= 0          || (sy+bitmap_height) <= 0)
  1175.    {
  1176.    // sprite is totally invisible therefore don't scan
  1177.  
  1178.    // set invisible flag in strucuture so that the draw sub-function
  1179.    // doesn't do anything
  1180.  
  1181.    sprite->visible = 0;
  1182.  
  1183.    return;
  1184.  
  1185.    } // end if invisible
  1186.  
  1187. // the sprite background region must be clipped before scanning
  1188. // therefore compute visible portion
  1189.  
  1190. // first compute upper left hand corner of clipped sprite background
  1191.  
  1192. if (sx<0)
  1193.    {
  1194.  
  1195.    bitmap_width += sx;
  1196.    sx            = 0;
  1197.  
  1198.  
  1199.    } // end off left edge
  1200. else
  1201. if (sx+width>=(int)SCREEN_WIDTH)
  1202.    {
  1203.  
  1204.    bitmap_width  = (int)SCREEN_WIDTH-sx;
  1205.  
  1206.    } // end off right edge
  1207.  
  1208. // now process y
  1209.  
  1210. if (sy<0)
  1211.    {
  1212.  
  1213.    bitmap_height += sy;
  1214.    sy             = 0;
  1215.  
  1216.    } // end off top edge
  1217. else
  1218. if (sy+bitmap_height>=(int)double_buffer_height)
  1219.    {
  1220.  
  1221.    bitmap_height  = (int)double_buffer_height - sy;
  1222.  
  1223.    } // end off lower edge
  1224.  
  1225. // this point we know were to start scanning the bitmap i.e.
  1226. // sx,sy
  1227. // and we know the size of the bitmap to be scanned i.e.
  1228. // width,height, so plug it all into the rest of function
  1229.  
  1230. // compute number of bytes between adjacent video lines after a row of pixels
  1231. // has been drawn
  1232.  
  1233. // compute offset of sprite background in source buffer
  1234.  
  1235. source_buffer = buffer + (sy << 8) + (sy << 6) + sx;
  1236.  
  1237. // alias a pointer to sprite background
  1238.  
  1239. back_buffer = sprite->background;
  1240.  
  1241. for (y=0; y<bitmap_height; y++)
  1242.     {
  1243.     // copy the next row into the destination buffer
  1244.  
  1245.     _fmemcpy((void far *)back_buffer,(void far *)source_buffer,bitmap_width);
  1246.  
  1247.     // move to next line in desintation buffer and sprite image buffer
  1248.  
  1249.     source_buffer += SCREEN_WIDTH;
  1250.     back_buffer   += width;  // note this width is the actual width of the
  1251.                              // entire bitmap NOT the visible portion
  1252.     } // end for y
  1253.  
  1254. // set variables in strucuture so that the erase sub-function can operate
  1255. // faster
  1256.  
  1257. sprite->x_clip      = sx;
  1258. sprite->y_clip      = sy;
  1259. sprite->width_clip  = bitmap_width;
  1260. sprite->height_clip = bitmap_height;
  1261. sprite->visible     = 1;
  1262.  
  1263. } // end Sprite_Under_Clip
  1264.  
  1265. //////////////////////////////////////////////////////////////////////////////
  1266.  
  1267. void Sprite_Erase_Clip(sprite_ptr sprite,unsigned char far *buffer)
  1268. {
  1269. // replace the background that was behind the sprite
  1270. // this function replaces the background that was saved from where a sprite
  1271. // was going to be placed
  1272.  
  1273. unsigned char far *back_buffer; // background buffer for sprite
  1274.  
  1275. int y,                          // current line being scanned
  1276.     width,                      // size of sprite background buffer
  1277.     bitmap_height,              // size of clipped bitmap
  1278.     bitmap_width;
  1279.  
  1280. // make sure sprite was visible
  1281.  
  1282. if (!sprite->visible)
  1283.    return;
  1284.  
  1285. // alias a pointer to sprite background for ease of access
  1286.  
  1287. back_buffer = sprite->background;
  1288.  
  1289. // alias width and height
  1290.  
  1291. bitmap_width  = sprite->width_clip;
  1292. bitmap_height = sprite->height_clip;
  1293. width         = sprite->width;
  1294.  
  1295. // compute offset in destination buffer
  1296.  
  1297. buffer = buffer + (sprite->y_clip << 8) + (sprite->y_clip << 6)
  1298.                 + sprite->x_clip;
  1299.  
  1300. for (y=0; y<bitmap_height; y++)
  1301.     {
  1302.     // copy the next row from sprite background buffer to destination buffer
  1303.  
  1304.     _fmemcpy((void far *)buffer,
  1305.              (void far *)back_buffer,
  1306.              bitmap_width);
  1307.  
  1308.     // move to next line in destination buffer and in sprite background buffer
  1309.  
  1310.     buffer      += SCREEN_WIDTH;
  1311.     back_buffer += width;
  1312.  
  1313.     } // end for y
  1314.  
  1315. } // end Sprite_Erase_Clip
  1316.  
  1317. //////////////////////////////////////////////////////////////////////////////
  1318.  
  1319. void Sprite_Draw_Clip(sprite_ptr sprite, unsigned char far *buffer,int transparent)
  1320. {
  1321.  
  1322. // this function draws a sprite on the screen row by row very quickly
  1323. // note the use of shifting to implement multplication
  1324. // if the transparent flag is true then pixels wil be draw one by one
  1325. // else a memcpy will be used to draw each line
  1326. // this function also performs clipping. It will test if the sprite
  1327. // is totally visible/invisible and will only draw the portions that are visible
  1328.  
  1329. unsigned char far *sprite_data; // pointer to sprite data
  1330. unsigned char far *dest_buffer; // pointer to destination buffer
  1331.  
  1332. int x,y,                        // looping variables
  1333.     sx,sy,                      // position of sprite
  1334.     width,                      // width of sprite
  1335.     bitmap_x      =0,           // starting upper left corner of sub-bitmap
  1336.     bitmap_y      =0,           // to be drawn after clipping
  1337.     bitmap_width  =0,           // width and height of sub-bitmap
  1338.     bitmap_height =0;
  1339.  
  1340. unsigned char pixel;            // the current pixel being processed
  1341.  
  1342. // alias a variable to sprite size
  1343.  
  1344. width         = sprite->width;
  1345. bitmap_width  = width;
  1346. bitmap_height = sprite->height;
  1347. sx            = sprite->x;
  1348. sy            = sprite->y;
  1349.  
  1350. // perform trivial rejection tests
  1351.  
  1352. if (sx >= (int)SCREEN_WIDTH || sy >= (int)double_buffer_height ||
  1353.    (sx+width) <= 0          || (sy+bitmap_height) <= 0 || !sprite->visible)
  1354.    {
  1355.    // sprite is totally invisible therefore don't draw
  1356.  
  1357.    // set invisible flag in strucuture so that the erase sub-function
  1358.    // doesn't do anything
  1359.  
  1360.    sprite->visible = 0;
  1361.  
  1362.    return;
  1363.  
  1364.    } // end if invisible
  1365.  
  1366. // the sprite needs some clipping or no clipping at all, so compute
  1367. // visible portion of sprite rectangle
  1368.  
  1369. // first compute upper left hand corner of clipped sprite
  1370.  
  1371. if (sx<0)
  1372.    {
  1373.  
  1374.    bitmap_x      = -sx;
  1375.    sx            = 0;
  1376.    bitmap_width -= bitmap_x;
  1377.  
  1378.    } // end off left edge
  1379. else
  1380. if (sx+width>=(int)SCREEN_WIDTH)
  1381.    {
  1382.  
  1383.    bitmap_x      = 0;
  1384.    bitmap_width  = (int)SCREEN_WIDTH-sx;
  1385.  
  1386.    } // end off right edge
  1387.  
  1388. // now process y
  1389.  
  1390. if (sy<0)
  1391.    {
  1392.  
  1393.    bitmap_y       = -sy;
  1394.    sy             = 0;
  1395.    bitmap_height -= bitmap_y;
  1396.  
  1397.    } // end off top edge
  1398. else
  1399. if (sy+bitmap_height>=(int)double_buffer_height)
  1400.    {
  1401.  
  1402.    bitmap_y       = 0;
  1403.    bitmap_height  = (int)double_buffer_height - sy;
  1404.  
  1405.    } // end off lower edge
  1406.  
  1407. // this point we know were to start drawing the bitmap i.e.
  1408. // sx,sy
  1409. // and we know were in the data to extract the bitmap i.e.
  1410. // bitmap_x, bitmap_y,
  1411. // and finaly we know the size of the bitmap to be drawn i.e.
  1412. // width,height, so plug it all into the rest of function
  1413.  
  1414. // compute number of bytes between adjacent video lines after a row of pixels
  1415. // has been drawn
  1416.  
  1417. // compute offset of sprite in destination buffer
  1418.  
  1419. dest_buffer = buffer + (sy << 8) + (sy << 6) + sx;
  1420.  
  1421. // alias a pointer to sprite for ease of access and locate starting sub
  1422. // bitmap that will be drawn
  1423.  
  1424. sprite_data = sprite->frames[sprite->curr_frame] + (bitmap_y*width) + bitmap_x;
  1425.  
  1426. // copy each line of the sprite data into destination buffer
  1427.  
  1428. if (transparent)
  1429.    {
  1430.    for (y=0; y<bitmap_height; y++)
  1431.        {
  1432.        // copy the next row into the destination buffer
  1433.  
  1434.        for (x=0; x<bitmap_width; x++)
  1435.            {
  1436.  
  1437.            // test for transparent pixel i.e. 0, if not transparent then draw
  1438.  
  1439.            if ((pixel=sprite_data[x]))
  1440.                 dest_buffer[x] = pixel;
  1441.  
  1442.            } // end for x
  1443.  
  1444.        // move to next line in desintation buffer and sprite image buffer
  1445.  
  1446.        dest_buffer += SCREEN_WIDTH;
  1447.        sprite_data += width;   // note this width is the actual width of the
  1448.                                // entire bitmap NOT the visible portion
  1449.        } // end for y
  1450.  
  1451.    } // end if transparent
  1452. else
  1453.    {
  1454.    // draw sprite with transparency off
  1455.  
  1456.    for (y=0; y<bitmap_height; y++)
  1457.        {
  1458.        // copy the next row into the destination buffer
  1459.  
  1460.        _fmemcpy((void far *)dest_buffer,(void far *)sprite_data,bitmap_width);
  1461.  
  1462.        // move to next line in desintation buffer and sprite image buffer
  1463.  
  1464.        dest_buffer += SCREEN_WIDTH;
  1465.        sprite_data += width;  // note this width is the actual width of the
  1466.                               // entire bitmap NOT the visible portion
  1467.        } // end for y
  1468.  
  1469.    } // end else
  1470.  
  1471. // set variables in strucuture so that the erase sub-function can operate
  1472. // faster
  1473.  
  1474. sprite->x_clip      = sx;
  1475. sprite->y_clip      = sy;
  1476. sprite->width_clip  = bitmap_width;
  1477. sprite->height_clip = bitmap_height;
  1478. sprite->visible     = 1;
  1479.  
  1480. } // end Sprite_Draw_Clip
  1481.  
  1482.  
  1483. //////////////////////////////////////////////////////////////////////////////
  1484.  
  1485. int Sprites_Collide(sprite_ptr sprite_1, sprite_ptr sprite_2)
  1486. {
  1487. // this function tests if two sprites have intersected by testing their
  1488. // bounding boxes for collision
  1489.  
  1490. return(0);
  1491.  
  1492. } // end Sprites_Collide
  1493.  
  1494. ///////////////////////////////////////////////////////////////////////////////
  1495.  
  1496. void Display_Double_Buffer(unsigned char far *buffer,int y)
  1497. {
  1498. // this functions copies the double buffer into the video buffer at the
  1499. // starting y location
  1500.  
  1501. #pragma aux Display_da_double_buffer = \
  1502.    "push ds"                     \
  1503.    "mov cx,double_buffer_size"   \
  1504.    "les di,video_buffer"         \
  1505.    "mov ax,320"                  \
  1506.    "mul y"                       \
  1507.    "add di,ax"                   \
  1508.    "lds si,buffer"               \
  1509.    "rep movsw"                   \
  1510.    "pop ds"                      \
  1511.    modify [cx es di ax si];
  1512.  
  1513. Display_da_double_buffer();
  1514.  
  1515. /*
  1516. _asm
  1517.    {
  1518.    push ds                     ; save DS on stack
  1519.    mov cx,double_buffer_size   ; this is the size of buffer in WORDS
  1520.    les di,video_buffer         ; es:di is destination of memory move
  1521.  
  1522.    mov ax,320                  ; multiply y by 320 i.e. screen width
  1523.    mul y
  1524.    add di,ax                   ; add result to es:di
  1525.  
  1526.    lds si,buffer               ; ds:si is source of memory move
  1527.    rep movsw                   ; move all the words
  1528.    pop ds                      ; restore the data segment
  1529.    } // end asm
  1530. */
  1531. } // end Display_Double_Buffer
  1532.  
  1533. //////////////////////////////////////////////////////////////////////////////
  1534.  
  1535. int Create_Double_Buffer(int num_lines)
  1536. {
  1537.  
  1538. // allocate enough memory to hold the double buffer
  1539.  
  1540. if ((double_buffer = (unsigned char far *)_fmalloc(SCREEN_WIDTH * (num_lines + 1)))==NULL)
  1541.    {
  1542.    printf("\nCouldn't allocate double buffer.");
  1543.    return(0);
  1544.    } // end if couldn't allocate
  1545.  
  1546. // set the height of the buffer and compute it's size
  1547.  
  1548. double_buffer_height = num_lines;
  1549.  
  1550. double_buffer_size = SCREEN_WIDTH * num_lines/2;
  1551.  
  1552. // fill the buffer with black
  1553.  
  1554. _fmemset(double_buffer, 0, SCREEN_WIDTH * num_lines);
  1555.  
  1556. // everything was ok
  1557.  
  1558. return(1);
  1559.  
  1560. } // end Init_Double_Buffer
  1561.  
  1562. ///////////////////////////////////////////////////////////////////////////////
  1563.  
  1564. void Fill_Double_Buffer(int color)
  1565. {
  1566. // this function fills in the double buffer with the sent color a WORD at
  1567. // a time
  1568.  
  1569. #pragma aux Fill_da_double_buffer = \
  1570.    "mov cx,double_buffer_size" \
  1571.    "mov al, BYTE PTR color"    \
  1572.    "mov ah,al"                 \
  1573.    "les di,double_buffer"      \
  1574.    "rep stosw"                 \
  1575.    modify [cx ax di];
  1576.  
  1577. Fill_da_double_buffer();
  1578.  
  1579. /*
  1580. _asm
  1581.    {
  1582.    mov cx,double_buffer_size ; this is the size of buffer in WORDS
  1583.    mov al, BYTE PTR color    ; move the color into al
  1584.    mov ah,al                 ; move the color in ah
  1585.    les di,double_buffer      ; es:di points to the double buffer
  1586.    rep stosw                 ; fill all the words
  1587.    } // end asm
  1588. */
  1589. } // end Fill_Double_Buffer
  1590.  
  1591. //////////////////////////////////////////////////////////////////////////////
  1592.  
  1593. void Delete_Double_Buffer(void)
  1594. {
  1595. // this function free's up the memory allocated by the double buffer
  1596. // make sure to use FAR version
  1597.  
  1598. if (double_buffer)
  1599.   _ffree(double_buffer);
  1600.  
  1601. } // end Delete_Double_Buffer
  1602.  
  1603. ///////////////////////////////////////////////////////////////////////////////
  1604.  
  1605. void Screen_Transition(int effect)
  1606. {
  1607. // this function can be called to perform a myraid of screen transitions
  1608. // to the video buffer, note I have left one for you to create!
  1609.  
  1610. int pal_reg;       //  used as loop counter
  1611. long index;        // used as loop counter
  1612. RGB_color color;   // temporary color
  1613.  
  1614. // test which screen effect is being selected
  1615.  
  1616. switch(effect)
  1617.       {
  1618.  
  1619.       case SCREEN_DARKNESS:
  1620.            {
  1621.            // fade to black
  1622.  
  1623.            for (index=0; index<10; index++)
  1624.                {
  1625.                // loop thru all palette registers
  1626.  
  1627.                for (pal_reg=0; pal_reg<256; pal_reg++)
  1628.                    {
  1629.                    // get the next color to fade
  1630.  
  1631.                    Read_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  1632.  
  1633.                    // test if this color regisyer is already black
  1634.  
  1635.                    if (color.red > 6) color.red-=6;
  1636.                    else
  1637.                       color.red = 0;
  1638.  
  1639.                    if (color.green > 6) color.green-=6;
  1640.                    else
  1641.                       color.green = 0;
  1642.  
  1643.                    if (color.blue  > 6) color.blue-=6;
  1644.                    else
  1645.                       color.blue = 0;
  1646.  
  1647.                    // set the color to a diminished intensity
  1648.  
  1649.                    Write_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  1650.  
  1651.                    } // end for pal_reg
  1652.  
  1653.                // wait a bit
  1654.  
  1655.                Time_Delay(1);
  1656.  
  1657.                } // end for index
  1658.  
  1659.            } break;
  1660.  
  1661.       case SCREEN_WHITENESS:
  1662.            {
  1663.            // fade to white
  1664.  
  1665.            for (index=0; index<20; index++)
  1666.                {
  1667.  
  1668.                // loop thru all palette registers
  1669.  
  1670.                for (pal_reg=0; pal_reg<256; pal_reg++)
  1671.                    {
  1672.                    // get the color to fade
  1673.  
  1674.                    Read_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  1675.  
  1676.                    color.red+=4;
  1677.  
  1678.                    if (color.red > 63)
  1679.                       color.red = 63;
  1680.  
  1681.                    color.green+=4;
  1682.  
  1683.                    if (color.green > 63)
  1684.                       color.green = 63;
  1685.  
  1686.                    color.blue+=4;
  1687.  
  1688.                    if (color.blue >63)
  1689.                       color.blue = 63;
  1690.  
  1691.                    // set the color to a brightend intensity
  1692.  
  1693.                    Write_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  1694.  
  1695.                    } // end for pal_reg
  1696.  
  1697.                // wait a bit
  1698.  
  1699.                Time_Delay(1);
  1700.  
  1701.                } // end for index
  1702.  
  1703.            } break;
  1704.  
  1705.  
  1706.       case SCREEN_WARP:
  1707.            {
  1708.  
  1709.            // this one you do!!!!
  1710.  
  1711.            } break;
  1712.  
  1713.       case SCREEN_SWIPE_X:
  1714.            {
  1715.            // do a screen wipe from right to left, left to right
  1716.  
  1717.            for (index=0; index<160; index+=2)
  1718.                {
  1719.  
  1720.                // use this as a 1/70th of second time delay
  1721.  
  1722.                Wait_For_Vertical_Retrace();
  1723.  
  1724.                // draw two vertical lines at opposite ends of the screen
  1725.  
  1726.                Line_V(0,199,319-index,0);
  1727.                Line_V(0,199,index,0);
  1728.                Line_V(0,199,319-(index+1),0);
  1729.                Line_V(0,199,index+1,0);
  1730.  
  1731.                } // end for index
  1732.  
  1733.            } break;
  1734.  
  1735.       case SCREEN_SWIPE_Y:
  1736.            {
  1737.  
  1738.            // do a screen wipe from top to bottom, bottom to top
  1739.  
  1740.            for (index=0; index<100; index+=2)
  1741.                {
  1742.  
  1743.                // use this as a 1/70th of second time delay
  1744.  
  1745.                Wait_For_Vertical_Retrace();
  1746.  
  1747.                // draw two horizontal lines at opposite ends of the screen
  1748.  
  1749.                Line_H(0,319,199-index,0);
  1750.                Line_H(0,319,index,0);
  1751.                Line_H(0,319,199-(index+1),0);
  1752.                Line_H(0,319,index+1,0);
  1753.  
  1754.                } // end for index
  1755.  
  1756.            } break;
  1757.  
  1758.  
  1759.       case SCREEN_DISOLVE:
  1760.            {
  1761.            // disolve the screen by plotting zillions of little black dots
  1762.  
  1763.            for (index=0; index<=300000; index++)
  1764.                 Write_Pixel(rand()%320,rand()%200, 0);
  1765.  
  1766.            } break;
  1767.  
  1768.       default:break;
  1769.  
  1770.       } // end switch
  1771.  
  1772. } // end Screen_Transition
  1773.  
  1774. //////////////////////////////////////////////////////////////////////////////////
  1775.  
  1776. void Wait_For_Vertical_Retrace(void)
  1777. {
  1778. // this function waits for the start of a vertical retrace, if a vertical
  1779. // retrace is in progress then it waits until the next one
  1780. // therefore the function can wait a maximum of 2/70 th's of a second
  1781. // before returning
  1782. // this function can be used to synchronize video updates to the vertical blank
  1783. // or as a high resolution time reference
  1784.  
  1785. while(inp(VGA_INPUT_STATUS_1) & VGA_VRETRACE_MASK)
  1786.      {
  1787.      // do nothing, vga is already in retrace
  1788.      } // end while
  1789.  
  1790. // now wait for start of vertical retrace and exit
  1791.  
  1792. while(!(inp(VGA_INPUT_STATUS_1) & VGA_VRETRACE_MASK))
  1793.      {
  1794.      // do nothing, wait for start of retrace
  1795.      } // end while
  1796.  
  1797. // at this point a vertical retrace is occuring, so return back to caller
  1798.  
  1799. } // end Wait_For_Vertical_Retrace
  1800.  
  1801. ///////////////////////////////////////////////////////////////////////////////
  1802. /*
  1803. void fwordcpy(void far *destination, void far *source,int num_words)
  1804. {
  1805. // this function is similar to fmemcpy except that is moves data in words
  1806. // it is about 25% faster than memcpy which uses bytes
  1807.  
  1808. #pragma aux copy_da_fword = \
  1809.    "push ds"              \
  1810.    "les di,destination"   \
  1811.    "lds si,source"        \
  1812.    "mov cx,num_words"     \
  1813.    "rep movsw"            \
  1814.    "pop ds"               \
  1815.    modify [ds di si cx];
  1816.  
  1817. copy_da_fword();
  1818.  
  1819.  
  1820. _asm
  1821.    {
  1822.    push ds              ; need to save segment registers i.e. ds
  1823.    les di,destination   ; point es:di to destination of memory move
  1824.    lds si,source        ; point ds:si to source of memory move
  1825.    mov cx,num_words     ; move into cx the number of words to be moved
  1826.    rep movsw            ; let the processor do the memory move
  1827.    pop ds               ; restore the ds segment register
  1828.  
  1829.    } // end inline asm
  1830.  
  1831. } // end fwordcpy
  1832. */
  1833. //////////////////////////////////////////////////////////////////////////////
  1834.  
  1835. void Bitmap_Put(bitmap_ptr image, unsigned char far *destination,int transparent)
  1836. {
  1837. // this fucntion will draw a bitmap on the destination buffer which could
  1838. // be a double buffer or the video buffer
  1839.  
  1840. int x,y,                        // looping variables
  1841.     width,height;               // size of bitmap
  1842.  
  1843. unsigned char far *bitmap_data; // pointer to bitmap buffer
  1844. unsigned char far *dest_buffer; // pointer to destination buffer
  1845.  
  1846. unsigned char pixel;            // current pixel value being processed
  1847.  
  1848. // compute offset of bitmap in destination buffer. note: all video or double
  1849. // buffers must be 320 bytes wide!
  1850.  
  1851. dest_buffer = destination + (image->y << 8) + (image->y << 6) + image->x;
  1852.  
  1853. // create aliases to variables so the strucuture doesn't need to be
  1854. // dereferenced continually
  1855.  
  1856. height      = image->height;
  1857. width       = image->width;
  1858. bitmap_data = image->buffer;
  1859.  
  1860. // test if transparency is on or off
  1861.  
  1862. if (transparent)
  1863.    {
  1864.    // use version that will draw a transparent bitmap(slighlty slower)
  1865.  
  1866.    // draw each line of the bitmap
  1867.  
  1868.    for (y=0; y<height; y++)
  1869.        {
  1870.        // copy the next row into the destination buffer
  1871.  
  1872.        for (x=0; x<width; x++)
  1873.            {
  1874.  
  1875.            // test for transparent pixel i.e. 0, if not transparent then draw
  1876.  
  1877.            if ((pixel=bitmap_data[x]))
  1878.                 dest_buffer[x] = pixel;
  1879.  
  1880.            } // end for x
  1881.  
  1882.        // move to next line in double buffer and in bitmap buffer
  1883.  
  1884.        dest_buffer += SCREEN_WIDTH;
  1885.        bitmap_data += width;
  1886.  
  1887.        } // end for y
  1888.  
  1889.    } // end if transparent
  1890. else
  1891.    {
  1892.  
  1893.    // draw each line of the bitmap, note how each pixel doesn't need to be
  1894.    // tested for transparency hence a memcpy can be used (very fast!)
  1895.  
  1896.    for (y=0; y<height; y++)
  1897.        {
  1898.        // copy the next row into the destination buffer using memcpy for speed
  1899.  
  1900.        _fmemcpy((void far *)dest_buffer,
  1901.                 (void far *)bitmap_data,width);
  1902.  
  1903.        // move to next line in destination buffer and in bitmap buffer
  1904.  
  1905.        dest_buffer += SCREEN_WIDTH;
  1906.        bitmap_data += width;
  1907.  
  1908.        } // end for y
  1909.  
  1910.    } // end else non-transparent version
  1911.  
  1912. } // end Bitmap_Put
  1913.  
  1914. //////////////////////////////////////////////////////////////////////////////
  1915.  
  1916. void Bitmap_Get(bitmap_ptr image, unsigned char far *source)
  1917. {
  1918. // this function will scan a bitmap fomr the source buffer
  1919. // could be a double buffer, video buffer or any other buffer with a
  1920. // logical row width of 320 bytes
  1921.  
  1922. unsigned int source_off,       // offsets into destination and source buffers
  1923.              bitmap_off;
  1924.  
  1925. int y,                         // looping variable
  1926.     width,height;              // size of bitmap
  1927.  
  1928. unsigned char far *bitmap_data; // pointer to bitmap buffer
  1929.  
  1930.  
  1931. // compute offset of bitmap in source buffer. note: all video or double
  1932. // buffers must be 320 bytes wide!
  1933.  
  1934. source_off   = (image->y << 8) + (image->y << 6) + image->x;
  1935.  
  1936. bitmap_off = 0;
  1937.  
  1938. // create aliases to variables so the strucuture doesn't need to be
  1939. // dereferenced continually
  1940.  
  1941. height      = image->height;
  1942. width       = image->width;
  1943. bitmap_data = image->buffer;
  1944.  
  1945. // draw each line of the bitmap, note how each pixel doesn't need to be
  1946. // tested for transparency hence a memcpy can be used (very fast!)
  1947.  
  1948. for (y=0; y<height; y++)
  1949.     {
  1950.     // copy the next row into the bitmap buffer using memcpy for speed
  1951.  
  1952.     _fmemcpy((void far *)&bitmap_data[bitmap_off],
  1953.              (void far *)&source[source_off],width);
  1954.  
  1955.     // move to next line in source buffer and in bitmap buffer
  1956.  
  1957.     source_off += SCREEN_WIDTH;
  1958.     bitmap_off += width;
  1959.  
  1960.     } // end for y
  1961.  
  1962. } // end Bitmap_Get
  1963.  
  1964. //////////////////////////////////////////////////////////////////////////////
  1965.  
  1966. int Bitmap_Allocate(bitmap_ptr image, int width, int height)
  1967. {
  1968. // this function can be used to allocate the memory needed for a bitmap
  1969.  
  1970. if ((image->buffer = (unsigned char far *)_fmalloc(width*height+1))==NULL)
  1971.    return(0);
  1972. else
  1973.    return(1);
  1974.  
  1975. } // end Bitmap_Allocate
  1976.  
  1977. //////////////////////////////////////////////////////////////////////////////
  1978.  
  1979. void Bitmap_Delete(bitmap_ptr the_bitmap)
  1980. {
  1981. // this function deletes the memory used by a bitmap
  1982.  
  1983. if (the_bitmap->buffer)
  1984.    _ffree(the_bitmap->buffer);
  1985.  
  1986. } // end Bitmap_Delete
  1987.  
  1988. //////////////////////////////////////////////////////////////////////////////
  1989.  
  1990. void Layer_Draw(layer_ptr source_layer, int source_x, int source_y,
  1991.                 unsigned char far *dest_buffer,int dest_y,int dest_height,
  1992.                 int transparent)
  1993. {
  1994. // this function will map down a section of the layer onto the destination
  1995. // buffer at the desired location, note the width of the destination buffer
  1996. // is always assumed to be 320 bytes width. Also, the function will always
  1997. // wrap around the layer
  1998.  
  1999. int x,y,                        // looping variables
  2000.     layer_width,                // the width of the layer
  2001.     right_width,                // the width of the right and left half of
  2002.     left_width;                 // the layer to be drawn
  2003.  
  2004. unsigned char far *layer_buffer_l; // pointers to the left and right halves
  2005. unsigned char far *dest_buffer_l;  // of the layer buffer and destination
  2006. unsigned char far *layer_buffer_r; // buffer
  2007. unsigned char far *dest_buffer_r;
  2008.  
  2009. unsigned char pixel;            // current pixel value being processed
  2010.  
  2011. layer_width = source_layer->width;
  2012.  
  2013. dest_buffer_l  = dest_buffer + (dest_y << 8) + (dest_y << 6);
  2014.  
  2015. layer_buffer_l = source_layer->buffer + layer_width*source_y + source_x;
  2016.  
  2017. // test if wraping is needed
  2018.  
  2019. if ( ( (layer_width-source_x)-(int)SCREEN_WIDTH ) >= 0)
  2020.    {
  2021.    // there's enough data in layer to draw a complete line, no wraping needed
  2022.  
  2023.    left_width  = SCREEN_WIDTH;
  2024.  
  2025.    right_width = 0; // no wraping flag
  2026.  
  2027.    }
  2028. else
  2029.    {
  2030.    // wrapping needed
  2031.  
  2032.    left_width  = layer_width - source_x;
  2033.  
  2034.    right_width = SCREEN_WIDTH - left_width;
  2035.  
  2036.    dest_buffer_r  = dest_buffer_l + left_width;
  2037.  
  2038.    layer_buffer_r = layer_buffer_l - source_x; // move to far left end of layer
  2039.  
  2040.    } // end else need to wrap
  2041.  
  2042. // test if transparency is on or off
  2043.  
  2044. if (transparent)
  2045.    {
  2046.    // use version that will draw a transparent bitmap(slighlty slower)
  2047.    // first draw left half then right half
  2048.  
  2049.    // draw each line of the bitmap
  2050.  
  2051.    for (y=0; y<dest_height; y++)
  2052.        {
  2053.        // copy the next row into the destination buffer
  2054.  
  2055.        for (x=0; x<left_width; x++)
  2056.            {
  2057.  
  2058.            // test for transparent pixel i.e. 0, if not transparent then draw
  2059.  
  2060.            if ((pixel=layer_buffer_l[x]))
  2061.                 dest_buffer_l[x] = pixel;
  2062.  
  2063.            } // end for x
  2064.  
  2065.        // move to next line in destination buffer and in layer buffer
  2066.  
  2067.        dest_buffer_l  += SCREEN_WIDTH;
  2068.        layer_buffer_l += layer_width;
  2069.  
  2070.        } // end for y
  2071.  
  2072.    // now right half
  2073.  
  2074.    // draw each line of the bitmap
  2075.  
  2076.    if (right_width)
  2077.       {
  2078.       for (y=0; y<dest_height; y++)
  2079.           {
  2080.           // copy the next row into the destination buffer
  2081.  
  2082.           for (x=0; x<right_width; x++)
  2083.               {
  2084.  
  2085.               // test for transparent pixel i.e. 0, if not transparent then draw
  2086.  
  2087.               if ((pixel=layer_buffer_r[x]))
  2088.                    dest_buffer_r[x] = pixel;
  2089.  
  2090.               } // end for x
  2091.  
  2092.           // move to next line in destination buffer and in layer buffer
  2093.  
  2094.           dest_buffer_r  += SCREEN_WIDTH;
  2095.           layer_buffer_r += layer_width;
  2096.  
  2097.           } // end for y
  2098.  
  2099.       } // end if right side needs to be drawn
  2100.  
  2101.    } // end if transparent
  2102. else
  2103.    {
  2104.  
  2105.    // draw each line of the bitmap, note how each pixel doesn't need to be
  2106.    // tested for transparency hence a memcpy can be used (very fast!)
  2107.  
  2108.    for (y=0; y<dest_height; y++)
  2109.        {
  2110.        // copy the next row into the destination buffer using memcpy for speed
  2111.  
  2112.        _fmemcpy((void far *)dest_buffer_l,
  2113.                 (void far *)layer_buffer_l,left_width);
  2114.  
  2115.        // move to next line in double buffer and in bitmap buffer
  2116.  
  2117.        dest_buffer_l  += SCREEN_WIDTH;
  2118.        layer_buffer_l += layer_width;
  2119.  
  2120.        } // end for y
  2121.  
  2122.    // now right half if needed
  2123.  
  2124.    if (right_width)
  2125.       {
  2126.  
  2127.       for (y=0; y<dest_height; y++)
  2128.           {
  2129.           // copy the next row into the destination buffer using memcpy for speed
  2130.  
  2131.           _fmemcpy((void far *)dest_buffer_r,
  2132.                    (void far *)layer_buffer_r,right_width);
  2133.  
  2134.           // move to next line in double buffer and in bitmap buffer
  2135.  
  2136.           dest_buffer_r  += SCREEN_WIDTH;
  2137.           layer_buffer_r += layer_width;
  2138.  
  2139.           } // end for y
  2140.  
  2141.       } // end if right half
  2142.  
  2143.    } // end else non-transparent version
  2144.  
  2145. } // end Layer_Draw
  2146.  
  2147. //////////////////////////////////////////////////////////////////////////////
  2148.  
  2149. void Layer_Build(layer_ptr dest_layer,int dest_x, int dest_y,
  2150.                  unsigned char far *source_buffer,int source_x,int source_y,
  2151.                  int width,int height)
  2152. {
  2153. // this function is used to build up the layer out of smaller pieces
  2154. // this allows a layer to be very long, tall etc. also the source data buffer
  2155. // must be constructed such that there are 320 bytes per row
  2156.  
  2157. int y,                       // looping variable
  2158.     layer_width;             // the width of the layer
  2159.  
  2160. unsigned char far *source_data;   // pointer to start of source bitmap image
  2161. unsigned char far *layer_buffer;  // pointer to layer buffer
  2162.  
  2163. // extract width of layer
  2164.  
  2165. layer_width  = dest_layer->width;
  2166.  
  2167. // compute starting location in layer buffer
  2168.  
  2169. layer_buffer = dest_layer->buffer + layer_width*dest_y + dest_x; ;
  2170.  
  2171. // compute starting location in source image buffer
  2172.  
  2173. source_data = source_buffer + (source_y << 8) + (source_y << 6) + source_x;
  2174.  
  2175. // scan each line of source image into layer buffer
  2176.  
  2177. for (y=0; y<height; y++)
  2178.     {
  2179.     // copy the next row into the layer buffer using memcpy for speed
  2180.  
  2181.     _fmemcpy((void far *)layer_buffer,
  2182.              (void far *)source_data,width);
  2183.  
  2184.     // move to next line in source buffer and in layer buffer
  2185.  
  2186.     source_data  += SCREEN_WIDTH;
  2187.     layer_buffer += layer_width;
  2188.  
  2189.     } // end for y
  2190.  
  2191. } // end Layer_Build
  2192.  
  2193. //////////////////////////////////////////////////////////////////////////////
  2194.  
  2195. int Layer_Create(layer_ptr dest_layer, int width, int height)
  2196. {
  2197. // this function can be used to allocate the memory needed for a layer
  2198. // the width must be divisible by two.
  2199.  
  2200. if ((dest_layer->buffer = (unsigned char far *)_fmalloc(width*height+2))==NULL)
  2201.    return(0);
  2202. else
  2203.    {
  2204.    // save the dimensions of layer
  2205.  
  2206.    dest_layer->width  = width;
  2207.    dest_layer->height = height;
  2208.  
  2209.    return(1);
  2210.  
  2211.    } // end else
  2212.  
  2213. } // end Layer_Create
  2214.  
  2215. //////////////////////////////////////////////////////////////////////////////
  2216.  
  2217. void Layer_Delete(layer_ptr the_layer)
  2218. {
  2219. // this function deletes the memory used by a layer
  2220.  
  2221. if (the_layer->buffer)
  2222.    _ffree(the_layer->buffer);
  2223.  
  2224. } // end Layer_Delete
  2225.  
  2226. //////////////////////////////////////////////////////////////////////////////
  2227.  
  2228. void Print_Char_DB(int xc,int yc,char c,int color,int transparent)
  2229. {
  2230. // this function is used to print a character on the double buffer. It uses the
  2231. // internal 8x8 character set to do this. Note that each character is
  2232. // 8 bytes where each byte represents the 8 pixels that make up the row
  2233. // of pixels
  2234.  
  2235. int offset,               // offset into video memory
  2236.          x,               // loop variable
  2237.          y;               // loop variable
  2238.  
  2239. unsigned char far *work_char; // pointer to character being printed
  2240.  
  2241. unsigned char bit_mask;       // bitmask used to extract proper bit
  2242.  
  2243. // compute starting offset in rom character lookup table
  2244. // multiple the character by 8 and add the result to the starting address
  2245. // of the ROM character set
  2246.  
  2247. work_char = rom_char_set + c * ROM_CHAR_HEIGHT;
  2248.  
  2249. // compute offset of character in double buffer, use shifting to multiply
  2250.  
  2251. offset = (yc << 8) + (yc << 6) + xc;
  2252.  
  2253. // draw the character row by row
  2254.  
  2255. for (y=0; y<ROM_CHAR_HEIGHT; y++)
  2256.     {
  2257.     // reset bit mask
  2258.  
  2259.     bit_mask = 0x80;
  2260.  
  2261.     // draw each pixel of this row
  2262.  
  2263.     for (x=0; x<ROM_CHAR_WIDTH; x++)
  2264.         {
  2265.         // test for transparent pixel i.e. 0, if not transparent then draw
  2266.  
  2267.         if ((*work_char & bit_mask))
  2268.              double_buffer[offset+x] = (unsigned char)color;
  2269.  
  2270.         else
  2271.         if (!transparent)               // takes care of transparency
  2272.             double_buffer[offset+x] = 0; // make black part opaque
  2273.  
  2274.         // shift bit mask
  2275.  
  2276.         bit_mask = (bit_mask>>1);
  2277.  
  2278.         } // end for x
  2279.  
  2280.     // move to next line in double buffer and in rom character data area
  2281.  
  2282.     offset      += MODE13_WIDTH;
  2283.     work_char++;
  2284.  
  2285.     } // end for y
  2286.  
  2287. } // end Print_Char_DB
  2288.  
  2289. //////////////////////////////////////////////////////////////////////////////
  2290.  
  2291. void Print_String_DB(int x,int y,int color, char *string,int transparent)
  2292. {
  2293. // this function prints an entire string into the double buffer with fixed
  2294. // spacing between each character by calling the Print_Char() function
  2295.  
  2296.  int index,   // loop index
  2297.      length;  // length of string
  2298.  
  2299. // compute length of string
  2300.  
  2301. length = strlen(string);
  2302.  
  2303. // print the string a character at a time
  2304.  
  2305. for (index=0; index<length; index++)
  2306.      Print_Char_DB(x+(index<<3),y,string[index],color,transparent);
  2307.  
  2308. } // end Print_String_DB
  2309.  
  2310. ///////////////////////////////////////////////////////////////////////////////
  2311.  
  2312. void Write_Pixel_DB(int x,int y,int color)
  2313. {
  2314.  
  2315. // plots the pixel in the desired color to the double buffer
  2316. // to accomplish the multiplications
  2317.  
  2318. // use the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  2319.  
  2320. double_buffer[((y<<8) + (y<<6)) + x] = (unsigned char )color;
  2321.  
  2322. } // end Write_Pixel_DB
  2323.  
  2324. ///////////////////////////////////////////////////////////////////////////////
  2325.  
  2326. int Read_Pixel_DB(int x,int y)
  2327. {
  2328. // this function read a pixel from the double buffer
  2329.  
  2330. // use the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  2331.  
  2332. return((int)(double_buffer[((y<<8) + (y<<6)) + x]));
  2333.  
  2334. } // end Read_Pixel_DB
  2335.  
  2336. //////////////////////////////////////////////////////////////////////////////
  2337.  
  2338. void Set_Visual_Page_Mode_Z(int page)
  2339. {
  2340. // this function sets the visual page that will be displayed by the VGA
  2341.  
  2342. if (page==PAGE_0)
  2343.    {
  2344.    // re-program the start address registers in the CRT controller
  2345.    // to point at page 0 @ 0xA000:0000
  2346.  
  2347.    // first low byte of address
  2348.  
  2349.    outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2350.    outp(CRT_CONTROLLER+1,0x00);
  2351.  
  2352.    // now high byte
  2353.  
  2354.    outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2355.    outp(CRT_CONTROLLER+1,0x00);
  2356.  
  2357.    } // end if page 0
  2358. else
  2359. if (page==PAGE_1)
  2360.    {
  2361.    // re-program the start address registers in the CRT controller
  2362.    // to point at page 1 @ 0xA000:8000
  2363.  
  2364.    // first low byte of address
  2365.  
  2366.    outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2367.    outp(CRT_CONTROLLER+1,0x00);
  2368.  
  2369.    // now high byte
  2370.  
  2371.    outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2372.    outp(CRT_CONTROLLER+1,0x80);
  2373.  
  2374.    } // end else page 1
  2375.  
  2376. // note: we could use WORD out's, but this is clearer, feel free to change them
  2377.  
  2378. } // end Set_Visual_Page_Mode_Z
  2379.  
  2380. ///////////////////////////////////////////////////////////////////////////////
  2381.  
  2382. void Set_Working_Page_Mode_Z(int page)
  2383. {
  2384. // this function sets the page that all mode Z functions will update when
  2385. // called
  2386.  
  2387. if (page==PAGE_0)
  2388.    video_buffer = page_0_buffer;
  2389. else
  2390.    video_buffer = page_1_buffer;
  2391.  
  2392. } // end Set_Working_Page_Mode_Z
  2393.  
  2394.  
  2395. //////////////////////////////////////////////////////////////////////////////
  2396.  
  2397. void Tech_Print(int x,int y, char *string, unsigned char far *destination)
  2398. {
  2399. // this function is used to print text out like a teletypwriter,it looks
  2400. // cool, trust me!
  2401.  
  2402. int length,  // length of input string
  2403.     index;   // looping variable
  2404.  
  2405.  
  2406. char buffer[3];  // a little string used to call font engine with
  2407.  
  2408. // compute length of input string
  2409.  
  2410. length = strlen(string);
  2411.  
  2412. // print the string out a character at a time
  2413.  
  2414. for (index=0; index<length; index++)
  2415.     {
  2416.     // the first character is the actual printable character
  2417.  
  2418.     buffer[0] = string[index];
  2419.  
  2420.     // this is a little cursor kind of thing
  2421.  
  2422.     buffer[1] = '<';
  2423.  
  2424.     // null terminate
  2425.  
  2426.     buffer[2] = 0;
  2427.  
  2428.     // print the string
  2429.  
  2430.     Font_Engine_1(x,y,0,0,buffer,destination);
  2431.  
  2432.     // move to next position
  2433.  
  2434.     x+=(TECH_FONT_WIDTH+1);
  2435.  
  2436.     // wait a bit  1/70th of a second
  2437.  
  2438.     Wait_For_Vertical_Retrace();
  2439.  
  2440.     // clear the cursor
  2441.  
  2442.     } // end for
  2443.  
  2444.     // clear the cursor
  2445.  
  2446.     buffer[0] = ' ';
  2447.     buffer[1] = ' ';
  2448.     buffer[2] = 0;
  2449.  
  2450.     Font_Engine_1(x,y,0,0,buffer,destination);
  2451.  
  2452. // done!
  2453.  
  2454. } // end Tech_Print
  2455.  
  2456. //////////////////////////////////////////////////////////////////////////////
  2457.  
  2458. void Font_Engine_1(int x,int y,
  2459.                    int font,int color,
  2460.                    char *string,unsigned char far *destination)
  2461. {
  2462. // this function prints a string out using one of the graphics fonts that
  2463. // we have drawn, note this first version doesn't use the font field, but
  2464. // we'll throw it in to keep the interface open for a future version
  2465.  
  2466. static int font_loaded=0;   // this is used to track the first time the
  2467.                             // function is loaded
  2468. int index,    // loop index
  2469.     c_index,  // character index
  2470.     length;   // used to compute lengths of strings
  2471.  
  2472. // test if this is the first time this function is called, if so load the
  2473. // font
  2474.  
  2475. if (!font_loaded)
  2476.    {
  2477.  
  2478.    // load the 4x7 tech font
  2479.    PCX_Init((pcx_picture_ptr)&background);
  2480.    PCX_Load("battlfnt.pcx", (pcx_picture_ptr)&background, 0);
  2481.  
  2482.    // allocate memory for each bitmap and load character
  2483.  
  2484.    for (index=0; index<NUM_TECH_FONT; index++)
  2485.        {
  2486.        // allocate memory for charcter
  2487.  
  2488.        Bitmap_Allocate((bitmap_ptr)&tech_font[index],
  2489.                        TECH_FONT_WIDTH,TECH_FONT_HEIGHT);
  2490.  
  2491.        // set size of character
  2492.  
  2493.        tech_font[index].width = TECH_FONT_WIDTH;
  2494.        tech_font[index].height= TECH_FONT_HEIGHT;
  2495.  
  2496.        // extract bitmap from PCX buffer
  2497.  
  2498.        tech_font[index].x = 1 + (index % 16) * (TECH_FONT_WIDTH+1);
  2499.        tech_font[index].y = 1 + (index / 16) * (TECH_FONT_HEIGHT+1);
  2500.  
  2501.        Bitmap_Get((bitmap_ptr)&tech_font[index],
  2502.                   (unsigned char far *)background.buffer);
  2503.  
  2504.        } // end for index
  2505.    // font is loaded, delete pcx file and set flag
  2506.  
  2507.    PCX_Delete((pcx_picture_ptr)&background);
  2508.  
  2509.    font_loaded=1;
  2510.  
  2511.    } // end if first time
  2512. else
  2513.    {
  2514.    // print the sent string
  2515.  
  2516.    // pre-compute length of string
  2517.  
  2518.    length=strlen(string);
  2519.  
  2520.    // print the string character by character
  2521.  
  2522.    for (index=0; index<length; index++)
  2523.        {
  2524.        // extract the character index from the space character
  2525.  
  2526.        c_index = string[index] - ' ';
  2527.  
  2528.        // set bitmap position
  2529.  
  2530.        tech_font[c_index].y = y;
  2531.        tech_font[c_index].x = x;
  2532.  
  2533.        // display bitmap
  2534.  
  2535.        Bitmap_Put((bitmap_ptr)&tech_font[c_index],
  2536.                   (unsigned char far*)destination,0);
  2537.  
  2538.        // move to next character position
  2539.  
  2540.        x+=(TECH_FONT_WIDTH+1);
  2541.  
  2542.        } // end for index
  2543.  
  2544.    } // end else print string
  2545.  
  2546. } // end Font_Engine_1
  2547.  
  2548.  
  2549.