home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / Source / GPCHAP12 / GPDUMB1.CPP < prev    next >
C/C++ Source or Header  |  2002-05-02  |  84KB  |  3,232 lines

  1. // GPDUMB1.CPP - Game Engine Part I
  2.  
  3. // INCLUDES ///////////////////////////////////////////////
  4.  
  5. #define WIN32_LEAN_AND_MEAN  
  6.  
  7. #include <windows.h>   // include important windows stuff
  8. #include <windowsx.h> 
  9. #include <mmsystem.h>
  10. #include <iostream.h> // include important C/C++ stuff
  11. #include <conio.h>
  12. #include <stdlib.h>
  13. #include <malloc.h>
  14. #include <memory.h>
  15. #include <string.h>
  16. #include <stdarg.h>
  17. #include <stdio.h>
  18. #include <math.h>
  19. #include <io.h>
  20. #include <fcntl.h>
  21.  
  22. #include <ddraw.h>  // directX includes
  23. #include "gpdumb1.h"
  24.  
  25. // DEFINES ////////////////////////////////////////////////
  26.  
  27. // TYPES //////////////////////////////////////////////////
  28.  
  29. // PROTOTYPES /////////////////////////////////////////////
  30.  
  31. // EXTERNALS /////////////////////////////////////////////
  32.  
  33. extern HWND main_window_handle; // save the window handle
  34. extern HINSTANCE main_instance; // save the instance
  35.  
  36. // GLOBALS ////////////////////////////////////////////////
  37.  
  38. FILE *fp_error                    = NULL; // general error file
  39. LPDIRECTDRAW7        lpdd         = NULL;  // dd object
  40. LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;  // dd primary surface
  41. LPDIRECTDRAWSURFACE7 lpddsback    = NULL;  // dd back surface
  42. LPDIRECTDRAWPALETTE  lpddpal      = NULL;  // a pointer to the created dd palette
  43. LPDIRECTDRAWCLIPPER  lpddclipper  = NULL;  // dd clipper
  44. PALETTEENTRY         palette[256];         // color palette
  45. PALETTEENTRY         save_palette[256];    // used to save palettes
  46. DDSURFACEDESC2       ddsd;                 // a direct draw surface description struct
  47. DDBLTFX              ddbltfx;              // used to fill
  48. DDSCAPS2             ddscaps;              // a direct draw surface capabilities struct
  49. HRESULT              ddrval;               // result back from dd calls
  50. UCHAR                *primary_buffer = NULL; // primary video buffer
  51. UCHAR                *back_buffer    = NULL; // secondary back buffer
  52. int                  primary_lpitch  = 0;    // memory line pitch
  53. int                  back_lpitch     = 0;    // memory line pitch
  54. BITMAP_FILE          bitmap16bit;            // a 16 bit bitmap file
  55. BITMAP_FILE          bitmap8bit;             // a 8 bit bitmap file
  56.  
  57. DWORD                start_clock_count = 0; // used for timing
  58.  
  59. // these defined the general clipping rectangle
  60. int min_clip_x = 0,                          // clipping rectangle 
  61.     max_clip_x = SCREEN_WIDTH-1,
  62.     min_clip_y = 0,
  63.     max_clip_y = SCREEN_HEIGHT-1;
  64.  
  65. // these are overwritten globally by DD_Init()
  66. int screen_width  = SCREEN_WIDTH,            // width of screen
  67.     screen_height = SCREEN_HEIGHT,           // height of screen
  68.     screen_bpp    = SCREEN_BPP;              // bits per pixel
  69.  
  70. // FUNCTIONS //////////////////////////////////////////////
  71.  
  72. // the BOB engine, note that 90% of the BOB functions have
  73. // the exact same code for the 8 and 16 bit versions, however
  74. // I decided that it was just easier using all 8 or 16 bit 
  75. // versions syntactically, plus you might want to add some
  76. // more functionality to the 16 bit versions, so having separate
  77. // functions makes that easier -- 
  78.  
  79. ///////////////////////////////////////////////////////////
  80.  
  81. int Create_BOB(BOB_PTR bob,           // the bob to create
  82.                float x, float y,      // initial posiiton
  83.                int width, int height, // size of bob
  84.                int num_frames,        // number of frames
  85.                int attr,              // attrs
  86.                int mem_flags)         // memory flag
  87. {
  88. // Create the BOB object, note that all BOBs 
  89. // are created as offscreen surfaces in VRAM as the
  90. // default, if you want to use system memory then
  91. // set flags equal to DDSCAPS_SYSTEMMEMORY
  92.  
  93. DDSURFACEDESC2 ddsd; // used to create surface
  94. int index;          // looping var
  95.  
  96. // set state and attributes of BOB
  97. bob->state          = BOB_STATE_ALIVE;
  98. bob->attr           = attr;
  99. bob->anim_state     = 0;
  100. bob->counter_1      = 0;     
  101. bob->counter_2      = 0;
  102. bob->max_count_1    = 0;
  103. bob->max_count_2    = 0;
  104.  
  105. bob->curr_frame     = 0;
  106. bob->num_frames     = num_frames;
  107. bob->curr_animation = 0;
  108. bob->anim_counter   = 0;
  109. bob->anim_index     = 0;
  110. bob->anim_count_max = 0; 
  111. bob->x              = x;
  112. bob->y              = y;
  113. bob->xv             = 0;
  114. bob->yv             = 0;
  115.  
  116. // set dimensions of the new bitmap surface
  117. bob->width  = width;
  118. bob->height = height;
  119. bob->bpp    = 8;
  120.  
  121. // set all images to null
  122. for (index=0; index < MAX_BOB_FRAMES; index++)
  123.     bob->images[index] = NULL;
  124.  
  125. // set all animations to null
  126. for (index=0; index < MAX_BOB_ANIMATIONS; index++)
  127.     bob->animations[index] = NULL;
  128.  
  129. // make sure width is a multiple of 8
  130. bob->width_fill = ((width%8!=0) ? (8-width%8) : 0);
  131. Write_Error("\nCreate BOB %d",bob->width_fill);
  132.  
  133. // now create each surface
  134. for (index=0; index<bob->num_frames; index++)
  135.     {
  136.     // set to access caps, width, and height
  137.     memset(&ddsd,0,sizeof(ddsd));
  138.     ddsd.dwSize  = sizeof(ddsd);
  139.     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  140.  
  141.     ddsd.dwWidth  = bob->width + bob->width_fill;
  142.     ddsd.dwHeight = bob->height;
  143.  
  144.     // set surface to offscreen plain
  145.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
  146.  
  147.     // create the surfaces
  148.     if (lpdd->CreateSurface(&ddsd,&(bob->images[index]),NULL)!=DD_OK)
  149.         return(0);
  150.  
  151.     // set color key to color 0
  152.     DDCOLORKEY color_key; // used to set color key
  153.     color_key.dwColorSpaceLowValue  = 0;
  154.     color_key.dwColorSpaceHighValue = 0;
  155.  
  156.     // now set the color key for source blitting
  157.     (bob->images[index])->SetColorKey(DDCKEY_SRCBLT, &color_key);
  158.     } // end for index
  159.  
  160. // return success
  161. return(1);
  162.  
  163. } // end Create_BOB
  164.  
  165. ///////////////////////////////////////////////////////////
  166.  
  167. int Create_BOB16(BOB_PTR bob,         // the bob to create
  168.                float x, float y,      // initial posiiton
  169.                int width, int height, // size of bob
  170.                int num_frames,        // number of frames
  171.                int attr,              // attrs
  172.                int mem_flags)         // memory flag
  173. {
  174. // Create the 16-bit BOB object, note that all BOBs 
  175. // are created as offscreen surfaces in VRAM as the
  176. // default, if you want to use system memory then
  177. // set flags equal to DDSCAPS_SYSTEMMEMORY
  178.  
  179. DDSURFACEDESC2 ddsd; // used to create surface
  180. int index;          // looping var
  181.  
  182. // set state and attributes of BOB
  183. bob->state          = BOB_STATE_ALIVE;
  184. bob->attr           = attr;
  185. bob->anim_state     = 0;
  186. bob->counter_1      = 0;     
  187. bob->counter_2      = 0;
  188. bob->max_count_1    = 0;
  189. bob->max_count_2    = 0;
  190.  
  191. bob->curr_frame     = 0;
  192. bob->num_frames     = num_frames;
  193. bob->curr_animation = 0;
  194. bob->anim_counter   = 0;
  195. bob->anim_index     = 0;
  196. bob->anim_count_max = 0; 
  197. bob->x              = x;
  198. bob->y              = y;
  199. bob->xv             = 0;
  200. bob->yv             = 0;
  201.  
  202. // set dimensions of the new bitmap surface
  203. bob->width  = width;
  204. bob->height = height;
  205. bob->bpp    = 16;
  206.  
  207. // set all images to null
  208. for (index=0; index < MAX_BOB_FRAMES; index++)
  209.     bob->images[index] = NULL;
  210.  
  211. // set all animations to null
  212. for (index=0; index < MAX_BOB_ANIMATIONS; index++)
  213.     bob->animations[index] = NULL;
  214.  
  215. // make sure width is a multiple of 8
  216. bob->width_fill = ((width%8!=0) ? (8-width%8) : 0);
  217. Write_Error("\nCreate BOB %d",bob->width_fill);
  218.  
  219. // now create each surface
  220. for (index=0; index<bob->num_frames; index++)
  221.     {
  222.     // set to access caps, width, and height
  223.     memset(&ddsd,0,sizeof(ddsd));
  224.     ddsd.dwSize  = sizeof(ddsd);
  225.     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  226.  
  227.     ddsd.dwWidth  = bob->width + bob->width_fill;
  228.     ddsd.dwHeight = bob->height;
  229.  
  230.     // set surface to offscreen plain
  231.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
  232.  
  233.     // create the surfaces
  234.     if (lpdd->CreateSurface(&ddsd,&(bob->images[index]),NULL)!=DD_OK)
  235.         return(0);
  236.  
  237.     // set color key to RGB (0,0,0) color 0
  238.     DDCOLORKEY color_key; // used to set color key
  239.     color_key.dwColorSpaceLowValue  = _RGB16BIT565(0,0,0);
  240.     color_key.dwColorSpaceHighValue = _RGB16BIT565(0,0,0);
  241.  
  242.     // now set the color key for source blitting
  243.     (bob->images[index])->SetColorKey(DDCKEY_SRCBLT, &color_key);
  244.     } // end for index
  245.  
  246. // return success
  247. return(1);
  248.  
  249. } // end Create_BOB16
  250.  
  251. ///////////////////////////////////////////////////////////
  252.  
  253. int Destroy_BOB(BOB_PTR bob)
  254. {
  255. // destroy the BOB, simply release the surface
  256.  
  257. int index; // looping var
  258.  
  259. // is this bob valid
  260. if (!bob)
  261.     return(0);
  262.    
  263. // destroy each bitmap surface
  264. for (index=0; index < MAX_BOB_FRAMES; index++)
  265.     if (bob->images[index])
  266.        (bob->images[index])->Release();
  267.  
  268. // release memory for animation sequences 
  269. for (index=0; index < MAX_BOB_ANIMATIONS; index++)
  270.     if (bob->animations[index])
  271.        free(bob->animations[index]);
  272.  
  273. // return success
  274. return(1);
  275.  
  276. } // end Destroy_BOB
  277.  
  278. ///////////////////////////////////////////////////////////
  279.  
  280. int Destroy_BOB16(BOB_PTR bob)
  281. {
  282. // destroy the BOB, simply release the surface
  283.  
  284. int index; // looping var
  285.  
  286. // is this bob valid
  287. if (!bob)
  288.     return(0);
  289.    
  290. // destroy each bitmap surface
  291. for (index=0; index < MAX_BOB_FRAMES; index++)
  292.     if (bob->images[index])
  293.        (bob->images[index])->Release();
  294.  
  295. // release memory for animation sequences 
  296. for (index=0; index < MAX_BOB_ANIMATIONS; index++)
  297.     if (bob->animations[index])
  298.        free(bob->animations[index]);
  299.  
  300. // return success
  301. return(1);
  302.  
  303. } // end Destroy_BOB16
  304.  
  305. ///////////////////////////////////////////////////////////
  306.  
  307. int Draw_BOB(BOB_PTR bob,              // bob to draw
  308.              LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on
  309. {
  310. // draw a bob at the x,y defined in the BOB
  311. // on the destination surface defined in dest
  312.  
  313. RECT dest_rect,   // the destination rectangle
  314.      source_rect; // the source rectangle                             
  315.  
  316. // is this a valid bob
  317. if (!bob)
  318.     return(0);
  319.  
  320. // is bob visible
  321. if (!(bob->attr & BOB_ATTR_VISIBLE))
  322.    return(1);
  323.  
  324. // fill in the destination rect
  325. dest_rect.left   = bob->x;
  326. dest_rect.top    = bob->y;
  327. dest_rect.right  = bob->x+bob->width;
  328. dest_rect.bottom = bob->y+bob->height;
  329.  
  330. // fill in the source rect
  331. source_rect.left    = 0;
  332. source_rect.top     = 0;
  333. source_rect.right   = bob->width;
  334. source_rect.bottom  = bob->height;
  335.  
  336. // blt to destination surface
  337. if (dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  338.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  339.           NULL)!=DD_OK)
  340.     return(0);
  341.  
  342. // return success
  343. return(1);
  344. } // end Draw_BOB
  345.  
  346. ///////////////////////////////////////////////////////////
  347.  
  348. int Draw_BOB16(BOB_PTR bob,              // bob to draw
  349.              LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on
  350. {
  351. // draw a bob at the x,y defined in the BOB
  352. // on the destination surface defined in dest
  353.  
  354. RECT dest_rect,   // the destination rectangle
  355.      source_rect; // the source rectangle                             
  356.  
  357. // is this a valid bob
  358. if (!bob)
  359.     return(0);
  360.  
  361. // is bob visible
  362. if (!(bob->attr & BOB_ATTR_VISIBLE))
  363.    return(1);
  364.  
  365. // fill in the destination rect
  366. dest_rect.left   = bob->x;
  367. dest_rect.top    = bob->y;
  368. dest_rect.right  = bob->x+bob->width;
  369. dest_rect.bottom = bob->y+bob->height;
  370.  
  371. // fill in the source rect
  372. source_rect.left    = 0;
  373. source_rect.top     = 0;
  374. source_rect.right   = bob->width;
  375. source_rect.bottom  = bob->height;
  376.  
  377. // blt to destination surface
  378. if (dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  379.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  380.           NULL)!=DD_OK)
  381.     return(0);
  382.  
  383. // return success
  384. return(1);
  385. } // end Draw_BOB16
  386.  
  387. ///////////////////////////////////////////////////////////
  388.  
  389. int Draw_Scaled_BOB(BOB_PTR bob, int swidth, int sheight,  // bob and new dimensions
  390.                     LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on)
  391. {
  392. // this function draws a scaled bob to the size swidth, sheight
  393.  
  394. RECT dest_rect,   // the destination rectangle
  395.      source_rect; // the source rectangle                             
  396.  
  397. // is this a valid bob
  398. if (!bob)
  399.     return(0);
  400.  
  401. // is bob visible
  402. if (!(bob->attr & BOB_ATTR_VISIBLE))
  403.    return(1);
  404.  
  405. // fill in the destination rect
  406. dest_rect.left   = bob->x;
  407. dest_rect.top    = bob->y;
  408. dest_rect.right  = bob->x+swidth;
  409. dest_rect.bottom = bob->y+sheight;
  410.  
  411. // fill in the source rect
  412. source_rect.left    = 0;
  413. source_rect.top     = 0;
  414. source_rect.right   = bob->width;
  415. source_rect.bottom  = bob->height;
  416.  
  417. // blt to destination surface
  418. if (dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  419.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  420.           NULL)!=DD_OK)
  421.     return(0);
  422.  
  423. // return success
  424. return(1);
  425. } // end Draw_Scaled_BOB
  426.  
  427. ///////////////////////////////////////////////////////////
  428.  
  429. int Draw_Scaled_BOB16(BOB_PTR bob, int swidth, int sheight,  // bob and new dimensions
  430.                     LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on)
  431. {
  432. // this function draws a scaled bob to the size swidth, sheight
  433.  
  434. RECT dest_rect,   // the destination rectangle
  435.      source_rect; // the source rectangle                             
  436.  
  437. // is this a valid bob
  438. if (!bob)
  439.     return(0);
  440.  
  441. // is bob visible
  442. if (!(bob->attr & BOB_ATTR_VISIBLE))
  443.    return(1);
  444.  
  445. // fill in the destination rect
  446. dest_rect.left   = bob->x;
  447. dest_rect.top    = bob->y;
  448. dest_rect.right  = bob->x+swidth;
  449. dest_rect.bottom = bob->y+sheight;
  450.  
  451. // fill in the source rect
  452. source_rect.left    = 0;
  453. source_rect.top     = 0;
  454. source_rect.right   = bob->width;
  455. source_rect.bottom  = bob->height;
  456.  
  457. // blt to destination surface
  458. if (dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  459.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  460.           NULL)!=DD_OK)
  461.     return(0);
  462.  
  463. // return success
  464. return(1);
  465.  
  466. } // end Draw_Scaled_BOB16
  467.  
  468. ///////////////////////////////////////////////////////////
  469.  
  470. int Load_Frame_BOB(BOB_PTR bob, // bob to load with data
  471.                    BITMAP_FILE_PTR bitmap, // bitmap to scan image data from
  472.                    int frame,       // frame to load
  473.                    int cx,int cy,   // cell or absolute pos. to scan image from
  474.                    int mode)        // if 0 then cx,cy is cell position, else 
  475.                                     // cx,cy are absolute coords
  476. {
  477. // this function extracts a bitmap out of a bitmap file
  478.  
  479. UCHAR *source_ptr,   // working pointers
  480.       *dest_ptr;
  481.  
  482. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  483.  
  484. // is this a valid bob
  485. if (!bob)
  486.    return(0);
  487.  
  488. // test the mode of extraction, cell based or absolute
  489. if (mode==BITMAP_EXTRACT_MODE_CELL)
  490.    {
  491.    // re-compute x,y
  492.    cx = cx*(bob->width+1) + 1;
  493.    cy = cy*(bob->height+1) + 1;
  494.    } // end if
  495.  
  496. // extract bitmap data
  497. source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  498.  
  499. // get the addr to destination surface memory
  500.  
  501. // set size of the structure
  502. ddsd.dwSize = sizeof(ddsd);
  503.  
  504. // lock the display surface
  505. (bob->images[frame])->Lock(NULL,
  506.                            &ddsd,
  507.                            DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  508.                            NULL);
  509.  
  510. // assign a pointer to the memory surface for manipulation
  511. dest_ptr = (UCHAR *)ddsd.lpSurface;
  512.  
  513. // iterate thru each scanline and copy bitmap
  514. for (int index_y=0; index_y<bob->height; index_y++)
  515.     {
  516.     // copy next line of data to destination
  517.     memcpy(dest_ptr, source_ptr,bob->width);
  518.  
  519.     // advance pointers
  520.     dest_ptr   += (bob->width+bob->width_fill);
  521.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  522.     } // end for index_y
  523.  
  524. // unlock the surface 
  525. (bob->images[frame])->Unlock(NULL);
  526.  
  527. // set state to loaded
  528. bob->attr |= BOB_ATTR_LOADED;
  529.  
  530. // return success
  531. return(1);
  532.  
  533. } // end Load_Frame_BOB
  534.  
  535. ///////////////////////////////////////////////////////////
  536.  
  537. int Load_Frame_BOB16(BOB_PTR bob, // bob to load with data
  538.                      BITMAP_FILE_PTR bitmap, // bitmap to scan image data from
  539.                      int frame,       // frame to load
  540.                      int cx,int cy,   // cell or absolute pos. to scan image from
  541.                      int mode)        // if 0 then cx,cy is cell position, else 
  542.                                     // cx,cy are absolute coords
  543. {
  544. // this function extracts a bitmap out of a bitmap file
  545.  
  546. USHORT *source_ptr,   // working pointers
  547.        *dest_ptr;
  548.  
  549. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  550.  
  551. // is this a valid bob
  552. if (!bob)
  553.    return(0);
  554.  
  555. // test the mode of extraction, cell based or absolute
  556. if (mode==BITMAP_EXTRACT_MODE_CELL)
  557.    {
  558.    // re-compute x,y
  559.    cx = cx*(bob->width+1) + 1;
  560.    cy = cy*(bob->height+1) + 1;
  561.    } // end if
  562.  
  563. // extract bitmap data
  564. source_ptr = (USHORT *)bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  565.  
  566. // get the addr to destination surface memory
  567.  
  568. // set size of the structure
  569. ddsd.dwSize = sizeof(ddsd);
  570.  
  571. // lock the display surface
  572. (bob->images[frame])->Lock(NULL,
  573.                            &ddsd,
  574.                            DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  575.                            NULL);
  576.  
  577. // assign a pointer to the memory surface for manipulation
  578. dest_ptr = (USHORT *)ddsd.lpSurface;
  579.  
  580. // iterate thru each scanline and copy bitmap
  581. for (int index_y=0; index_y<bob->height; index_y++)
  582.     {
  583.     // copy next line of data to destination
  584.     memcpy(dest_ptr, source_ptr,(bob->width*2));
  585.  
  586.     // advance pointers
  587.     dest_ptr   += (ddsd.lPitch >> 1);
  588.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  589.     } // end for index_y
  590.  
  591. // unlock the surface 
  592. (bob->images[frame])->Unlock(NULL);
  593.  
  594. // set state to loaded
  595. bob->attr |= BOB_ATTR_LOADED;
  596.  
  597. // return success
  598. return(1);
  599.  
  600. } // end Load_Frame_BOB16
  601.  
  602. ///////////////////////////////////////////////////////////
  603.  
  604. int Animate_BOB(BOB_PTR bob)
  605. {
  606. // this function animates a bob, basically it takes a look at
  607. // the attributes of the bob and determines if the bob is 
  608. // a single frame, multiframe, or multi animation, updates
  609. // the counters and frames appropriately
  610.  
  611. #if 0
  612.         int curr_frame;     // current animation frame
  613.         int num_frames;     // total number of animation frames
  614.         int curr_animation; // index of current animation
  615.         int anim_counter;   // used to time animation transitions
  616.         int anim_index;     // animation element index
  617.         int anim_count_max; // number of cycles before animation
  618.         int *animations[MAX_BOB_ANIMATIONS]; // animation sequences
  619.  
  620.         LPDIRECTDRAWSURFACE7 images[MAX_BOB_FRAMES]; // the bitmap images DD surfaces
  621. #endif
  622.  
  623.  
  624. // is this a valid bob
  625. if (!bob)
  626.    return(0);
  627.  
  628. // test the level of animation
  629. if (bob->attr & BOB_ATTR_SINGLE_FRAME)
  630.     {
  631.     // current frame always = 0
  632.     bob->curr_frame = 0;
  633.     return(1);
  634.     } // end if
  635. else
  636. if (bob->attr & BOB_ATTR_MULTI_FRAME)
  637.    {
  638.    // update the counter and test if its time to increment frame
  639.    if (++bob->anim_counter >= bob->anim_count_max)
  640.       {
  641.       // reset counter
  642.       bob->anim_counter = 0;
  643.  
  644.       // move to next frame
  645.       if (++bob->curr_frame >= bob->num_frames)
  646.          bob->curr_frame = 0;
  647.  
  648.       } // end if
  649.   
  650.    } // end elseif
  651. else
  652. if (bob->attr & BOB_ATTR_MULTI_ANIM)
  653.    {
  654.    // this is the most complex of the animations it must look up the
  655.    // next frame in the animation sequence
  656.  
  657.    // first test if its time to animate
  658.    if (++bob->anim_counter >= bob->anim_count_max)
  659.       {
  660.       // reset counter
  661.       bob->anim_counter = 0;
  662.  
  663.       // increment the animation frame index
  664.       bob->anim_index++;
  665.       
  666.       // extract the next frame from animation list 
  667.       bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  668.      
  669.       // is this and end sequence flag -1
  670.       if (bob->curr_frame == -1)
  671.          {
  672.          // test if this is a single shot animation
  673.          if (bob->attr & BOB_ATTR_ANIM_ONE_SHOT)
  674.             {
  675.             // set animation state message to done
  676.             bob->anim_state = BOB_STATE_ANIM_DONE;
  677.             
  678.             // reset frame back one
  679.             bob->anim_index--;
  680.  
  681.             // extract animation frame
  682.             bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];    
  683.  
  684.             } // end if
  685.         else
  686.            {
  687.            // reset animation index
  688.            bob->anim_index = 0;
  689.  
  690.            // extract first animation frame
  691.            bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  692.            } // end else
  693.  
  694.          }  // end if
  695.       
  696.       } // end if
  697.  
  698.    } // end elseif
  699.  
  700. // return success
  701. return(1);
  702.  
  703. } // end Animate_BOB
  704.  
  705. ////////////////////////////////////////////////////////////////
  706.  
  707. int Animate_BOB16(BOB_PTR bob)
  708. {
  709. // this function animates a bob, basically it takes a look at
  710. // the attributes of the bob and determines if the bob is 
  711. // a single frame, multiframe, or multi animation, updates
  712. // the counters and frames appropriately
  713.  
  714. #if 0
  715.         int curr_frame;     // current animation frame
  716.         int num_frames;     // total number of animation frames
  717.         int curr_animation; // index of current animation
  718.         int anim_counter;   // used to time animation transitions
  719.         int anim_index;     // animation element index
  720.         int anim_count_max; // number of cycles before animation
  721.         int *animations[MAX_BOB_ANIMATIONS]; // animation sequences
  722.  
  723.         LPDIRECTDRAWSURFACE7 images[MAX_BOB_FRAMES]; // the bitmap images DD surfaces
  724. #endif
  725.  
  726.  
  727. // is this a valid bob
  728. if (!bob)
  729.    return(0);
  730.  
  731. // test the level of animation
  732. if (bob->attr & BOB_ATTR_SINGLE_FRAME)
  733.     {
  734.     // current frame always = 0
  735.     bob->curr_frame = 0;
  736.     return(1);
  737.     } // end if
  738. else
  739. if (bob->attr & BOB_ATTR_MULTI_FRAME)
  740.    {
  741.    // update the counter and test if its time to increment frame
  742.    if (++bob->anim_counter >= bob->anim_count_max)
  743.       {
  744.       // reset counter
  745.       bob->anim_counter = 0;
  746.  
  747.       // move to next frame
  748.       if (++bob->curr_frame >= bob->num_frames)
  749.          bob->curr_frame = 0;
  750.  
  751.       } // end if
  752.   
  753.    } // end elseif
  754. else
  755. if (bob->attr & BOB_ATTR_MULTI_ANIM)
  756.    {
  757.    // this is the most complex of the animations it must look up the
  758.    // next frame in the animation sequence
  759.  
  760.    // first test if its time to animate
  761.    if (++bob->anim_counter >= bob->anim_count_max)
  762.       {
  763.       // reset counter
  764.       bob->anim_counter = 0;
  765.  
  766.       // increment the animation frame index
  767.       bob->anim_index++;
  768.       
  769.       // extract the next frame from animation list 
  770.       bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  771.      
  772.       // is this and end sequence flag -1
  773.       if (bob->curr_frame == -1)
  774.          {
  775.          // test if this is a single shot animation
  776.          if (bob->attr & BOB_ATTR_ANIM_ONE_SHOT)
  777.             {
  778.             // set animation state message to done
  779.             bob->anim_state = BOB_STATE_ANIM_DONE;
  780.             
  781.             // reset frame back one
  782.             bob->anim_index--;
  783.  
  784.             // extract animation frame
  785.             bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];    
  786.  
  787.             } // end if
  788.         else
  789.            {
  790.            // reset animation index
  791.            bob->anim_index = 0;
  792.  
  793.            // extract first animation frame
  794.            bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  795.            } // end else
  796.  
  797.          }  // end if
  798.       
  799.       } // end if
  800.  
  801.    } // end elseif
  802.  
  803. // return success
  804. return(1);
  805.  
  806. } // end Animate_BOB16
  807.  
  808. ///////////////////////////////////////////////////////////
  809.  
  810. int Scroll_BOB(void)
  811. {
  812. // this function scrolls a bob 
  813. // not implemented
  814.  
  815. // return success
  816. return(1);
  817. } // end Scroll_BOB
  818.  
  819. ///////////////////////////////////////////////////////////
  820.  
  821. int Move_BOB(BOB_PTR bob)
  822. {
  823. // this function moves the bob based on its current velocity
  824. // also, the function test for various motion attributes of the'
  825. // bob and takes the appropriate actions
  826.    
  827.  
  828. // is this a valid bob
  829. if (!bob)
  830.    return(0);
  831.  
  832. // translate the bob
  833. bob->x+=bob->xv;
  834. bob->y+=bob->yv;
  835.  
  836. // test for wrap around
  837. if (bob->attr & BOB_ATTR_WRAPAROUND)
  838.    {
  839.    // test x extents first
  840.    if (bob->x > max_clip_x)
  841.        bob->x = min_clip_x - bob->width;
  842.    else
  843.    if (bob->x < min_clip_x-bob->width)
  844.        bob->x = max_clip_x;
  845.    
  846.    // now y extents
  847.    if (bob->y > max_clip_y)
  848.        bob->y = min_clip_y - bob->height;
  849.    else
  850.    if (bob->y < min_clip_y-bob->height)
  851.        bob->y = max_clip_y;
  852.  
  853.    } // end if
  854. else
  855. // test for bounce
  856. if (bob->attr & BOB_ATTR_BOUNCE)
  857.    {
  858.    // test x extents first
  859.    if ((bob->x > max_clip_x - bob->width) || (bob->x < min_clip_x) )
  860.        bob->xv = -bob->xv;
  861.     
  862.    // now y extents 
  863.    if ((bob->y > max_clip_y - bob->height) || (bob->y < min_clip_y) )
  864.        bob->yv = -bob->yv;
  865.  
  866.    } // end if
  867.  
  868. // return success
  869. return(1);
  870. } // end Move_BOB
  871.  
  872. ///////////////////////////////////////////////////////////
  873.  
  874. int Move_BOB16(BOB_PTR bob)
  875. {
  876. // this function moves the bob based on its current velocity
  877. // also, the function test for various motion attributes of the'
  878. // bob and takes the appropriate actions
  879.    
  880.  
  881. // is this a valid bob
  882. if (!bob)
  883.    return(0);
  884.  
  885. // translate the bob
  886. bob->x+=bob->xv;
  887. bob->y+=bob->yv;
  888.  
  889. // test for wrap around
  890. if (bob->attr & BOB_ATTR_WRAPAROUND)
  891.    {
  892.    // test x extents first
  893.    if (bob->x > max_clip_x)
  894.        bob->x = min_clip_x - bob->width;
  895.    else
  896.    if (bob->x < min_clip_x-bob->width)
  897.        bob->x = max_clip_x;
  898.    
  899.    // now y extents
  900.    if (bob->y > max_clip_y)
  901.        bob->y = min_clip_y - bob->height;
  902.    else
  903.    if (bob->y < min_clip_y-bob->height)
  904.        bob->y = max_clip_y;
  905.  
  906.    } // end if
  907. else
  908. // test for bounce
  909. if (bob->attr & BOB_ATTR_BOUNCE)
  910.    {
  911.    // test x extents first
  912.    if ((bob->x > max_clip_x - bob->width) || (bob->x < min_clip_x) )
  913.        bob->xv = -bob->xv;
  914.     
  915.    // now y extents 
  916.    if ((bob->y > max_clip_y - bob->height) || (bob->y < min_clip_y) )
  917.        bob->yv = -bob->yv;
  918.  
  919.    } // end if
  920.  
  921. // return success
  922. return(1);
  923. } // end Move_BOB16
  924.  
  925. ///////////////////////////////////////////////////////////
  926.  
  927. int Load_Animation_BOB(BOB_PTR bob, 
  928.                        int anim_index, 
  929.                        int num_frames, 
  930.                        int *sequence)
  931. {
  932. // this function load an animation sequence for a bob
  933. // the sequence consists of frame indices, the function
  934. // will append a -1 to the end of the list so the display
  935. // software knows when to restart the animation sequence
  936.  
  937. // is this bob valid
  938. if (!bob)
  939.    return(0);
  940.  
  941. // allocate memory for bob animation
  942. if (!(bob->animations[anim_index] = (int *)malloc((num_frames+1)*sizeof(int))))
  943.    return(0);
  944.  
  945. // load data into 
  946. for (int index=0; index<num_frames; index++)
  947.     bob->animations[anim_index][index] = sequence[index];
  948.  
  949. // set the end of the list to a -1
  950. bob->animations[anim_index][index] = -1;
  951.  
  952. // return success
  953. return(1);
  954.  
  955. } // end Load_Animation_BOB
  956.  
  957. ///////////////////////////////////////////////////////////
  958.  
  959. int Load_Animation_BOB16(BOB_PTR bob, 
  960.                        int anim_index, 
  961.                        int num_frames, 
  962.                        int *sequence)
  963. {
  964. // this function load an animation sequence for a bob
  965. // the sequence consists of frame indices, the function
  966. // will append a -1 to the end of the list so the display
  967. // software knows when to restart the animation sequence
  968.  
  969. // is this bob valid
  970. if (!bob)
  971.    return(0);
  972.  
  973. // allocate memory for bob animation
  974. if (!(bob->animations[anim_index] = (int *)malloc((num_frames+1)*sizeof(int))))
  975.    return(0);
  976.  
  977. // load data into 
  978. for (int index=0; index<num_frames; index++)
  979.     bob->animations[anim_index][index] = sequence[index];
  980.  
  981. // set the end of the list to a -1
  982. bob->animations[anim_index][index] = -1;
  983.  
  984. // return success
  985. return(1);
  986.  
  987. } // end Load_Animation_BOB16
  988.  
  989. ///////////////////////////////////////////////////////////
  990.  
  991. int Set_Pos_BOB(BOB_PTR bob, int x, int y)
  992. {
  993. // this functions sets the postion of a bob
  994.  
  995. // is this a valid bob
  996. if (!bob)
  997.    return(0);
  998.  
  999. // set positin
  1000. bob->x = x;
  1001. bob->y = y;
  1002.  
  1003. // return success
  1004. return(1);
  1005. } // end Set_Pos_BOB
  1006.  
  1007. ///////////////////////////////////////////////////////////
  1008.  
  1009. int Set_Pos_BOB16(BOB_PTR bob, int x, int y)
  1010. {
  1011. // this functions sets the postion of a bob
  1012.  
  1013. // is this a valid bob
  1014. if (!bob)
  1015.    return(0);
  1016.  
  1017. // set positin
  1018. bob->x = x;
  1019. bob->y = y;
  1020.  
  1021. // return success
  1022. return(1);
  1023. } // end Set_Pos_BOB16
  1024.  
  1025. ///////////////////////////////////////////////////////////
  1026.  
  1027. int Set_Anim_Speed_BOB(BOB_PTR bob,int speed)
  1028. {
  1029. // this function simply sets the animation speed of a bob
  1030.     
  1031. // is this a valid bob
  1032. if (!bob)
  1033.    return(0);
  1034.  
  1035. // set speed
  1036. bob->anim_count_max = speed;
  1037.  
  1038. // return success
  1039. return(1);
  1040.  
  1041. } // end Set_Anim_Speed
  1042.  
  1043. ///////////////////////////////////////////////////////////
  1044.  
  1045. int Set_Anim_Speed_BOB16(BOB_PTR bob,int speed)
  1046. {
  1047. // this function simply sets the animation speed of a bob
  1048.     
  1049. // is this a valid bob
  1050. if (!bob)
  1051.    return(0);
  1052.  
  1053. // set speed
  1054. bob->anim_count_max = speed;
  1055.  
  1056. // return success
  1057. return(1);
  1058.  
  1059. } // end Set_Anim_Speed16
  1060.  
  1061. ///////////////////////////////////////////////////////////
  1062.  
  1063. int Set_Animation_BOB(BOB_PTR bob, int anim_index)
  1064. {
  1065. // this function sets the animation to play
  1066.  
  1067. // is this a valid bob
  1068. if (!bob)
  1069.    return(0);
  1070.  
  1071. // set the animation index
  1072. bob->curr_animation = anim_index;
  1073.  
  1074. // reset animation 
  1075. bob->anim_index = 0;
  1076.  
  1077. // return success
  1078. return(1);
  1079.  
  1080. } // end Set_Animation_BOB
  1081.  
  1082. ///////////////////////////////////////////////////////////
  1083.  
  1084. int Set_Animation_BOB16(BOB_PTR bob, int anim_index)
  1085. {
  1086. // this function sets the animation to play
  1087.  
  1088. // is this a valid bob
  1089. if (!bob)
  1090.    return(0);
  1091.  
  1092. // set the animation index
  1093. bob->curr_animation = anim_index;
  1094.  
  1095. // reset animation 
  1096. bob->anim_index = 0;
  1097.  
  1098. // return success
  1099. return(1);
  1100.  
  1101. } // end Set_Animation_BOB16
  1102.  
  1103. ///////////////////////////////////////////////////////////
  1104.  
  1105. int Set_Vel_BOB(BOB_PTR bob,int xv, int yv)
  1106. {
  1107. // this function sets the velocity of a bob
  1108.  
  1109. // is this a valid bob
  1110. if (!bob)
  1111.    return(0);
  1112.  
  1113. // set velocity
  1114. bob->xv = xv;
  1115. bob->yv = yv;
  1116.  
  1117. // return success
  1118. return(1);
  1119. } // end Set_Vel_BOB
  1120.  
  1121. ///////////////////////////////////////////////////////////
  1122.  
  1123. int Set_Vel_BOB16(BOB_PTR bob,int xv, int yv)
  1124. {
  1125. // this function sets the velocity of a bob
  1126.  
  1127. // is this a valid bob
  1128. if (!bob)
  1129.    return(0);
  1130.  
  1131. // set velocity
  1132. bob->xv = xv;
  1133. bob->yv = yv;
  1134.  
  1135. // return success
  1136. return(1);
  1137. } // end Set_Vel_BOB16
  1138.  
  1139. ///////////////////////////////////////////////////////////
  1140.  
  1141. int Hide_BOB(BOB_PTR bob)
  1142. {
  1143. // this functions hides bob 
  1144.  
  1145. // is this a valid bob
  1146. if (!bob)
  1147.    return(0);
  1148.  
  1149. // reset the visibility bit
  1150. RESET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  1151.  
  1152. // return success
  1153. return(1);
  1154. } // end Hide_BOB
  1155.  
  1156. ///////////////////////////////////////////////////////////
  1157.  
  1158. int Hide_BOB16(BOB_PTR bob)
  1159. {
  1160. // this functions hides bob 
  1161.  
  1162. // is this a valid bob
  1163. if (!bob)
  1164.    return(0);
  1165.  
  1166. // reset the visibility bit
  1167. RESET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  1168.  
  1169. // return success
  1170. return(1);
  1171. } // end Hide_BOB16
  1172.  
  1173. ///////////////////////////////////////////////////////////
  1174.  
  1175. int Show_BOB(BOB_PTR bob)
  1176. {
  1177. // this function shows a bob
  1178.  
  1179. // is this a valid bob
  1180. if (!bob)
  1181.    return(0);
  1182.  
  1183. // set the visibility bit
  1184. SET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  1185.  
  1186. // return success
  1187. return(1);
  1188. } // end Show_BOB
  1189.  
  1190. ///////////////////////////////////////////////////////////
  1191.  
  1192. int Show_BOB16(BOB_PTR bob)
  1193. {
  1194. // this function shows a bob
  1195.  
  1196. // is this a valid bob
  1197. if (!bob)
  1198.    return(0);
  1199.  
  1200. // set the visibility bit
  1201. SET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  1202.  
  1203. // return success
  1204. return(1);
  1205. } // end Show_BOB16
  1206.  
  1207. ///////////////////////////////////////////////////////////
  1208.  
  1209. int Collision_BOBS(BOB_PTR bob1, BOB_PTR bob2)
  1210. {
  1211. // are these a valid bobs
  1212. if (!bob1 || !bob2)
  1213.    return(0);
  1214.  
  1215. // get the radi of each rect
  1216. int width1  = (bob1->width>>1) - (bob1->width>>3);
  1217. int height1 = (bob1->height>>1) - (bob1->height>>3);
  1218.  
  1219. int width2  = (bob2->width>>1) - (bob2->width>>3);
  1220. int height2 = (bob2->height>>1) - (bob2->height>>3);
  1221.  
  1222. // compute center of each rect
  1223. int cx1 = bob1->x + width1;
  1224. int cy1 = bob1->y + height1;
  1225.  
  1226. int cx2 = bob2->x + width2;
  1227. int cy2 = bob2->y + height2;
  1228.  
  1229. // compute deltas
  1230. int dx = abs(cx2 - cx1);
  1231. int dy = abs(cy2 - cy1);
  1232.  
  1233. // test if rects overlap
  1234. if (dx < (width1+width2) && dy < (height1+height2))
  1235.    return(1);
  1236. else
  1237. // else no collision
  1238. return(0);
  1239.  
  1240. } // end Collision_BOBS
  1241.  
  1242.  
  1243. ///////////////////////////////////////////////////////////
  1244.  
  1245. int Collision_BOBS16(BOB_PTR bob1, BOB_PTR bob2)
  1246. {
  1247. // are these a valid bobs
  1248. if (!bob1 || !bob2)
  1249.    return(0);
  1250.  
  1251. // get the radi of each rect
  1252. int width1  = (bob1->width>>1) - (bob1->width>>3);
  1253. int height1 = (bob1->height>>1) - (bob1->height>>3);
  1254.  
  1255. int width2  = (bob2->width>>1) - (bob2->width>>3);
  1256. int height2 = (bob2->height>>1) - (bob2->height>>3);
  1257.  
  1258. // compute center of each rect
  1259. int cx1 = bob1->x + width1;
  1260. int cy1 = bob1->y + height1;
  1261.  
  1262. int cx2 = bob2->x + width2;
  1263. int cy2 = bob2->y + height2;
  1264.  
  1265. // compute deltas
  1266. int dx = abs(cx2 - cx1);
  1267. int dy = abs(cy2 - cy1);
  1268.  
  1269. // test if rects overlap
  1270. if (dx < (width1+width2) && dy < (height1+height2))
  1271.    return(1);
  1272. else
  1273. // else no collision
  1274. return(0);
  1275.  
  1276. } // end Collision_BOBS16
  1277.  
  1278. ///////////////////////////////////////////////////////////
  1279.  
  1280. int DD_Init(int width, int height, int bpp)
  1281. {
  1282. // this function initializes directdraw
  1283. int index; // looping variable
  1284. // create object and test for error
  1285. if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)!=DD_OK)
  1286.    return(0);
  1287.  
  1288. // set cooperation level to windowed mode normal
  1289. if (lpdd->SetCooperativeLevel(main_window_handle,
  1290.            DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 
  1291.            DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)!=DD_OK)
  1292.     return(0);
  1293.  
  1294. // set the display mode
  1295. if (lpdd->SetDisplayMode(width,height,bpp,0,0)!=DD_OK)
  1296.    return(0);
  1297.  
  1298. // set globals
  1299. screen_height = height;
  1300. screen_width = width;
  1301. screen_bpp = bpp;
  1302.  
  1303. // Create the primary surface
  1304. memset(&ddsd,0,sizeof(ddsd));
  1305. ddsd.dwSize = sizeof(ddsd);
  1306. ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  1307.  
  1308. // we need to let dd know that we want a complex 
  1309. // flippable surface structure, set flags for that
  1310. ddsd.ddsCaps.dwCaps = 
  1311.   DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  1312.  
  1313. // set the backbuffer count to 1
  1314. ddsd.dwBackBufferCount = 1;
  1315.  
  1316. // create the primary surface
  1317. lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);
  1318.  
  1319. // query for the backbuffer i.e the secondary surface
  1320. ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  1321. lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback);
  1322.  
  1323. // create and attach palette for 8-bit modes
  1324.  
  1325. if (screen_bpp==8)
  1326. {
  1327. // create palette data
  1328. // clear all entries defensive programming
  1329. memset(palette,0,256*sizeof(PALETTEENTRY));
  1330.  
  1331. // create a R,G,B,GR gradient palette
  1332. for (index=0; index < 256; index++)
  1333.     {
  1334.     // set each entry
  1335.     if (index < 64) 
  1336.         palette[index].peRed = index*4; 
  1337.     else           // shades of green
  1338.     if (index >= 64 && index < 128) 
  1339.         palette[index].peGreen = (index-64)*4;
  1340.     else           // shades of blue
  1341.     if (index >= 128 && index < 192) 
  1342.        palette[index].peBlue = (index-128)*4;
  1343.     else           // shades of grey
  1344.     if (index >= 192 && index < 256) 
  1345.         palette[index].peRed = palette[index].peGreen = 
  1346.         palette[index].peBlue = (index-192)*4;
  1347.     
  1348.     // set flags
  1349.     palette[index].peFlags = PC_NOCOLLAPSE;
  1350.     } // end for index
  1351.  
  1352. // now create the palette object
  1353. if (lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE | DDPCAPS_ALLOW256,
  1354.                          palette,&lpddpal,NULL)!=DD_OK)
  1355.    return(0);
  1356.  
  1357. // attach the palette to the primary
  1358. if (lpddsprimary->SetPalette(lpddpal)!=DD_OK)
  1359.    return(0);
  1360.  
  1361. } // end if palette
  1362.  
  1363. // clear out both primary and secondary surfaces
  1364. DD_Fill_Surface(lpddsprimary,0);
  1365. DD_Fill_Surface(lpddsback,0);
  1366.  
  1367. // return success
  1368. return(1);
  1369. } // end DD_Init
  1370.  
  1371. ///////////////////////////////////////////////////////////
  1372.  
  1373. int DD_Shutdown(void)
  1374. {
  1375. // this function release all the resources directdraw
  1376. // allocated, mainly to com objects
  1377.  
  1378. // release the clipper first
  1379. if (lpddclipper)
  1380.     lpddclipper->Release();
  1381.  
  1382. // release the palette
  1383. if (lpddpal)
  1384.    lpddpal->Release();
  1385.  
  1386. // release the secondary surface
  1387. if (lpddsback)
  1388.     lpddsback->Release();
  1389.  
  1390. // release the primary surface
  1391. if (lpddsprimary)
  1392.    lpddsprimary->Release();
  1393.  
  1394. // finally, the main dd object
  1395. if (lpdd)
  1396.     lpdd->Release();
  1397.  
  1398. // return success
  1399. return(1);
  1400. } // end DD_Shutdown
  1401.  
  1402. ///////////////////////////////////////////////////////////   
  1403.  
  1404. LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,
  1405.                                       int num_rects,
  1406.                                       LPRECT clip_list)
  1407.  
  1408. {
  1409. // this function creates a clipper from the sent clip list and attaches
  1410. // it to the sent surface
  1411.  
  1412. int index;                         // looping var
  1413. LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly created dd clipper
  1414. LPRGNDATA region_data;             // pointer to the region data that contains
  1415.                                    // the header and clip list
  1416.  
  1417. // first create the direct draw clipper
  1418. if ((lpdd->CreateClipper(0,&lpddclipper,NULL))!=DD_OK)
  1419.    return(NULL);
  1420.  
  1421. // now create the clip list from the sent data
  1422.  
  1423. // first allocate memory for region data
  1424. region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));
  1425.  
  1426. // now copy the rects into region data
  1427. memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);
  1428.  
  1429. // set up fields of header
  1430. region_data->rdh.dwSize          = sizeof(RGNDATAHEADER);
  1431. region_data->rdh.iType           = RDH_RECTANGLES;
  1432. region_data->rdh.nCount          = num_rects;
  1433. region_data->rdh.nRgnSize        = num_rects*sizeof(RECT);
  1434.  
  1435. region_data->rdh.rcBound.left    =  64000;
  1436. region_data->rdh.rcBound.top     =  64000;
  1437. region_data->rdh.rcBound.right   = -64000;
  1438. region_data->rdh.rcBound.bottom  = -64000;
  1439.  
  1440. // find bounds of all clipping regions
  1441. for (index=0; index<num_rects; index++)
  1442.     {
  1443.     // test if the next rectangle unioned with the current bound is larger
  1444.     if (clip_list[index].left < region_data->rdh.rcBound.left)
  1445.        region_data->rdh.rcBound.left = clip_list[index].left;
  1446.  
  1447.     if (clip_list[index].right > region_data->rdh.rcBound.right)
  1448.        region_data->rdh.rcBound.right = clip_list[index].right;
  1449.  
  1450.     if (clip_list[index].top < region_data->rdh.rcBound.top)
  1451.        region_data->rdh.rcBound.top = clip_list[index].top;
  1452.  
  1453.     if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)
  1454.        region_data->rdh.rcBound.bottom = clip_list[index].bottom;
  1455.  
  1456.     } // end for index
  1457.  
  1458. // now we have computed the bounding rectangle region and set up the data
  1459. // now let's set the clipping list
  1460.  
  1461. if ((lpddclipper->SetClipList(region_data, 0))!=DD_OK)
  1462.    {
  1463.    // release memory and return error
  1464.    free(region_data);
  1465.    return(NULL);
  1466.    } // end if
  1467.  
  1468. // now attach the clipper to the surface
  1469. if ((lpdds->SetClipper(lpddclipper))!=DD_OK)
  1470.    {
  1471.    // release memory and return error
  1472.    free(region_data);
  1473.    return(NULL);
  1474.    } // end if
  1475.  
  1476. // all is well, so release memory and send back the pointer to the new clipper
  1477. free(region_data);
  1478. return(lpddclipper);
  1479.  
  1480. } // end DD_Attach_Clipper
  1481.  
  1482. ///////////////////////////////////////////////////////////   
  1483.    
  1484. LPDIRECTDRAWSURFACE7 DD_Create_Surface(int width, int height, int mem_flags)
  1485. {
  1486. // this function creates an offscreen plain surface
  1487.  
  1488. DDSURFACEDESC2 ddsd;         // working description
  1489. LPDIRECTDRAWSURFACE7 lpdds;  // temporary surface
  1490.     
  1491. // set to access caps, width, and height
  1492. memset(&ddsd,0,sizeof(ddsd));
  1493. ddsd.dwSize  = sizeof(ddsd);
  1494. ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  1495.  
  1496. // set dimensions of the new bitmap surface
  1497. ddsd.dwWidth  =  width;
  1498. ddsd.dwHeight =  height;
  1499.  
  1500. // set surface to offscreen plain
  1501. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
  1502.  
  1503. // create the surface
  1504. if (lpdd->CreateSurface(&ddsd,&lpdds,NULL)!=DD_OK)
  1505.    return(NULL);
  1506.  
  1507. // set color key to 0 which is index 0 and 0,0,0 rgb
  1508. DDCOLORKEY color_key; // used to set color key
  1509. color_key.dwColorSpaceLowValue  = 0;
  1510. color_key.dwColorSpaceHighValue = 0;
  1511.  
  1512. // now set the color key for source blitting
  1513. lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);
  1514.  
  1515. // return surface
  1516. return(lpdds);
  1517. } // end DD_Create_Surface
  1518.  
  1519. ///////////////////////////////////////////////////////////   
  1520.    
  1521. int DD_Flip(void)
  1522. {
  1523. // this function flip the primary surface with the secondary surface
  1524.  
  1525. // test if either of the buffers are locked
  1526. if (primary_buffer || back_buffer)
  1527.    return(0);
  1528.  
  1529. // flip pages
  1530. while(lpddsprimary->Flip(NULL, DDFLIP_WAIT)!=DD_OK);
  1531.  
  1532. // flip the surface
  1533.  
  1534. // return success
  1535. return(1);
  1536.  
  1537. } // end DD_Flip
  1538.  
  1539. ///////////////////////////////////////////////////////////   
  1540.    
  1541. int DD_Wait_For_Vsync(void)
  1542. {
  1543. // this function waits for a vertical blank to begin
  1544.     
  1545. lpdd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);
  1546.  
  1547. // return success
  1548. return(1);
  1549. } // end DD_Wait_For_Vsync
  1550.  
  1551. ///////////////////////////////////////////////////////////   
  1552.    
  1553. int DD_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds, int color)
  1554. {
  1555. DDBLTFX ddbltfx; // this contains the DDBLTFX structure
  1556.  
  1557. // clear out the structure and set the size field 
  1558. DD_INIT_STRUCT(ddbltfx);
  1559.  
  1560. // set the dwfillcolor field to the desired color
  1561. ddbltfx.dwFillColor = color; 
  1562.  
  1563. // ready to blt to surface
  1564. lpdds->Blt(NULL,       // ptr to dest rectangle
  1565.            NULL,       // ptr to source surface, NA            
  1566.            NULL,       // ptr to source rectangle, NA
  1567.            DDBLT_COLORFILL | DDBLT_WAIT,   // fill and wait                   
  1568.            &ddbltfx);  // ptr to DDBLTFX structure
  1569.  
  1570. // return success
  1571. return(1);
  1572. } // end DD_Fill_Surface
  1573.  
  1574. ///////////////////////////////////////////////////////////   
  1575.    
  1576. UCHAR *DD_Lock_Surface(LPDIRECTDRAWSURFACE7 lpdds,int *lpitch)
  1577. {
  1578. // this function locks the sent surface and returns a pointer to it
  1579.  
  1580. // is this surface valid
  1581. if (!lpdds)
  1582.    return(NULL);
  1583.  
  1584. // lock the surface
  1585. DD_INIT_STRUCT(ddsd);
  1586. lpdds->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1587.  
  1588. // set the memory pitch
  1589. if (lpitch)
  1590.    *lpitch = ddsd.lPitch;
  1591.  
  1592. // return pointer to surface
  1593. return((UCHAR *)ddsd.lpSurface);
  1594.  
  1595. } // end DD_Lock_Surface
  1596.  
  1597. ///////////////////////////////////////////////////////////   
  1598.    
  1599. int DD_Unlock_Surface(LPDIRECTDRAWSURFACE7 lpdds, UCHAR *surface_buffer)
  1600. {
  1601. // this unlocks a general surface
  1602.  
  1603. // is this surface valid
  1604. if (!lpdds)
  1605.    return(0);
  1606.  
  1607. // unlock the surface memory
  1608. lpdds->Unlock(NULL);
  1609.  
  1610. // return success
  1611. return(1);
  1612. } // end DD_Unlock_Surface
  1613.  
  1614. ///////////////////////////////////////////////////////////
  1615.  
  1616. UCHAR *DD_Lock_Primary_Surface(void)
  1617. {
  1618. // this function locks the priamary surface and returns a pointer to it
  1619. // and updates the global variables primary_buffer, and primary_lpitch
  1620.  
  1621. // is this surface already locked
  1622. if (primary_buffer)
  1623.    {
  1624.    // return to current lock
  1625.    return(primary_buffer);
  1626.    } // end if
  1627.  
  1628. // lock the primary surface
  1629. DD_INIT_STRUCT(ddsd);
  1630. lpddsprimary->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1631.  
  1632. // set globals
  1633. primary_buffer = (UCHAR *)ddsd.lpSurface;
  1634. primary_lpitch = ddsd.lPitch;
  1635.  
  1636. // return pointer to surface
  1637. return(primary_buffer);
  1638.  
  1639. } // end DD_Lock_Primary_Surface
  1640.  
  1641. ///////////////////////////////////////////////////////////   
  1642.    
  1643. int DD_Unlock_Primary_Surface(void)
  1644. {
  1645. // this unlocks the primary
  1646.  
  1647. // is this surface valid
  1648. if (!primary_buffer)
  1649.    return(0);
  1650.  
  1651. // unlock the primary surface
  1652. lpddsprimary->Unlock(NULL);
  1653.  
  1654. // reset the primary surface
  1655. primary_buffer = NULL;
  1656. primary_lpitch = 0;
  1657.  
  1658. // return success
  1659. return(1);
  1660. } // end DD_Unlock_Primary_Surface
  1661.  
  1662. //////////////////////////////////////////////////////////
  1663.  
  1664. UCHAR *DD_Lock_Back_Surface(void)
  1665. {
  1666. // this function locks the secondary back surface and returns a pointer to it
  1667. // and updates the global variables secondary buffer, and back_lpitch
  1668.  
  1669. // is this surface already locked
  1670. if (back_buffer)
  1671.    {
  1672.    // return to current lock
  1673.    return(back_buffer);
  1674.    } // end if
  1675.  
  1676. // lock the primary surface
  1677. DD_INIT_STRUCT(ddsd);
  1678. lpddsback->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1679.  
  1680. // set globals
  1681. back_buffer = (UCHAR *)ddsd.lpSurface;
  1682. back_lpitch = ddsd.lPitch;
  1683.  
  1684. // return pointer to surface
  1685. return(back_buffer);
  1686.  
  1687. } // end DD_Lock_Back_Surface
  1688.  
  1689. ///////////////////////////////////////////////////////////   
  1690.    
  1691. int DD_Unlock_Back_Surface(void)
  1692. {
  1693. // this unlocks the secondary
  1694.  
  1695. // is this surface valid
  1696. if (!back_buffer)
  1697.    return(0);
  1698.  
  1699. // unlock the secondary surface
  1700. lpddsback->Unlock(NULL);
  1701.  
  1702. // reset the secondary surface
  1703. back_buffer = NULL;
  1704. back_lpitch = 0;
  1705.  
  1706. // return success
  1707. return(1);
  1708. } // end DD_Unlock_Back_Surface
  1709.  
  1710. ///////////////////////////////////////////////////////////
  1711.  
  1712. DWORD Get_Clock(void)
  1713. {
  1714. // this function returns the current tick count
  1715.  
  1716. // return time
  1717. return(GetTickCount());
  1718.  
  1719. } // end Get_Clock
  1720.  
  1721. ///////////////////////////////////////////////////////////
  1722.  
  1723. DWORD Start_Clock(void)
  1724. {
  1725. // this function starts the clock, that is, saves the current
  1726. // count, use in conjunction with Wait_Clock()
  1727.  
  1728. return(start_clock_count = Get_Clock());
  1729.  
  1730. } // end Start_Clock
  1731.  
  1732. ////////////////////////////////////////////////////////////
  1733.  
  1734. DWORD Wait_Clock(DWORD count)
  1735. {
  1736. // this function is used to wait for a specific number of clicks
  1737. // since the call to Start_Clock
  1738.  
  1739. while((Get_Clock() - start_clock_count) < count);
  1740. return(Get_Clock());
  1741.  
  1742. } // end Wait_Clock
  1743.  
  1744. ///////////////////////////////////////////////////////////
  1745.  
  1746. int Draw_Clip_Line(int x0,int y0, int x1, int y1,USHORT color, 
  1747.                     UCHAR *dest_buffer, int lpitch)
  1748. {
  1749. // this function draws a wireframe triangle
  1750.  
  1751. int cxs, cys,
  1752.     cxe, cye;
  1753.  
  1754. // clip and draw each line
  1755. cxs = x0;
  1756. cys = y0;
  1757. cxe = x1;
  1758. cye = y1;
  1759.  
  1760. // clip the line
  1761. if (Clip_Line(cxs,cys,cxe,cye))
  1762.     Draw_Line(cxs, cys, cxe,cye,color,dest_buffer,lpitch);
  1763.  
  1764. // return success
  1765. return(1);
  1766.  
  1767. } // end Draw_Clip_Line
  1768.  
  1769.  
  1770. ///////////////////////////////////////////////////////////
  1771.  
  1772. int Draw_Clip_Line16(int x0,int y0, int x1, int y1,USHORT color, 
  1773.                     UCHAR *dest_buffer, int lpitch)
  1774. {
  1775. // this function draws a wireframe triangle
  1776.  
  1777. int cxs, cys,
  1778.     cxe, cye;
  1779.  
  1780. // clip and draw each line
  1781. cxs = x0;
  1782. cys = y0;
  1783. cxe = x1;
  1784. cye = y1;
  1785.  
  1786. // clip the line
  1787. if (Clip_Line(cxs,cys,cxe,cye))
  1788.     Draw_Line16(cxs, cys, cxe,cye,color,dest_buffer,lpitch);
  1789.  
  1790. // return success
  1791. return(1);
  1792.  
  1793. } // end Draw_Clip_Line16
  1794.  
  1795. ///////////////////////////////////////////////////////////
  1796.  
  1797. int Clip_Line(int &x1,int &y1,int &x2, int &y2)
  1798. {
  1799. // this function clips the sent line using the globally defined clipping
  1800. // region
  1801.  
  1802. // internal clipping codes
  1803. #define CLIP_CODE_C  0x0000
  1804. #define CLIP_CODE_N  0x0008
  1805. #define CLIP_CODE_S  0x0004
  1806. #define CLIP_CODE_E  0x0002
  1807. #define CLIP_CODE_W  0x0001
  1808.  
  1809. #define CLIP_CODE_NE 0x000a
  1810. #define CLIP_CODE_SE 0x0006
  1811. #define CLIP_CODE_NW 0x0009 
  1812. #define CLIP_CODE_SW 0x0005
  1813.  
  1814. int xc1=x1, 
  1815.     yc1=y1, 
  1816.     xc2=x2, 
  1817.     yc2=y2;
  1818.  
  1819. int p1_code=0, 
  1820.     p2_code=0;
  1821.  
  1822. // determine codes for p1 and p2
  1823. if (y1 < min_clip_y)
  1824.     p1_code|=CLIP_CODE_N;
  1825. else
  1826. if (y1 > max_clip_y)
  1827.     p1_code|=CLIP_CODE_S;
  1828.  
  1829. if (x1 < min_clip_x)
  1830.     p1_code|=CLIP_CODE_W;
  1831. else
  1832. if (x1 > max_clip_x)
  1833.     p1_code|=CLIP_CODE_E;
  1834.  
  1835. if (y2 < min_clip_y)
  1836.     p2_code|=CLIP_CODE_N;
  1837. else
  1838. if (y2 > max_clip_y)
  1839.     p2_code|=CLIP_CODE_S;
  1840.  
  1841. if (x2 < min_clip_x)
  1842.     p2_code|=CLIP_CODE_W;
  1843. else
  1844. if (x2 > max_clip_x)
  1845.     p2_code|=CLIP_CODE_E;
  1846.  
  1847. // try and trivially reject
  1848. if ((p1_code & p2_code)) 
  1849.     return(0);
  1850.  
  1851. // test for totally visible, if so leave points untouched
  1852. if (p1_code==0 && p2_code==0)
  1853.     return(1);
  1854.  
  1855. // determine end clip point for p1
  1856. switch(p1_code)
  1857.       {
  1858.       case CLIP_CODE_C: break;
  1859.  
  1860.       case CLIP_CODE_N:
  1861.            {
  1862.            yc1 = min_clip_y;
  1863.            xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1864.            } break;
  1865.       case CLIP_CODE_S:
  1866.            {
  1867.            yc1 = max_clip_y;
  1868.            xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  1869.            } break;
  1870.  
  1871.       case CLIP_CODE_W:
  1872.            {
  1873.            xc1 = min_clip_x;
  1874.            yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  1875.            } break;
  1876.         
  1877.       case CLIP_CODE_E:
  1878.            {
  1879.            xc1 = max_clip_x;
  1880.            yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1881.            } break;
  1882.  
  1883.     // these cases are more complex, must compute 2 intersections
  1884.       case CLIP_CODE_NE:
  1885.            {
  1886.            // north hline intersection
  1887.            yc1 = min_clip_y;
  1888.            xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1889.  
  1890.            // test if intersection is valid, of so then done, else compute next
  1891.             if (xc1 < min_clip_x || xc1 > max_clip_x)
  1892.                 {
  1893.                 // east vline intersection
  1894.                 xc1 = max_clip_x;
  1895.                 yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1896.                 } // end if
  1897.  
  1898.            } break;
  1899.       
  1900.       case CLIP_CODE_SE:
  1901.              {
  1902.            // south hline intersection
  1903.            yc1 = max_clip_y;
  1904.            xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);    
  1905.  
  1906.            // test if intersection is valid, of so then done, else compute next
  1907.            if (xc1 < min_clip_x || xc1 > max_clip_x)
  1908.               {
  1909.               // east vline intersection
  1910.               xc1 = max_clip_x;
  1911.               yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1912.               } // end if
  1913.  
  1914.            } break;
  1915.         
  1916.       case CLIP_CODE_NW: 
  1917.              {
  1918.            // north hline intersection
  1919.            yc1 = min_clip_y;
  1920.            xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1921.            
  1922.            // test if intersection is valid, of so then done, else compute next
  1923.            if (xc1 < min_clip_x || xc1 > max_clip_x)
  1924.               {
  1925.               xc1 = min_clip_x;
  1926.               yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);    
  1927.               } // end if
  1928.  
  1929.            } break;
  1930.             
  1931.       case CLIP_CODE_SW:
  1932.            {
  1933.            // south hline intersection
  1934.            yc1 = max_clip_y;
  1935.            xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);    
  1936.            
  1937.            // test if intersection is valid, of so then done, else compute next
  1938.            if (xc1 < min_clip_x || xc1 > max_clip_x)
  1939.               {
  1940.               xc1 = min_clip_x;
  1941.               yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);    
  1942.               } // end if
  1943.  
  1944.            } break;
  1945.  
  1946.       default:break;
  1947.  
  1948.       } // end switch
  1949.  
  1950. // determine clip point for p2
  1951. switch(p2_code)
  1952.       {
  1953.       case CLIP_CODE_C: break;
  1954.  
  1955.       case CLIP_CODE_N:
  1956.            {
  1957.            yc2 = min_clip_y;
  1958.            xc2 = x2 + (min_clip_y-y2)*(x1-x2)/(y1-y2);
  1959.            } break;
  1960.  
  1961.       case CLIP_CODE_S:
  1962.            {
  1963.            yc2 = max_clip_y;
  1964.            xc2 = x2 + (max_clip_y-y2)*(x1-x2)/(y1-y2);
  1965.            } break;
  1966.  
  1967.       case CLIP_CODE_W:
  1968.            {
  1969.            xc2 = min_clip_x;
  1970.            yc2 = y2 + (min_clip_x-x2)*(y1-y2)/(x1-x2);
  1971.            } break;
  1972.         
  1973.       case CLIP_CODE_E:
  1974.            {
  1975.            xc2 = max_clip_x;
  1976.            yc2 = y2 + (max_clip_x-x2)*(y1-y2)/(x1-x2);
  1977.            } break;
  1978.  
  1979.         // these cases are more complex, must compute 2 intersections
  1980.       case CLIP_CODE_NE:
  1981.            {
  1982.            // north hline intersection
  1983.            yc2 = min_clip_y;
  1984.            xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
  1985.  
  1986.            // test if intersection is valid, of so then done, else compute next
  1987.             if (xc2 < min_clip_x || xc2 > max_clip_x)
  1988.                 {
  1989.                 // east vline intersection
  1990.                 xc2 = max_clip_x;
  1991.                 yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
  1992.                 } // end if
  1993.  
  1994.            } break;
  1995.       
  1996.       case CLIP_CODE_SE:
  1997.              {
  1998.            // south hline intersection
  1999.            yc2 = max_clip_y;
  2000.            xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);    
  2001.  
  2002.            // test if intersection is valid, of so then done, else compute next
  2003.            if (xc2 < min_clip_x || xc2 > max_clip_x)
  2004.               {
  2005.               // east vline intersection
  2006.               xc2 = max_clip_x;
  2007.               yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
  2008.               } // end if
  2009.  
  2010.            } break;
  2011.         
  2012.       case CLIP_CODE_NW: 
  2013.              {
  2014.            // north hline intersection
  2015.            yc2 = min_clip_y;
  2016.            xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
  2017.            
  2018.            // test if intersection is valid, of so then done, else compute next
  2019.            if (xc2 < min_clip_x || xc2 > max_clip_x)
  2020.               {
  2021.               xc2 = min_clip_x;
  2022.               yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);    
  2023.               } // end if
  2024.  
  2025.            } break;
  2026.             
  2027.       case CLIP_CODE_SW:
  2028.            {
  2029.            // south hline intersection
  2030.            yc2 = max_clip_y;
  2031.            xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);    
  2032.            
  2033.            // test if intersection is valid, of so then done, else compute next
  2034.            if (xc2 < min_clip_x || xc2 > max_clip_x)
  2035.               {
  2036.               xc2 = min_clip_x;
  2037.               yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);    
  2038.               } // end if
  2039.  
  2040.            } break;
  2041.     
  2042.       default:break;
  2043.  
  2044.       } // end switch
  2045.  
  2046. // do bounds check
  2047. if ((xc1 < min_clip_x) || (xc1 > max_clip_x) ||
  2048.     (yc1 < min_clip_y) || (yc1 > max_clip_y) ||
  2049.     (xc2 < min_clip_x) || (xc2 > max_clip_x) ||
  2050.     (yc2 < min_clip_y) || (yc2 > max_clip_y) )
  2051.     {
  2052.     return(0);
  2053.     } // end if
  2054.  
  2055. // store vars back
  2056. x1 = xc1;
  2057. y1 = yc1;
  2058. x2 = xc2;
  2059. y2 = yc2;
  2060.  
  2061. return(1);
  2062.  
  2063. } // end Clip_Line
  2064.  
  2065. ///////////////////////////////////////////////////////////
  2066.  
  2067. int Draw_Line(int xo, int yo, int x1,int y1, USHORT color,
  2068.                UCHAR *vb_start,int lpitch)
  2069. {
  2070. // this function draws a line from xo,yo to x1,y1 using differential error
  2071. // terms (based on Bresenahams work)
  2072.  
  2073. int dx,             // difference in x's
  2074.     dy,             // difference in y's
  2075.     x_inc,          // amount in pixel space to move during drawing
  2076.     y_inc,          // amount in pixel space to move during drawing
  2077.     error=0,        // the discriminant i.e. error i.e. decision variable
  2078.     index;          // used for looping
  2079.  
  2080. // pre-compute first pixel address in video buffer
  2081. vb_start = vb_start + xo + yo*lpitch;
  2082.  
  2083. // compute horizontal and vertical deltas
  2084. dx = x1-xo;
  2085. dy = y1-yo;
  2086.  
  2087. // test which direction the line is going in i.e. slope angle
  2088. if (dx>=0)
  2089.    {
  2090.    x_inc = 1;
  2091.  
  2092.    } // end if line is moving right
  2093. else
  2094.    {
  2095.    x_inc = -1;
  2096.    dx    = -dx;  // need absolute value
  2097.  
  2098.    } // end else moving left
  2099.  
  2100. // test y component of slope
  2101.  
  2102. if (dy>=0)
  2103.    {
  2104.    y_inc = lpitch;
  2105.    } // end if line is moving down
  2106. else
  2107.    {
  2108.    y_inc = -lpitch;
  2109.    dy    = -dy;  // need absolute value
  2110.  
  2111.    } // end else moving up
  2112.  
  2113. // now based on which delta is greater we can draw the line
  2114. if (dx>dy)
  2115.    {
  2116.    // draw the line
  2117.    for (index=0; index<=dx; index++)
  2118.        {
  2119.        // set the pixel
  2120.        *vb_start = (UCHAR)color;
  2121.  
  2122.        // adjust the error term
  2123.        error+=dy;
  2124.  
  2125.        // test if error has overflowed
  2126.        if (error>dx)
  2127.           {
  2128.           error-=dx;
  2129.  
  2130.           // move to next line
  2131.           vb_start+=y_inc;
  2132.  
  2133.  
  2134.        } // end if error overflowed
  2135.  
  2136.        // move to the next pixel
  2137.        vb_start+=x_inc;
  2138.  
  2139.        } // end for
  2140.  
  2141.    } // end if |slope| <= 1
  2142. else
  2143.    {
  2144.    // draw the line
  2145.    for (index=0; index<=dy; index++)
  2146.        {
  2147.        // set the pixel
  2148.        *vb_start = (UCHAR)color;
  2149.  
  2150.        // adjust the error term
  2151.        error+=dx;
  2152.  
  2153.        // test if error overflowed
  2154.        if (error>0)
  2155.           {
  2156.           error-=dy;
  2157.  
  2158.           // move to next line
  2159.           vb_start+=x_inc;
  2160.  
  2161.           } // end if error overflowed
  2162.  
  2163.        // move to the next pixel
  2164.        vb_start+=y_inc;
  2165.  
  2166.        } // end for
  2167.  
  2168.    } // end else |slope| > 1
  2169.  
  2170. // return success
  2171. return(1);
  2172.  
  2173. } // end Draw_Line
  2174.  
  2175. ///////////////////////////////////////////////////////////
  2176.  
  2177. int Draw_Line16(int xo, int yo, int x1,int y1, USHORT color,
  2178.                UCHAR *vb_start,int lpitch)
  2179. {
  2180. // this function draws a line from xo,yo to x1,y1 using differential error
  2181. // terms (based on Bresenahams work)
  2182.  
  2183. int dx,             // difference in x's
  2184.     dy,             // difference in y's
  2185.     x_inc,          // amount in pixel space to move during drawing
  2186.     y_inc,          // amount in pixel space to move during drawing
  2187.     error=0,        // the discriminant i.e. error i.e. decision variable
  2188.     index;          // used for looping
  2189.  
  2190. // pre-compute first pixel address in video buffer
  2191. USHORT *vb_start16 = (USHORT *)vb_start + xo + yo*(lpitch >> 1);
  2192.  
  2193. // compute horizontal and vertical deltas
  2194. dx = x1-xo;
  2195. dy = y1-yo;
  2196.  
  2197. // test which direction the line is going in i.e. slope angle
  2198. if (dx>=0)
  2199.    {
  2200.    x_inc = 1;
  2201.  
  2202.    } // end if line is moving right
  2203. else
  2204.    {
  2205.    x_inc = -1;
  2206.    dx    = -dx;  // need absolute value
  2207.  
  2208.    } // end else moving left
  2209.  
  2210. // test y component of slope
  2211.  
  2212. if (dy>=0)
  2213.    {
  2214.    y_inc = (lpitch >> 1);
  2215.    } // end if line is moving down
  2216. else
  2217.    {
  2218.    y_inc = -(lpitch >> 1);
  2219.    dy    = -dy;  // need absolute value
  2220.  
  2221.    } // end else moving up
  2222.  
  2223. // now based on which delta is greater we can draw the line
  2224. if (dx>dy)
  2225.    {
  2226.    // draw the line
  2227.    for (index=0; index<=dx; index++)
  2228.        {
  2229.        // set the pixel
  2230.        *vb_start16 = color;
  2231.  
  2232.        // adjust the error term
  2233.        error+=dy;
  2234.  
  2235.        // test if error has overflowed
  2236.        if (error>dx)
  2237.           {
  2238.           error-=dx;
  2239.  
  2240.           // move to next line
  2241.           vb_start16+=y_inc;
  2242.  
  2243.  
  2244.        } // end if error overflowed
  2245.  
  2246.        // move to the next pixel
  2247.        vb_start16+=x_inc;
  2248.  
  2249.        } // end for
  2250.  
  2251.    } // end if |slope| <= 1
  2252. else
  2253.    {
  2254.    // draw the line
  2255.    for (index=0; index<=dy; index++)
  2256.        {
  2257.        // set the pixel
  2258.        *vb_start16 = color;
  2259.  
  2260.        // adjust the error term
  2261.        error+=dx;
  2262.  
  2263.        // test if error overflowed
  2264.        if (error>0)
  2265.           {
  2266.           error-=dy;
  2267.  
  2268.           // move to next line
  2269.           vb_start16+=x_inc;
  2270.  
  2271.           } // end if error overflowed
  2272.  
  2273.        // move to the next pixel
  2274.        vb_start16+=y_inc;
  2275.  
  2276.        } // end for
  2277.  
  2278.    } // end else |slope| > 1
  2279.  
  2280. // return success
  2281. return(1);
  2282.  
  2283. } // end Draw_Line16
  2284.  
  2285.  
  2286. ///////////////////////////////////////////////////////////   
  2287.    
  2288. int Draw_Pixel(int x, int y,int color,
  2289.                UCHAR *video_buffer, int lpitch)
  2290. {
  2291. // this function plots a single pixel at x,y with color
  2292.  
  2293. video_buffer[x + y*lpitch] = color;
  2294.  
  2295. // return success
  2296. return(1);
  2297.  
  2298. } // end Draw_Pixel
  2299.  
  2300.  
  2301. ///////////////////////////////////////////////////////////   
  2302.    
  2303. int Draw_Pixel16(int x, int y,int color,
  2304.                UCHAR *video_buffer, int lpitch)
  2305. {
  2306. // this function plots a single pixel at x,y with color
  2307.  
  2308. ((USHORT *)video_buffer)[x + y*(lpitch>>1)] = color;
  2309.  
  2310. // return success
  2311. return(1);
  2312.  
  2313. } // end Draw_Pixel16
  2314.  
  2315. ///////////////////////////////////////////////////////////   
  2316.    
  2317. int Draw_Rectangle(int x1, int y1, int x2, int y2, int color,
  2318.                    LPDIRECTDRAWSURFACE7 lpdds)
  2319. {
  2320. // this function uses directdraw to draw a filled rectangle
  2321.  
  2322. DDBLTFX ddbltfx; // this contains the DDBLTFX structure
  2323. RECT fill_area;  // this contains the destination rectangle
  2324.  
  2325. // clear out the structure and set the size field 
  2326. DD_INIT_STRUCT(ddbltfx);
  2327.  
  2328. // set the dwfillcolor field to the desired color
  2329. ddbltfx.dwFillColor = color; 
  2330.  
  2331. // fill in the destination rectangle data (your data)
  2332. fill_area.top    = y1;
  2333. fill_area.left   = x1;
  2334. fill_area.bottom = y2;
  2335. fill_area.right  = x2;
  2336.  
  2337. // ready to blt to surface, in this case blt to primary
  2338. lpdds->Blt(&fill_area, // ptr to dest rectangle
  2339.            NULL,       // ptr to source surface, NA            
  2340.            NULL,       // ptr to source rectangle, NA
  2341.            DDBLT_COLORFILL | DDBLT_WAIT,   // fill and wait                   
  2342.            &ddbltfx);  // ptr to DDBLTFX structure
  2343.  
  2344. // return success
  2345. return(1);
  2346.  
  2347. } // end Draw_Rectangle
  2348.  
  2349. ///////////////////////////////////////////////////////////
  2350.    
  2351. int Set_Palette_Entry(int color_index, LPPALETTEENTRY color)
  2352. {
  2353. // this function sets a palette color in the palette
  2354. lpddpal->SetEntries(0,color_index,1,color);
  2355.  
  2356. // set data in shadow palette
  2357. memcpy(&palette[color_index],color,sizeof(PALETTEENTRY));
  2358.  
  2359. // return success
  2360. return(1);
  2361. } // end Set_Palette_Entry
  2362.  
  2363. ///////////////////////////////////////////////////////////   
  2364.    
  2365. int Get_Palette_Entry(int color_index,LPPALETTEENTRY color)
  2366. {
  2367. // this function retrieves a palette entry from the color
  2368. // palette
  2369.  
  2370. // copy data out from shadow palette
  2371. memcpy(color, &palette[color_index],sizeof(PALETTEENTRY));
  2372.  
  2373. // return success
  2374. return(1);
  2375. } // end Get_Palette_Entry
  2376.  
  2377. ///////////////////////////////////////////////////////////
  2378.    
  2379. int Load_Palette_From_File(char *filename, LPPALETTEENTRY palette)
  2380. {
  2381. // this function loads a palette from disk into a palette
  2382. // structure, but does not set the pallette
  2383.  
  2384. FILE *fp_file; // working file
  2385.  
  2386. // try and open file
  2387. if ((fp_file = fopen(filename,"r"))==NULL)
  2388.    return(0);
  2389.  
  2390. // read in all 256 colors RGBF
  2391. for (int index=0; index<256; index++)
  2392.     {
  2393.     // read the next entry in
  2394.     fscanf(fp_file,"%d %d %d %d",&palette[index].peRed,
  2395.                                  &palette[index].peGreen,
  2396.                                  &palette[index].peBlue,                                
  2397.                                  &palette[index].peFlags);
  2398.     } // end for index
  2399.  
  2400. // close the file
  2401. fclose(fp_file);
  2402.  
  2403. // return success
  2404. return(1);
  2405. } // end Load_Palette_From_Disk
  2406.  
  2407. ///////////////////////////////////////////////////////////   
  2408.    
  2409. int Save_Palette_To_File(char *filename, LPPALETTEENTRY palette)
  2410. {
  2411. // this function saves a palette to disk
  2412.  
  2413. FILE *fp_file; // working file
  2414.  
  2415. // try and open file
  2416. if ((fp_file = fopen(filename,"w"))==NULL)
  2417.    return(0);
  2418.  
  2419. // write in all 256 colors RGBF
  2420. for (int index=0; index<256; index++)
  2421.     {
  2422.     // read the next entry in
  2423.     fprintf(fp_file,"\n%d %d %d %d",palette[index].peRed,
  2424.                                     palette[index].peGreen,
  2425.                                     palette[index].peBlue,                                
  2426.                                     palette[index].peFlags);
  2427.     } // end for index
  2428.  
  2429. // close the file
  2430. fclose(fp_file);
  2431.  
  2432. // return success
  2433. return(1);
  2434.  
  2435. } // end Save_Palette_To_Disk
  2436.  
  2437. ///////////////////////////////////////////////////////////
  2438.  
  2439. int Save_Palette(LPPALETTEENTRY sav_palette)
  2440. {
  2441. // this function saves the current palette 
  2442.  
  2443. memcpy(sav_palette, palette,256*sizeof(PALETTEENTRY));
  2444.  
  2445. // return success
  2446. return(1);
  2447. } // end Save_Palette
  2448.  
  2449. ///////////////////////////////////////////////////////////   
  2450.    
  2451. int Set_Palette(LPPALETTEENTRY set_palette)
  2452. {
  2453. // this function writes the sent palette
  2454.  
  2455. // first save the new palette in shadow
  2456. memcpy(palette, set_palette,256*sizeof(PALETTEENTRY));
  2457.  
  2458. // now set the new palette
  2459. lpddpal->SetEntries(0,0,256,palette);
  2460.  
  2461. // return success
  2462. return(1);
  2463. } // end Set_Palette
  2464.  
  2465. ///////////////////////////////////////////////////////////
  2466.  
  2467. int Rotate_Colors(int start_index, int colors)
  2468. {
  2469. // this function rotates the color between start and end
  2470.  
  2471. PALETTEENTRY work_pal[256]; // working palette
  2472.  
  2473. // get the color palette
  2474. lpddpal->GetEntries(0,start_index,colors,work_pal);
  2475.  
  2476. // shift the colors
  2477. lpddpal->SetEntries(0,start_index+1,colors-1,work_pal);
  2478.  
  2479. // fix up the last color
  2480. lpddpal->SetEntries(0,start_index,1,&work_pal[colors - 1]);
  2481.  
  2482. // update shadow palette
  2483. lpddpal->GetEntries(0,0,256,palette);
  2484.  
  2485. // return sucess
  2486. return(1);
  2487.  
  2488. } // end Rotate_Colors
  2489.  
  2490. ///////////////////////////////////////////////////////////   
  2491.    
  2492. int Blink_Colors(void)
  2493. {
  2494. // this funciton blinks a set of lights
  2495. // not implemented
  2496.  
  2497. // return success
  2498. return(1);
  2499. } // end Blink_Colors
  2500.  
  2501. ///////////////////////////////////////////////////////////   
  2502.    
  2503. int Screen_Transition(void)
  2504. {
  2505. // this function performs a screen transition on the sent
  2506. // video buffer
  2507. // not implemented
  2508.  
  2509.  
  2510. // return success
  2511. return(1);
  2512. } // end Screen_Transition
  2513.  
  2514. ///////////////////////////////////////////////////////////
  2515.  
  2516. int Draw_Text_GDI(char *text, int x,int y,COLORREF color, LPDIRECTDRAWSURFACE7 lpdds)
  2517. {
  2518. // this function draws the sent text on the sent surface 
  2519. // using color index as the color in the palette
  2520.  
  2521. HDC xdc; // the working dc
  2522.  
  2523. // get the dc from surface
  2524. if (lpdds->GetDC(&xdc)!=DD_OK)
  2525.    return(0);
  2526.  
  2527. // set the colors for the text up
  2528. SetTextColor(xdc,color);
  2529.  
  2530. // set background mode to transparent so black isn't copied
  2531. SetBkMode(xdc, TRANSPARENT);
  2532.  
  2533. // draw the text a
  2534. TextOut(xdc,x,y,text,strlen(text));
  2535.  
  2536. // release the dc
  2537. lpdds->ReleaseDC(xdc);
  2538.  
  2539. // return success
  2540. return(1);
  2541. } // end Draw_Text_GDI
  2542.  
  2543. ///////////////////////////////////////////////////////////
  2544.  
  2545. int Draw_Text_GDI(char *text, int x,int y,int color, LPDIRECTDRAWSURFACE7 lpdds)
  2546. {
  2547. // this function draws the sent text on the sent surface 
  2548. // using color index as the color in the palette
  2549.  
  2550. HDC xdc; // the working dc
  2551.  
  2552. // get the dc from surface
  2553. if (lpdds->GetDC(&xdc)!=DD_OK)
  2554.    return(0);
  2555.  
  2556. // set the colors for the text up
  2557. SetTextColor(xdc,RGB(palette[color].peRed,palette[color].peGreen,palette[color].peBlue) );
  2558.  
  2559. // set background mode to transparent so black isn't copied
  2560. SetBkMode(xdc, TRANSPARENT);
  2561.  
  2562. // draw the text a
  2563. TextOut(xdc,x,y,text,strlen(text));
  2564.  
  2565. // release the dc
  2566. lpdds->ReleaseDC(xdc);
  2567.  
  2568. // return success
  2569. return(1);
  2570. } // end Draw_Text_GDI
  2571.  
  2572. ///////////////////////////////////////////////////////////
  2573.  
  2574. int Open_Error_File(char *filename)
  2575. {
  2576. // this function opens the output error file
  2577.  
  2578. FILE *fp_temp; // temporary file
  2579.  
  2580. // test if this file is valid
  2581. if ((fp_temp = fopen(filename,"w"))==NULL)
  2582.    return(0);
  2583.  
  2584. // close old file if there was one
  2585. if (fp_error)
  2586.    Close_Error_File();
  2587.  
  2588. // assign new file
  2589.  
  2590. fp_error = fp_temp;
  2591.  
  2592. // write out header
  2593. Write_Error("\nOpening Error Output File (%s):\n",filename);
  2594.  
  2595. // return success
  2596. return(1);
  2597.  
  2598. } // end Open_Error_File
  2599.  
  2600. ///////////////////////////////////////////////////////////
  2601.  
  2602. int Close_Error_File(void)
  2603. {
  2604. // this function closes the error file
  2605.  
  2606. if (fp_error)
  2607.     {
  2608.     // write close file string
  2609.     Write_Error("\nClosing Error Output File.");
  2610.  
  2611.     // close the file handle
  2612.     fclose(fp_error);
  2613.     fp_error = NULL;
  2614.  
  2615.     // return success
  2616.     return(1);
  2617.     } // end if
  2618. else
  2619.    return(0);
  2620.  
  2621. } // end Close_Error_File
  2622.  
  2623. ///////////////////////////////////////////////////////////
  2624.  
  2625. int Write_Error(char *string, ...)
  2626. {
  2627. // this function prints out the error string to the error file
  2628.  
  2629. char buffer[80]; // working buffer
  2630.  
  2631. va_list arglist; // variable argument list
  2632.  
  2633. // make sure both the error file and string are valid
  2634. if (!string || !fp_error)
  2635.    return(0);
  2636.  
  2637. // print out the string using the variable number of arguments on stack
  2638. va_start(arglist,string);
  2639. vsprintf(buffer,string,arglist);
  2640. va_end(arglist);
  2641.  
  2642. // write string to file
  2643. fprintf(fp_error,buffer);
  2644.  
  2645. // return success
  2646. return(1);
  2647. } // end Write_Error
  2648.  
  2649. ///////////////////////////////////////////////////////////////////////////////
  2650.  
  2651. int Create_Bitmap(BITMAP_IMAGE_PTR image, int x, int y, int width, int height)
  2652. {
  2653. // this function is used to intialize a bitmap
  2654.  
  2655. // allocate the memory
  2656. if (!(image->buffer = (UCHAR *)malloc(width*height)))
  2657.    return(0);
  2658.  
  2659. // initialize variables
  2660. image->state     = BITMAP_STATE_ALIVE;
  2661. image->attr      = 0;
  2662. image->width     = width;
  2663. image->height    = height;
  2664. image->bpp       = 8;
  2665. image->x         = x;
  2666. image->y         = y;
  2667. image->num_bytes = width*height;
  2668.  
  2669. // clear memory out
  2670. memset(image->buffer,0,width*height);
  2671.  
  2672. // return success
  2673. return(1);
  2674.  
  2675. } // end Create_Bitmap
  2676. ///////////////////////////////////////////////////////////////////////////////
  2677.  
  2678. int Create_Bitmap16(BITMAP_IMAGE_PTR image, int x, int y, int width, int height)
  2679. {
  2680. // this function is used to intialize a bitmap
  2681.  
  2682. // allocate the memory
  2683. if (!(image->buffer = (UCHAR *)malloc(width*height*2)))
  2684.    return(0);
  2685.  
  2686. // initialize variables
  2687. image->state     = BITMAP_STATE_ALIVE;
  2688. image->attr      = 0;
  2689. image->width     = width;
  2690. image->height    = height;
  2691. image->bpp       = 16;
  2692. image->x         = x;
  2693. image->y         = y;
  2694. image->num_bytes = width*height*2;
  2695.  
  2696. // clear memory out
  2697. memset(image->buffer,0,width*height*2);
  2698.  
  2699. // return success
  2700. return(1);
  2701.  
  2702. } // end Create_Bitmap16
  2703.  
  2704. ///////////////////////////////////////////////////////////////////////////////
  2705.  
  2706. int Destroy_Bitmap(BITMAP_IMAGE_PTR image)
  2707. {
  2708. // this function releases the memory associated with a bitmap
  2709.  
  2710. if (image && image->buffer)
  2711.    {
  2712.    // free memory and reset vars
  2713.    free(image->buffer);
  2714.  
  2715.    // set all vars in structure to 0
  2716.    memset(image,0,sizeof(BITMAP_IMAGE));
  2717.  
  2718.    // return success
  2719.    return(1);
  2720.  
  2721.    } // end if
  2722. else  // invalid entry pointer of the object wasn't initialized
  2723.    return(0);
  2724.  
  2725. } // end Destroy_Bitmap
  2726.  
  2727. ///////////////////////////////////////////////////////////////////////////////
  2728.  
  2729. int Destroy_Bitmap16(BITMAP_IMAGE_PTR image)
  2730. {
  2731. // this function releases the memory associated with a bitmap
  2732.  
  2733. if (image && image->buffer)
  2734.    {
  2735.    // free memory and reset vars
  2736.    free(image->buffer);
  2737.  
  2738.    // set all vars in structure to 0
  2739.    memset(image,0,sizeof(BITMAP_IMAGE));
  2740.  
  2741.    // return success
  2742.    return(1);
  2743.  
  2744.    } // end if
  2745. else  // invalid entry pointer of the object wasn't initialized
  2746.    return(0);
  2747.  
  2748. } // end Destroy_Bitmap16
  2749.  
  2750. ///////////////////////////////////////////////////////////
  2751.  
  2752. int Draw_Bitmap(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
  2753. {
  2754. // this function draws the bitmap onto the destination memory surface
  2755. // if transparent is 1 then color 0 will be transparent
  2756. // note this function does NOT clip, so be carefull!!!
  2757.  
  2758. UCHAR *dest_addr,   // starting address of bitmap in destination
  2759.       *source_addr; // starting adddress of bitmap data in source
  2760.  
  2761. UCHAR pixel;        // used to hold pixel value
  2762.  
  2763. int index,          // looping vars
  2764.     pixel_x;
  2765.  
  2766. // test if this bitmap is loaded
  2767.  
  2768. if (source_bitmap->attr & BITMAP_ATTR_LOADED)
  2769.    {
  2770.    // compute starting destination address
  2771.    dest_addr = dest_buffer + (int)source_bitmap->y*lpitch + (int)source_bitmap->x;
  2772.  
  2773.    // compute the starting source address
  2774.    source_addr = source_bitmap->buffer;
  2775.  
  2776.    // is this bitmap transparent
  2777.    if (transparent)
  2778.    {
  2779.    // copy each line of bitmap into destination with transparency
  2780.    for (index=0; index<source_bitmap->height; index++)
  2781.        {
  2782.        // copy the memory
  2783.        for (pixel_x=0; pixel_x<source_bitmap->width; pixel_x++)
  2784.            {
  2785.            if ((pixel = source_addr[pixel_x])!=0)
  2786.                dest_addr[pixel_x] = pixel;
  2787.  
  2788.            } // end if
  2789.  
  2790.        // advance all the pointers
  2791.        dest_addr   += lpitch;
  2792.        source_addr += source_bitmap->width;
  2793.  
  2794.        } // end for index
  2795.    } // end if
  2796.    else
  2797.    {
  2798.    // non-transparent version
  2799.    // copy each line of bitmap into destination
  2800.  
  2801.    for (index=0; index<source_bitmap->height; index++)
  2802.        {
  2803.        // copy the memory
  2804.        memcpy(dest_addr, source_addr, source_bitmap->width);
  2805.  
  2806.        // advance all the pointers
  2807.        dest_addr   += lpitch;
  2808.        source_addr += source_bitmap->width;
  2809.  
  2810.        } // end for index
  2811.  
  2812.    } // end else
  2813.  
  2814.    // return success
  2815.    return(1);
  2816.  
  2817.    } // end if
  2818. else
  2819.    return(0);
  2820.  
  2821. } // end Draw_Bitmap
  2822.  
  2823. ///////////////////////////////////////////////////////////
  2824.  
  2825. int Draw_Bitmap16(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
  2826. {
  2827. // this function draws the bitmap onto the destination memory surface
  2828. // if transparent is 1 then color 0 will be transparent
  2829. // note this function does NOT clip, so be carefull!!!
  2830.  
  2831. USHORT *dest_addr,   // starting address of bitmap in destination
  2832.        *source_addr; // starting adddress of bitmap data in source
  2833.  
  2834. USHORT pixel;        // used to hold pixel value
  2835.  
  2836. int index,          // looping vars
  2837.     pixel_x;
  2838.  
  2839. // test if this bitmap is loaded
  2840.  
  2841. if (source_bitmap->attr & BITMAP_ATTR_LOADED)
  2842.    {
  2843.    // compute starting destination address
  2844.    dest_addr = (USHORT *)dest_buffer + (int)source_bitmap->y*(lpitch >> 1) + (int)source_bitmap->x;
  2845.  
  2846.    // compute the starting source address
  2847.    source_addr = (USHORT *)source_bitmap->buffer;
  2848.  
  2849.    // is this bitmap transparent
  2850.    if (transparent)
  2851.    {
  2852.    // copy each line of bitmap into destination with transparency
  2853.    for (index=0; index<source_bitmap->height; index++)
  2854.        {
  2855.        // copy the memory
  2856.        for (pixel_x=0; pixel_x < source_bitmap->width; pixel_x++)
  2857.            {
  2858.            if ((pixel = source_addr[pixel_x])!=0)
  2859.                dest_addr[pixel_x] = pixel;
  2860.  
  2861.            } // end if
  2862.  
  2863.        // advance all the pointers
  2864.        dest_addr   += (lpitch >> 1);
  2865.        source_addr += source_bitmap->width;
  2866.  
  2867.        } // end for index
  2868.    } // end if
  2869.    else
  2870.    {
  2871.    // non-transparent version
  2872.    // copy each line of bitmap into destination
  2873.  
  2874.    for (index=0; index<source_bitmap->height; index++)
  2875.        {
  2876.        // copy the memory
  2877.        memcpy(dest_addr, source_addr, source_bitmap->width*2);
  2878.  
  2879.        // advance all the pointers
  2880.        dest_addr   += (lpitch >> 1);
  2881.        source_addr += source_bitmap->width;
  2882.  
  2883.        } // end for index
  2884.  
  2885.    } // end else
  2886.  
  2887.    // return success
  2888.    return(1);
  2889.  
  2890.    } // end if
  2891. else
  2892.    return(0);
  2893.  
  2894. } // end Draw_Bitmap16
  2895.  
  2896. ///////////////////////////////////////////////////////////////////////////////
  2897.  
  2898.  
  2899. int Load_Image_Bitmap(BITMAP_IMAGE_PTR image, // bitmap image to load with data
  2900.                       BITMAP_FILE_PTR bitmap,    // bitmap to scan image data from
  2901.                       int cx,int cy,   // cell or absolute pos. to scan image from
  2902.                       int mode)        // if 0 then cx,cy is cell position, else 
  2903.                                     // cx,cy are absolute coords
  2904. {
  2905. // this function extracts a bitmap out of a bitmap file
  2906.  
  2907. UCHAR *source_ptr,   // working pointers
  2908.       *dest_ptr;
  2909.  
  2910. // is this a valid bob
  2911. if (!image)
  2912.    return(0);
  2913.  
  2914. // test the mode of extraction, cell based or absolute
  2915. if (mode==BITMAP_EXTRACT_MODE_CELL)
  2916.    {
  2917.    // re-compute x,y
  2918.    cx = cx*(image->width+1) + 1;
  2919.    cy = cy*(image->height+1) + 1;
  2920.    } // end if
  2921.  
  2922. // extract bitmap data
  2923. source_ptr = bitmap->buffer +
  2924.       cy*bitmap->bitmapinfoheader.biWidth+cx;
  2925.  
  2926. // assign a pointer to the bimap image
  2927. dest_ptr = (UCHAR *)image->buffer;
  2928.  
  2929. // iterate thru each scanline and copy bitmap
  2930. for (int index_y=0; index_y < image->height; index_y++)
  2931.     {
  2932.     // copy next line of data to destination
  2933.     memcpy(dest_ptr, source_ptr,image->width);
  2934.  
  2935.     // advance pointers
  2936.     dest_ptr   += image->width;
  2937.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  2938.     } // end for index_y
  2939.  
  2940. // set state to loaded
  2941. image->attr |= BITMAP_ATTR_LOADED;
  2942.  
  2943. // return success
  2944. return(1);
  2945.  
  2946. } // end Load_Image_Bitmap
  2947.  
  2948. //////////////////////////////////////////////////////////////////
  2949.  
  2950. int Load_Image_Bitmap16(BITMAP_IMAGE_PTR image, // bitmap image to load with data
  2951.                       BITMAP_FILE_PTR bitmap,    // bitmap to scan image data from
  2952.                       int cx,int cy,   // cell or absolute pos. to scan image from
  2953.                       int mode)        // if 0 then cx,cy is cell position, else 
  2954.                                     // cx,cy are absolute coords
  2955. {
  2956. // this function extracts a bitmap out of a bitmap file
  2957.  
  2958. USHORT *source_ptr,   // working pointers
  2959.        *dest_ptr;
  2960.  
  2961. // is this a valid bob
  2962. if (!image)
  2963.    return(0);
  2964.  
  2965. // test the mode of extraction, cell based or absolute
  2966. if (mode==BITMAP_EXTRACT_MODE_CELL)
  2967.    {
  2968.    // re-compute x,y
  2969.    cx = cx*(image->width+1) + 1;
  2970.    cy = cy*(image->height+1) + 1;
  2971.    } // end if
  2972.  
  2973. // extract bitmap data
  2974. source_ptr = (USHORT *)bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  2975.  
  2976. // assign a pointer to the bimap image
  2977. dest_ptr = (USHORT *)image->buffer;
  2978.  
  2979. // iterate thru each scanline and copy bitmap
  2980. for (int index_y=0; index_y < image->height; index_y++)
  2981.     {
  2982.     // copy next line of data to destination
  2983.     memcpy(dest_ptr, source_ptr,image->width*2);
  2984.  
  2985.     // advance pointers
  2986.     dest_ptr   += image->width;
  2987.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  2988.     } // end for index_y
  2989.  
  2990. // set state to loaded
  2991. image->attr |= BITMAP_ATTR_LOADED;
  2992.  
  2993. // return success
  2994. return(1);
  2995.  
  2996. } // end Load_Image_Bitmap16
  2997.  
  2998. ///////////////////////////////////////////////////////////
  2999.  
  3000. int Scroll_Bitmap(void)
  3001. {
  3002. // this function scrolls a bitmap
  3003. // not implemented
  3004.  
  3005. // return success
  3006. return(1);
  3007. } // end Scroll_Bitmap
  3008. ///////////////////////////////////////////////////////////
  3009.  
  3010. int Copy_Bitmap(void)
  3011. {
  3012. // this function copies a bitmap from one source to another
  3013. // not implemented
  3014.  
  3015.  
  3016. // return success
  3017. return(1);
  3018. } // end Copy_Bitmap
  3019.  
  3020. ///////////////////////////////////////////////////////////
  3021.  
  3022. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
  3023. {
  3024. // this function opens a bitmap file and loads the data into bitmap
  3025.  
  3026. int file_handle,  // the file handle
  3027.     index;        // looping index
  3028.  
  3029. UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
  3030. OFSTRUCT file_data;        // the file data information
  3031.  
  3032. // open the file if it exists
  3033. if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
  3034.    return(0);
  3035.  
  3036. // now load the bitmap file header
  3037. _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
  3038.  
  3039. // test if this is a bitmap file
  3040. if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
  3041.    {
  3042.    // close the file
  3043.    _lclose(file_handle);
  3044.  
  3045.    // return error
  3046.    return(0);
  3047.    } // end if
  3048.  
  3049. // now we know this is a bitmap, so read in all the sections
  3050.  
  3051. // first the bitmap infoheader
  3052.  
  3053. // now load the bitmap file header
  3054. _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
  3055.  
  3056. // now load the color palette if there is one
  3057. if (bitmap->bitmapinfoheader.biBitCount == 8)
  3058.    {
  3059.    _lread(file_handle, &bitmap->palette,256*sizeof(PALETTEENTRY));
  3060.  
  3061.    // now set all the flags in the palette correctly and fix the reversed 
  3062.    // BGR RGBQUAD data format
  3063.    for (index=0; index < 256; index++)
  3064.        {
  3065.        // reverse the red and green fields
  3066.        int temp_color = bitmap->palette[index].peRed;
  3067.        bitmap->palette[index].peRed  = bitmap->palette[index].peBlue;
  3068.        bitmap->palette[index].peBlue = temp_color;
  3069.        
  3070.        // always set the flags word to this
  3071.        bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
  3072.        } // end for index
  3073.  
  3074.     } // end if
  3075.  
  3076. // finally the image data itself
  3077. _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
  3078.  
  3079. // now read in the image, if the image is 8 or 16 bit then simply read it
  3080. // but if its 24 bit then read it into a temporary area and then convert
  3081. // it to a 16 bit image
  3082.  
  3083. if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16)
  3084.    {
  3085.    // delete the last image if there was one
  3086.    if (bitmap->buffer)
  3087.        free(bitmap->buffer);
  3088.  
  3089.    // allocate the memory for the image
  3090.    if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  3091.       {
  3092.       // close the file
  3093.       _lclose(file_handle);
  3094.  
  3095.       // return error
  3096.       return(0);
  3097.       } // end if
  3098.  
  3099.    // now read it in
  3100.    _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
  3101.  
  3102.    } // end if
  3103. else
  3104.    {
  3105.    // this must be a 24 bit image, load it in and convert it to 16 bit
  3106. //   printf("\nconverting 24 bit image...");
  3107.  
  3108.    // allocate temporary buffer
  3109.    if (!(temp_buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  3110.       {
  3111.       // close the file
  3112.       _lclose(file_handle);
  3113.  
  3114.       // return error
  3115.       return(0);
  3116.       } // end if
  3117.    
  3118.    // allocate final 16 bit storage buffer
  3119.    if (!(bitmap->buffer=(UCHAR *)malloc(2*bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight)))
  3120.       {
  3121.       // close the file
  3122.       _lclose(file_handle);
  3123.  
  3124.       // release working buffer
  3125.       free(temp_buffer);
  3126.  
  3127.       // return error
  3128.       return(0);
  3129.       } // end if
  3130.  
  3131.    // now read it in
  3132.    _lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);
  3133.  
  3134.    // now convert each 24 bit RGB value into a 16 bit value
  3135.    for (index=0; index<bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight; index++)
  3136.        {
  3137.        // extract RGB components (note they are in memory BGR)
  3138.        // also, assume 5.6.5 format, so scale appropriately
  3139.        UCHAR red    = (temp_buffer[index*3 + 2] >> 3), // 5 bits
  3140.              green  = (temp_buffer[index*3 + 1] >> 2), // 6 bits, change to 3 for 5 bits
  3141.              blue   = (temp_buffer[index*3 + 0] >> 3); // 5 bits
  3142.  
  3143.        // build up 16 bit color word assume 5.6.5 format
  3144.        USHORT color = _RGB16BIT565(red,green,blue);
  3145.  
  3146.        // write color to buffer
  3147.        ((USHORT *)bitmap->buffer)[index] = color;
  3148.  
  3149.        } // end for index
  3150.  
  3151.    // finally write out the correct number of bits
  3152.    bitmap->bitmapinfoheader.biBitCount=16;
  3153.  
  3154.    } // end if
  3155.  
  3156. #if 0
  3157. // write the file info out 
  3158. printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
  3159.         filename,
  3160.         bitmap->bitmapinfoheader.biSizeImage,
  3161.         bitmap->bitmapinfoheader.biWidth,
  3162.         bitmap->bitmapinfoheader.biHeight,
  3163.         bitmap->bitmapinfoheader.biBitCount,
  3164.         bitmap->bitmapinfoheader.biClrUsed,
  3165.         bitmap->bitmapinfoheader.biClrImportant);
  3166. #endif
  3167.  
  3168. // close the file
  3169. _lclose(file_handle);
  3170.  
  3171. // flip the bitmap
  3172. Flip_Bitmap(bitmap->buffer, 
  3173.             bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8), 
  3174.             bitmap->bitmapinfoheader.biHeight);
  3175.  
  3176. // return success
  3177. return(1);
  3178.  
  3179. } // end Load_Bitmap_File
  3180.  
  3181. ///////////////////////////////////////////////////////////
  3182.  
  3183. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
  3184. {
  3185. // this function releases all memory associated with "bitmap"
  3186. if (bitmap->buffer)
  3187.    {
  3188.    // release memory
  3189.    free(bitmap->buffer);
  3190.  
  3191.    // reset pointer
  3192.    bitmap->buffer = NULL;
  3193.  
  3194.    } // end if
  3195.  
  3196. // return success
  3197. return(1);
  3198.  
  3199. } // end Unload_Bitmap_File
  3200.  
  3201. ///////////////////////////////////////////////////////////
  3202.  
  3203. int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
  3204. {
  3205. // this function is used to flip upside down .BMP images
  3206.  
  3207. UCHAR *buffer; // used to perform the image processing
  3208. int index;     // looping index
  3209.  
  3210. // allocate the temporary buffer
  3211. if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
  3212.    return(0);
  3213.  
  3214. // copy image to work area
  3215. memcpy(buffer,image,bytes_per_line*height);
  3216.  
  3217. // flip vertically
  3218. for (index=0; index < height; index++)
  3219.     memcpy(&image[((height-1) - index)*bytes_per_line],
  3220.            &buffer[index*bytes_per_line], bytes_per_line);
  3221.  
  3222. // release the memory
  3223. free(buffer);
  3224.  
  3225. // return success
  3226. return(1);
  3227.  
  3228. } // end Flip_Bitmap
  3229.  
  3230. ///////////////////////////////////////////////////////////
  3231.  
  3232.