t3dlib1.cpp
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:175k
源码类别:

游戏

开发平台:

Visual C++

  1. // T3DLIB1.CPP - Game Engine Part I
  2.  
  3. // INCLUDES ///////////////////////////////////////////////
  4. #define WIN32_LEAN_AND_MEAN  
  5. // has the GUID library been included?
  6. //#ifndef INITGUID
  7. //#define INITGUID
  8. //#endif
  9. #define DEBUG_ON
  10. #include <windows.h>   // include important windows stuff
  11. #include <windowsx.h> 
  12. #include <mmsystem.h>
  13. #include <iostream.h> // include important C/C++ stuff
  14. #include <conio.h>
  15. #include <stdlib.h>
  16. #include <malloc.h>
  17. #include <memory.h>
  18. #include <string.h>
  19. #include <stdarg.h>
  20. #include <stdio.h>
  21. #include <math.h>
  22. #include <io.h>
  23. #include <fcntl.h>
  24. #include <sys/timeb.h>
  25. #include <time.h>
  26. #include <ddraw.h>    // directX includes
  27. #include "T3DLIB1.H"
  28. // DEFINES ////////////////////////////////////////////////
  29. // TYPES //////////////////////////////////////////////////
  30. // PROTOTYPES /////////////////////////////////////////////
  31. // EXTERNALS /////////////////////////////////////////////
  32. extern HWND main_window_handle; // save the window handle
  33. extern HINSTANCE main_instance; // save the instance
  34. // GLOBALS ////////////////////////////////////////////////
  35. FILE *fp_error                    = NULL; // general error file
  36. char error_filename[80];                  // error file name
  37. // notice that interface 7.0 is used on a number of interfaces
  38. LPDIRECTDRAW7        lpdd         = NULL;  // dd object
  39. LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;  // dd primary surface
  40. LPDIRECTDRAWSURFACE7 lpddsback    = NULL;  // dd back surface
  41. LPDIRECTDRAWPALETTE  lpddpal      = NULL;  // a pointer to the created dd palette
  42. LPDIRECTDRAWCLIPPER  lpddclipper  = NULL;   // dd clipper for back surface
  43. LPDIRECTDRAWCLIPPER  lpddclipperwin = NULL; // dd clipper for window
  44. PALETTEENTRY         palette[MAX_COLORS_PALETTE];         // color palette
  45. PALETTEENTRY         save_palette[MAX_COLORS_PALETTE];    // 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 for primary buffer
  53. int                  back_lpitch     = 0;    // memory line pitch for back buffer
  54. BITMAP_FILE          bitmap8bit;             // a 8 bit bitmap file
  55. BITMAP_FILE          bitmap16bit;            // a 16 bit bitmap file
  56. BITMAP_FILE          bitmap24bit;            // a 24 bit bitmap file
  57. DWORD                start_clock_count = 0;     // used for timing
  58. int                  windowed_mode     = FALSE; // tracks if dd is windowed or not
  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. // these are overwritten globally by DDraw_Init()
  65. int screen_width    = SCREEN_WIDTH,            // width of screen
  66.     screen_height   = SCREEN_HEIGHT,           // height of screen
  67.     screen_bpp      = SCREEN_BPP,              // bits per pixel
  68.     screen_windowed = 0;                       // is this a windowed app?    
  69. int dd_pixel_format = DD_PIXEL_FORMAT565;  // default pixel format
  70. int window_client_x0   = 0;   // used to track the starting (x,y) client area for
  71. int window_client_y0   = 0;   // for windowed mode directdraw operations
  72. // storage for our lookup tables
  73. float cos_look[361]; // 1 extra element so we can store 0-360 inclusive
  74. float sin_look[361];
  75. // function ptr to RGB16 builder
  76. USHORT (*RGB16Bit)(int r, int g, int b) = NULL;
  77. // conditionally compilation for engine stats
  78. int debug_total_polys_per_frame = 0;
  79. int debug_polys_lit_per_frame = 0;
  80. int debug_polys_clipped_per_frame = 0;
  81. int debug_polys_rendered_per_frame = 0;
  82. int debug_backfaces_removed_per_frame = 0;
  83. int debug_objects_removed_per_frame = 0;
  84. int debug_total_transformations_per_frame = 0;
  85. // FUNCTIONS //////////////////////////////////////////////
  86. USHORT RGB16Bit565(int r, int g, int b)
  87. {
  88. // this function simply builds a 5.6.5 format 16 bit pixel
  89. // assumes input is RGB 0-255 each channel
  90. r>>=3; g>>=2; b>>=3;
  91. return(_RGB16BIT565((r),(g),(b)));
  92. } // end RGB16Bit565
  93. //////////////////////////////////////////////////////////
  94. USHORT RGB16Bit555(int r, int g, int b)
  95. {
  96. // this function simply builds a 5.5.5 format 16 bit pixel
  97. // assumes input is RGB 0-255 each channel
  98. r>>=3; g>>=3; b>>=3;
  99. return(_RGB16BIT555((r),(g),(b)));
  100. } // end RGB16Bit555
  101. //////////////////////////////////////////////////////////
  102. #if 0 
  103. inline void Mem_Set_WORD(void *dest, USHORT data, int count)
  104. {
  105. // this function fills or sets unsigned 16-bit aligned memory
  106. // count is number of words
  107. //Write_Error("{");
  108. _asm 
  109.     { 
  110.     mov edi, dest   ; edi points to destination memory
  111.     mov ecx, count  ; number of 16-bit words to move
  112.     mov ax,  data   ; 16-bit data
  113.     rep stosw       ; move data
  114.     } // end asm
  115. //Write_Error("}");
  116. } // end Mem_Set_WORD
  117. ///////////////////////////////////////////////////////////
  118. inline void Mem_Set_QUAD(void *dest, UINT data, int count)
  119. {
  120. // this function fills or sets unsigned 32-bit aligned memory
  121. // count is number of quads
  122. _asm 
  123.     { 
  124.     mov edi, dest   ; edi points to destination memory
  125.     mov ecx, count  ; number of 32-bit words to move
  126.     mov eax, data   ; 32-bit data
  127.     rep stosd       ; move data
  128.     } // end asm
  129. } // end Mem_Set_QUAD
  130. #endif
  131. //////////////////////////////////////////////////////////
  132. int Create_BOB(BOB_PTR bob,           // the bob to create
  133.                int x, int y,          // initial posiiton
  134.                int width, int height, // size of bob
  135.                int num_frames,        // number of frames
  136.                int attr,              // attrs
  137.                int mem_flags,         // memory flags in DD format
  138.                USHORT color_key_value, // default color key
  139.                int bpp)                // bits per pixel
  140. {
  141. // Create the BOB object, note that all BOBs 
  142. // are created as offscreen surfaces in VRAM as the
  143. // default, if you want to use system memory then
  144. // set flags equal to:
  145. // DDSCAPS_SYSTEMMEMORY 
  146. // for video memory you can create either local VRAM surfaces or AGP 
  147. // surfaces via the second set of constants shown below in the regular expression
  148. // DDSCAPS_VIDEOMEMORY | (DDSCAPS_NONLOCALVIDMEM | DDSCAPS_LOCALVIDMEM ) 
  149. DDSURFACEDESC2 ddsd; // used to create surface
  150. int index;           // looping var
  151. // set state and attributes of BOB
  152. bob->state          = BOB_STATE_ALIVE;
  153. bob->attr           = attr;
  154. bob->anim_state     = 0;
  155. bob->counter_1      = 0;     
  156. bob->counter_2      = 0;
  157. bob->max_count_1    = 0;
  158. bob->max_count_2    = 0;
  159. bob->curr_frame     = 0;
  160. bob->num_frames     = num_frames;
  161. bob->bpp            = bpp;
  162. bob->curr_animation = 0;
  163. bob->anim_counter   = 0;
  164. bob->anim_index     = 0;
  165. bob->anim_count_max = 0; 
  166. bob->x              = x;
  167. bob->y              = y;
  168. bob->xv             = 0;
  169. bob->yv             = 0;
  170. // set dimensions of the new bitmap surface
  171. bob->width  = width;
  172. bob->height = height;
  173. // set all images to null
  174. for (index=0; index<MAX_BOB_FRAMES; index++)
  175.     bob->images[index] = NULL;
  176. // set all animations to null
  177. for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  178.     bob->animations[index] = NULL;
  179. #if 0
  180. // make sure surface width is a multiple of 8, some old version of dd like that
  181. // now, it's unneeded...
  182. bob->width_fill = ((width%8!=0) ? (8-width%8) : 0);
  183. Write_Error("nCreate BOB: width_fill=%d",bob->width_fill);
  184. #endif
  185. // now create each surface
  186. for (index=0; index<bob->num_frames; index++)
  187.     {
  188.     // set to access caps, width, and height
  189.     memset(&ddsd,0,sizeof(ddsd));
  190.     ddsd.dwSize  = sizeof(ddsd);
  191.     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  192.     ddsd.dwWidth  = bob->width + bob->width_fill;
  193.     ddsd.dwHeight = bob->height;
  194.     // set surface to offscreen plain
  195.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
  196.     // create the surfaces, return failure if problem
  197.     if (FAILED(lpdd->CreateSurface(&ddsd,&(bob->images[index]),NULL)))
  198.         return(0);
  199.     // set color key to default color 000
  200.     // note that if this is a 8bit bob then palette index 0 will be 
  201.     // transparent by default
  202.     // note that if this is a 16bit bob then RGB value 000 will be 
  203.     // transparent
  204.     DDCOLORKEY color_key; // used to set color key
  205.     color_key.dwColorSpaceLowValue  = color_key_value;
  206.     color_key.dwColorSpaceHighValue = color_key_value;
  207.     // now set the color key for source blitting
  208.     (bob->images[index])->SetColorKey(DDCKEY_SRCBLT, &color_key);
  209.     
  210.     } // end for index
  211. // return success
  212. return(1);
  213. } // end Create_BOB
  214. ///////////////////////////////////////////////////////////
  215. int Clone_BOB(BOB_PTR source, BOB_PTR dest)
  216. {
  217. // this function clones a BOB and updates the attr var to reflect that
  218. // the BOB is a clone and not real, this is used later in the destroy
  219. // function so a clone doesn't destroy the memory of a real bob
  220. if ((source && dest) && (source!=dest))
  221.    {
  222.    // copy the bob data
  223.    memcpy(dest,source, sizeof(BOB));
  224.    // set the clone attribute
  225.    dest->attr |= BOB_ATTR_CLONE;
  226.    } // end if
  227. else
  228.     return(0);
  229. // return success
  230. return(1);
  231. } // end Clone_BOB
  232. ///////////////////////////////////////////////////////////
  233. int Destroy_BOB(BOB_PTR bob)
  234. {
  235. // destroy the BOB, tests if this is a real bob or a clone
  236. // if real then release all the memory, otherwise, just resets
  237. // the pointers to null
  238. int index; // looping var
  239. // is this bob valid
  240. if (!bob)
  241.     return(0);
  242. // test if this is a clone
  243. if ((bob->attr & BOB_ATTR_CLONE))
  244.     {
  245.     // null link all surfaces
  246.     for (index=0; index<MAX_BOB_FRAMES; index++)
  247.         if (bob->images[index])
  248.             bob->images[index]=NULL;
  249.     // release memory for animation sequences 
  250.     for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  251.         if (bob->animations[index])
  252.             bob->animations[index]=NULL;
  253.     } // end if
  254. else
  255.     {
  256.     // destroy each bitmap surface
  257.     for (index=0; index<MAX_BOB_FRAMES; index++)
  258.         if (bob->images[index])
  259.             (bob->images[index])->Release();
  260.     // release memory for animation sequences 
  261.     for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  262.         if (bob->animations[index])
  263.             free(bob->animations[index]);
  264.     } // end else not clone
  265. // return success
  266. return(1);
  267. } // end Destroy_BOB
  268. ///////////////////////////////////////////////////////////
  269. int Draw_BOB(BOB_PTR bob,               // bob to draw
  270.              LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on
  271. {
  272. // draw a bob at the x,y defined in the BOB
  273. // on the destination surface defined in dest
  274. RECT dest_rect,   // the destination rectangle
  275.      source_rect; // the source rectangle                             
  276. // is this a valid bob
  277. if (!bob)
  278.     return(0);
  279. // is bob visible
  280. if (!(bob->attr & BOB_ATTR_VISIBLE))
  281.    return(1);
  282. // fill in the destination rect
  283. dest_rect.left   = bob->x;
  284. dest_rect.top    = bob->y;
  285. dest_rect.right  = bob->x+bob->width;
  286. dest_rect.bottom = bob->y+bob->height;
  287. // fill in the source rect
  288. source_rect.left    = 0;
  289. source_rect.top     = 0;
  290. source_rect.right   = bob->width;
  291. source_rect.bottom  = bob->height;
  292. // blt to destination surface
  293. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  294.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  295.           NULL)))
  296.     return(0);
  297. // return success
  298. return(1);
  299. } // end Draw_BOB
  300. ///////////////////////////////////////////////////////////
  301. int Draw_Scaled_BOB(BOB_PTR bob, int swidth, int sheight,  // bob and new dimensions
  302.                     LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on)
  303. {
  304. // this function draws a scaled bob to the size swidth, sheight
  305. RECT dest_rect,   // the destination rectangle
  306.      source_rect; // the source rectangle                             
  307. // is this a valid bob
  308. if (!bob)
  309.     return(0);
  310. // is bob visible
  311. if (!(bob->attr & BOB_ATTR_VISIBLE))
  312.    return(1);
  313. // fill in the destination rect
  314. dest_rect.left   = bob->x;
  315. dest_rect.top    = bob->y;
  316. dest_rect.right  = bob->x+swidth;
  317. dest_rect.bottom = bob->y+sheight;
  318. // fill in the source rect
  319. source_rect.left    = 0;
  320. source_rect.top     = 0;
  321. source_rect.right   = bob->width;
  322. source_rect.bottom  = bob->height;
  323. // blt to destination surface
  324. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  325.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  326.           NULL)))
  327.     return(0);
  328. // return success
  329. return(1);
  330. } // end Draw_Scaled_BOB
  331. ////////////////////////////////////////////////////
  332. int Draw_BOB16(BOB_PTR bob,             // bob to draw
  333.              LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on
  334. {
  335. // draw a bob at the x,y defined in the BOB
  336. // on the destination surface defined in dest
  337. RECT dest_rect,   // the destination rectangle
  338.      source_rect; // the source rectangle                             
  339. // is this a valid bob
  340. if (!bob)
  341.     return(0);
  342. // is bob visible
  343. if (!(bob->attr & BOB_ATTR_VISIBLE))
  344.    return(1);
  345. // fill in the destination rect
  346. dest_rect.left   = bob->x;
  347. dest_rect.top    = bob->y;
  348. dest_rect.right  = bob->x+bob->width;
  349. dest_rect.bottom = bob->y+bob->height;
  350. // fill in the source rect
  351. source_rect.left    = 0;
  352. source_rect.top     = 0;
  353. source_rect.right   = bob->width;
  354. source_rect.bottom  = bob->height;
  355. // blt to destination surface
  356. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  357.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  358.           NULL)))
  359.     return(0);
  360. // return success
  361. return(1);
  362. } // end Draw_BOB16
  363. ///////////////////////////////////////////////////////////
  364. int Draw_Scaled_BOB16(BOB_PTR bob, int swidth, int sheight,  // bob and new dimensions
  365.                     LPDIRECTDRAWSURFACE7 dest) // surface to draw the bob on)
  366. {
  367. // this function draws a scaled bob to the size swidth, sheight
  368. RECT dest_rect,   // the destination rectangle
  369.      source_rect; // the source rectangle                             
  370. // is this a valid bob
  371. if (!bob)
  372.     return(0);
  373. // is bob visible
  374. if (!(bob->attr & BOB_ATTR_VISIBLE))
  375.    return(1);
  376. // fill in the destination rect
  377. dest_rect.left   = bob->x;
  378. dest_rect.top    = bob->y;
  379. dest_rect.right  = bob->x+swidth;
  380. dest_rect.bottom = bob->y+sheight;
  381. // fill in the source rect
  382. source_rect.left    = 0;
  383. source_rect.top     = 0;
  384. source_rect.right   = bob->width;
  385. source_rect.bottom  = bob->height;
  386. // blt to destination surface
  387. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  388.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  389.           NULL)))
  390.     return(0);
  391. // return success
  392. return(1);
  393. } // end Draw_Scaled_BOB16
  394. ///////////////////////////////////////////////////////////
  395. int Load_Frame_BOB(BOB_PTR bob, // bob to load with data
  396.                    BITMAP_FILE_PTR bitmap, // bitmap to scan image data from
  397.                    int frame,       // frame to load
  398.                    int cx,int cy,   // cell or absolute pos. to scan image from
  399.                    int mode)        // if 0 then cx,cy is cell position, else 
  400.                                     // cx,cy are absolute coords
  401. {
  402. // this function extracts a bitmap out of a bitmap file
  403. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  404. // is this a valid bob
  405. if (!bob)
  406.    return(0);
  407. UCHAR *source_ptr,   // working pointers
  408.       *dest_ptr;
  409. // test the mode of extraction, cell based or absolute
  410. if (mode==BITMAP_EXTRACT_MODE_CELL)
  411.    {
  412.    // re-compute x,y
  413.    cx = cx*(bob->width+1) + 1;
  414.    cy = cy*(bob->height+1) + 1;
  415.    } // end if
  416. // extract bitmap data
  417. source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  418. // get the addr to destination surface memory
  419. // set size of the structure
  420. ddsd.dwSize = sizeof(ddsd);
  421. // lock the display surface
  422. (bob->images[frame])->Lock(NULL,
  423.                            &ddsd,
  424.                            DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  425.                            NULL);
  426. // assign a pointer to the memory surface for manipulation
  427. dest_ptr = (UCHAR *)ddsd.lpSurface;
  428. // iterate thru each scanline and copy bitmap
  429. for (int index_y=0; index_y<bob->height; index_y++)
  430.     {
  431.     // copy next line of data to destination
  432.     memcpy(dest_ptr, source_ptr,bob->width);
  433.     // advance pointers
  434.     dest_ptr   += (ddsd.lPitch); // (bob->width+bob->width_fill);
  435.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  436.     } // end for index_y
  437. // unlock the surface 
  438. (bob->images[frame])->Unlock(NULL);
  439. // set state to loaded
  440. bob->attr |= BOB_ATTR_LOADED;
  441. // return success
  442. return(1);
  443. } // end Load_Frame_BOB
  444. ///////////////////////////////////////////////////////////////
  445. int Load_Frame_BOB16(BOB_PTR bob, // bob to load with data
  446.                      BITMAP_FILE_PTR bitmap, // bitmap to scan image data from
  447.                      int frame,       // frame to load
  448.                      int cx,int cy,   // cell or absolute pos. to scan image from
  449.                      int mode)        // if 0 then cx,cy is cell position, else 
  450.                                     // cx,cy are absolute coords
  451. {
  452. // this function extracts a 16-bit bitmap out of a 16-bit bitmap file
  453. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  454. // is this a valid bob
  455. if (!bob)
  456.    return(0);
  457. USHORT *source_ptr,   // working pointers
  458.        *dest_ptr;
  459. // test the mode of extraction, cell based or absolute
  460. if (mode==BITMAP_EXTRACT_MODE_CELL)
  461.    {
  462.    // re-compute x,y
  463.    cx = cx*(bob->width+1) + 1;
  464.    cy = cy*(bob->height+1) + 1;
  465.    } // end if
  466. // extract bitmap data
  467. source_ptr = (USHORT *)bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  468. // get the addr to destination surface memory
  469. // set size of the structure
  470. ddsd.dwSize = sizeof(ddsd);
  471. // lock the display surface
  472. (bob->images[frame])->Lock(NULL,
  473.                            &ddsd,
  474.                            DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  475.                            NULL);
  476. // assign a pointer to the memory surface for manipulation
  477. dest_ptr = (USHORT *)ddsd.lpSurface;
  478. // iterate thru each scanline and copy bitmap
  479. for (int index_y=0; index_y<bob->height; index_y++)
  480.     {
  481.     // copy next line of data to destination
  482.     memcpy(dest_ptr, source_ptr,(bob->width*2));
  483.     // advance pointers
  484.     dest_ptr   += (ddsd.lPitch >> 1); 
  485.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  486.     } // end for index_y
  487. // unlock the surface 
  488. (bob->images[frame])->Unlock(NULL);
  489. // set state to loaded
  490. bob->attr |= BOB_ATTR_LOADED;
  491. // return success
  492. return(1);
  493. } // end Load_Frame_BOB16
  494. ///////////////////////////////////////////////////////////
  495. int Animate_BOB(BOB_PTR bob)
  496. {
  497. // this function animates a bob, basically it takes a look at
  498. // the attributes of the bob and determines if the bob is 
  499. // a single frame, multiframe, or multi animation, updates
  500. // the counters and frames appropriately
  501. // is this a valid bob
  502. if (!bob)
  503.    return(0);
  504. // test the level of animation
  505. if (bob->attr & BOB_ATTR_SINGLE_FRAME)
  506.     {
  507.     // current frame always = 0
  508.     bob->curr_frame = 0;
  509.     return(1);
  510.     } // end if
  511. else
  512. if (bob->attr & BOB_ATTR_MULTI_FRAME)
  513.    {
  514.    // update the counter and test if its time to increment frame
  515.    if (++bob->anim_counter >= bob->anim_count_max)
  516.       {
  517.       // reset counter
  518.       bob->anim_counter = 0;
  519.       // move to next frame
  520.       if (++bob->curr_frame >= bob->num_frames)
  521.          bob->curr_frame = 0;
  522.       } // end if
  523.   
  524.    } // end elseif
  525. else
  526. if (bob->attr & BOB_ATTR_MULTI_ANIM)
  527.    {
  528.    // this is the most complex of the animations it must look up the
  529.    // next frame in the animation sequence
  530.    // first test if its time to animate
  531.    if (++bob->anim_counter >= bob->anim_count_max)
  532.       {
  533.       // reset counter
  534.       bob->anim_counter = 0;
  535.       // increment the animation frame index
  536.       bob->anim_index++;
  537.       
  538.       // extract the next frame from animation list 
  539.       bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  540.      
  541.       // is this and end sequence flag -1
  542.       if (bob->curr_frame == -1)
  543.          {
  544.          // test if this is a single shot animation
  545.          if (bob->attr & BOB_ATTR_ANIM_ONE_SHOT)
  546.             {
  547.             // set animation state message to done
  548.             bob->anim_state = BOB_STATE_ANIM_DONE;
  549.             
  550.             // reset frame back one
  551.             bob->anim_index--;
  552.             // extract animation frame
  553.             bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];    
  554.             } // end if
  555.         else
  556.            {
  557.            // reset animation index
  558.            bob->anim_index = 0;
  559.            // extract first animation frame
  560.            bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  561.            } // end else
  562.          }  // end if
  563.       
  564.       } // end if
  565.    } // end elseif
  566. // return success
  567. return(1);
  568. } // end Amimate_BOB
  569. ///////////////////////////////////////////////////////////
  570. int Scroll_BOB(void)
  571. {
  572. // this function scrolls a bob 
  573. // not implemented
  574. // return success
  575. return(1);
  576. } // end Scroll_BOB
  577. ///////////////////////////////////////////////////////////
  578. int Move_BOB(BOB_PTR bob)
  579. {
  580. // this function moves the bob based on its current velocity
  581. // also, the function test for various motion attributes of the'
  582. // bob and takes the appropriate actions
  583.    
  584. // is this a valid bob
  585. if (!bob)
  586.    return(0);
  587. // translate the bob
  588. bob->x+=bob->xv;
  589. bob->y+=bob->yv;
  590. // test for wrap around
  591. if (bob->attr & BOB_ATTR_WRAPAROUND)
  592.    {
  593.    // test x extents first
  594.    if (bob->x > max_clip_x)
  595.        bob->x = min_clip_x - bob->width;
  596.    else
  597.    if (bob->x < min_clip_x-bob->width)
  598.        bob->x = max_clip_x;
  599.    
  600.    // now y extents
  601.    if (bob->x > max_clip_x)
  602.        bob->x = min_clip_x - bob->width;
  603.    else
  604.    if (bob->x < min_clip_x-bob->width)
  605.        bob->x = max_clip_x;
  606.    } // end if
  607. else
  608. // test for bounce
  609. if (bob->attr & BOB_ATTR_BOUNCE)
  610.    {
  611.    // test x extents first
  612.    if ((bob->x > max_clip_x - bob->width) || (bob->x < min_clip_x) )
  613.        bob->xv = -bob->xv;
  614.     
  615.    // now y extents 
  616.    if ((bob->y > max_clip_y - bob->height) || (bob->y < min_clip_y) )
  617.        bob->yv = -bob->yv;
  618.    } // end if
  619. // return success
  620. return(1);
  621. } // end Move_BOB
  622. ///////////////////////////////////////////////////////////
  623. int Load_Animation_BOB(BOB_PTR bob, 
  624.                        int anim_index, 
  625.                        int num_frames, 
  626.                        int *sequence)
  627. {
  628. // this function load an animation sequence for a bob
  629. // the sequence consists of frame indices, the function
  630. // will append a -1 to the end of the list so the display
  631. // software knows when to restart the animation sequence
  632. // is this bob valid
  633. if (!bob)
  634.    return(0);
  635. // allocate memory for bob animation
  636. if (!(bob->animations[anim_index] = (int *)malloc((num_frames+1)*sizeof(int))))
  637.    return(0);
  638. // load data into 
  639. for (int index=0; index<num_frames; index++)
  640.     bob->animations[anim_index][index] = sequence[index];
  641. // set the end of the list to a -1
  642. bob->animations[anim_index][index] = -1;
  643. // return success
  644. return(1);
  645. } // end Load_Animation_BOB
  646. ///////////////////////////////////////////////////////////
  647. int Set_Pos_BOB(BOB_PTR bob, int x, int y)
  648. {
  649. // this functions sets the postion of a bob
  650. // is this a valid bob
  651. if (!bob)
  652.    return(0);
  653. // set positin
  654. bob->x = x;
  655. bob->y = y;
  656. // return success
  657. return(1);
  658. } // end Set_Pos_BOB
  659. ///////////////////////////////////////////////////////////
  660. int Set_Anim_Speed_BOB(BOB_PTR bob,int speed)
  661. {
  662. // this function simply sets the animation speed of a bob
  663.     
  664. // is this a valid bob
  665. if (!bob)
  666.    return(0);
  667. // set speed
  668. bob->anim_count_max = speed;
  669. // return success
  670. return(1);
  671. } // end Set_Anim_Speed
  672. ///////////////////////////////////////////////////////////
  673. int Set_Animation_BOB(BOB_PTR bob, int anim_index)
  674. {
  675. // this function sets the animation to play
  676. // is this a valid bob
  677. if (!bob)
  678.    return(0);
  679. // set the animation index
  680. bob->curr_animation = anim_index;
  681. // reset animation 
  682. bob->anim_index = 0;
  683. // return success
  684. return(1);
  685. } // end Set_Animation_BOB
  686. ///////////////////////////////////////////////////////////
  687. int Set_Vel_BOB(BOB_PTR bob,int xv, int yv)
  688. {
  689. // this function sets the velocity of a bob
  690. // is this a valid bob
  691. if (!bob)
  692.    return(0);
  693. // set velocity
  694. bob->xv = xv;
  695. bob->yv = yv;
  696. // return success
  697. return(1);
  698. } // end Set_Vel_BOB
  699. ///////////////////////////////////////////////////////////
  700. int Hide_BOB(BOB_PTR bob)
  701. {
  702. // this functions hides bob 
  703. // is this a valid bob
  704. if (!bob)
  705.    return(0);
  706. // reset the visibility bit
  707. RESET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  708. // return success
  709. return(1);
  710. } // end Hide_BOB
  711. ///////////////////////////////////////////////////////////
  712. int Show_BOB(BOB_PTR bob)
  713. {
  714. // this function shows a bob
  715. // is this a valid bob
  716. if (!bob)
  717.    return(0);
  718. // set the visibility bit
  719. SET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  720. // return success
  721. return(1);
  722. } // end Show_BOB
  723. ///////////////////////////////////////////////////////////
  724. int Collision_BOBS(BOB_PTR bob1, BOB_PTR bob2)
  725. {
  726. // are these a valid bobs
  727. if (!bob1 || !bob2)
  728.    return(0);
  729. // get the radi of each rect
  730. int width1  = (bob1->width>>1) - (bob1->width>>3);
  731. int height1 = (bob1->height>>1) - (bob1->height>>3);
  732. int width2  = (bob2->width>>1) - (bob2->width>>3);
  733. int height2 = (bob2->height>>1) - (bob2->height>>3);
  734. // compute center of each rect
  735. int cx1 = bob1->x + width1;
  736. int cy1 = bob1->y + height1;
  737. int cx2 = bob2->x + width2;
  738. int cy2 = bob2->y + height2;
  739. // compute deltas
  740. int dx = abs(cx2 - cx1);
  741. int dy = abs(cy2 - cy1);
  742. // test if rects overlap
  743. if (dx < (width1+width2) && dy < (height1+height2))
  744.    return(1);
  745. else
  746. // else no collision
  747. return(0);
  748. } // end Collision_BOBS
  749. //////////////////////////////////////////////////////////
  750. int DDraw_Init(int width, int height, int bpp, int windowed)
  751. {
  752. // this function initializes directdraw
  753. int index; // looping variable
  754. // create IDirectDraw interface 7.0 object and test for error
  755. if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)))
  756.    return(0);
  757. // based on windowed or fullscreen set coorperation level
  758. if (windowed)
  759.    {
  760.    // set cooperation level to windowed mode 
  761.    if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,DDSCL_NORMAL)))
  762.        return(0);
  763.    } // end if
  764. else
  765.    {
  766.    // set cooperation level to fullscreen mode 
  767.    if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,
  768.               DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 
  769.               DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT | DDSCL_MULTITHREADED )))
  770.        return(0);
  771.    // set the display mode
  772.    if (FAILED(lpdd->SetDisplayMode(width,height,bpp,0,0)))
  773.       return(0);
  774.    } // end else
  775. // set globals
  776. screen_height   = height;
  777. screen_width    = width;
  778. screen_bpp      = bpp;
  779. screen_windowed = windowed;
  780. // Create the primary surface
  781. memset(&ddsd,0,sizeof(ddsd));
  782. ddsd.dwSize = sizeof(ddsd);
  783. // we need to let dd know that we want a complex 
  784. // flippable surface structure, set flags for that
  785. if (!screen_windowed)
  786.    {
  787.    // fullscreen mode
  788.    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  789.    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  790.    
  791.    // set the backbuffer count to 0 for windowed mode
  792.    // 1 for fullscreen mode, 2 for triple buffering
  793.    ddsd.dwBackBufferCount = 1;
  794.    } // end if
  795. else
  796.    {
  797.    // windowed mode
  798.    ddsd.dwFlags = DDSD_CAPS;
  799.    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  800.    // set the backbuffer count to 0 for windowed mode
  801.    // 1 for fullscreen mode, 2 for triple buffering
  802.    ddsd.dwBackBufferCount = 0;
  803.    } // end else
  804. // create the primary surface
  805. lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);
  806. // get the pixel format of the primary surface
  807. DDPIXELFORMAT ddpf; // used to get pixel format
  808. // initialize structure
  809. DDRAW_INIT_STRUCT(ddpf);
  810. // query the format from primary surface
  811. lpddsprimary->GetPixelFormat(&ddpf);
  812. // based on masks determine if system is 5.6.5 or 5.5.5
  813. //RGB Masks for 5.6.5 mode
  814. //DDPF_RGB  16 R: 0x0000F800  
  815. //             G: 0x000007E0  
  816. //             B: 0x0000001F  
  817. //RGB Masks for 5.5.5 mode
  818. //DDPF_RGB  16 R: 0x00007C00  
  819. //             G: 0x000003E0  
  820. //             B: 0x0000001F  
  821. // test for 6 bit green mask)
  822. //if (ddpf.dwGBitMask == 0x000007E0)
  823. //   dd_pixel_format = DD_PIXEL_FORMAT565;
  824. // use number of bits, better method
  825. dd_pixel_format = ddpf.dwRGBBitCount;
  826. Write_Error("npixel format = %d",dd_pixel_format);
  827. // set up conversion macros, so you don't have to test which one to use
  828. if (dd_pixel_format == DD_PIXEL_FORMAT555)
  829.    {
  830.    RGB16Bit = RGB16Bit555;
  831.    Write_Error("npixel format = 5.5.5");
  832.    } // end if
  833. else
  834.    {
  835.    RGB16Bit = RGB16Bit565;
  836.    Write_Error("npixel format = 5.6.5");
  837.    } // end else
  838. // only need a backbuffer for fullscreen modes
  839. if (!screen_windowed)
  840.    {
  841.    // query for the backbuffer i.e the secondary surface
  842.    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  843.    if (FAILED(lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback)))
  844.       return(0);
  845.    } // end if
  846. else
  847.    {
  848.    // must be windowed, so create a double buffer that will be blitted
  849.    // rather than flipped as in full screen mode
  850.    lpddsback = DDraw_Create_Surface(width, height, DDSCAPS_SYSTEMMEMORY); // int mem_flags, USHORT color_key_flag);
  851.    } // end else
  852. // create a palette only if 8bit mode
  853. if (screen_bpp==DD_PIXEL_FORMAT8)
  854. {
  855. // create and attach palette
  856. // clear all entries, defensive programming
  857. memset(palette,0,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  858. // load a pre-made "good" palette off disk
  859. Load_Palette_From_File(DEFAULT_PALETTE_FILE, palette);
  860. // load and attach the palette, test for windowed mode
  861. if (screen_windowed)
  862.    {
  863.    // in windowed mode, so the first 10 and last 10 entries have
  864.    // to be slightly modified as does the call to createpalette
  865.    // reset the peFlags bit to PC_EXPLICIT for the "windows" colors
  866.    for (index=0; index < 10; index++)
  867.        palette[index].peFlags = palette[index+246].peFlags = PC_EXPLICIT;         
  868.    // now create the palette object, but disable access to all 256 entries
  869.    if (FAILED(lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE,
  870.                                   palette,&lpddpal,NULL)))
  871.    return(0);
  872.    } // end 
  873. else
  874.    {
  875.    // in fullscreen mode, so simple create the palette with the default palette
  876.    // and fill in all 256 entries
  877.    if (FAILED(lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE | DDPCAPS_ALLOW256,
  878.                                   palette,&lpddpal,NULL)))
  879.       return(0);
  880.    } // end if
  881. // now attach the palette to the primary surface
  882. if (FAILED(lpddsprimary->SetPalette(lpddpal)))
  883.    return(0);
  884. } // end if attach palette for 8bit mode
  885. // clear out both primary and secondary surfaces
  886. if (screen_windowed)
  887.    {
  888.    // only clear backbuffer
  889.    DDraw_Fill_Surface(lpddsback,0);
  890.    } // end if
  891. else
  892.    {
  893.    // fullscreen, simply clear everything
  894.    DDraw_Fill_Surface(lpddsprimary,0);
  895.    DDraw_Fill_Surface(lpddsback,0);
  896.    } // end else
  897. // set software algorithmic clipping region
  898. min_clip_x = 0;
  899. max_clip_x = screen_width - 1;
  900. min_clip_y = 0;
  901. max_clip_y = screen_height - 1;
  902. // setup backbuffer clipper always
  903. RECT screen_rect = {0,0,screen_width,screen_height};
  904. lpddclipper = DDraw_Attach_Clipper(lpddsback,1,&screen_rect);
  905. // set up windowed mode clipper
  906. if (screen_windowed)
  907.    {
  908.    // set windowed clipper
  909.    if (FAILED(lpdd->CreateClipper(0,&lpddclipperwin,NULL)))
  910.        return(0);
  911.    if (FAILED(lpddclipperwin->SetHWnd(0, main_window_handle)))
  912.        return(0);
  913.    if (FAILED(lpddsprimary->SetClipper(lpddclipperwin)))
  914.        return(0);
  915.    } // end if screen windowed
  916. // return success
  917. return(1);
  918. } // end DDraw_Init
  919. ///////////////////////////////////////////////////////////
  920. int DDraw_Shutdown(void)
  921. {
  922. // this function release all the resources directdraw
  923. // allocated, mainly to com objects
  924. // release the clippers first
  925. if (lpddclipper)
  926.     lpddclipper->Release();
  927. if (lpddclipperwin)
  928.     lpddclipperwin->Release();
  929. // release the palette if there is one
  930. if (lpddpal)
  931.    lpddpal->Release();
  932. // release the secondary surface
  933. if (lpddsback)
  934.     lpddsback->Release();
  935. // release the primary surface
  936. if (lpddsprimary)
  937.    lpddsprimary->Release();
  938. // finally, the main dd object
  939. if (lpdd)
  940.     lpdd->Release();
  941. // return success
  942. return(1);
  943. } // end DDraw_Shutdown
  944. ///////////////////////////////////////////////////////////   
  945. LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,
  946.                                          int num_rects,
  947.                                          LPRECT clip_list)
  948. {
  949. // this function creates a clipper from the sent clip list and attaches
  950. // it to the sent surface
  951. int index;                         // looping var
  952. LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly created dd clipper
  953. LPRGNDATA region_data;             // pointer to the region data that contains
  954.                                    // the header and clip list
  955. // first create the direct draw clipper
  956. if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))
  957.    return(NULL);
  958. // now create the clip list from the sent data
  959. // first allocate memory for region data
  960. region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));
  961. // now copy the rects into region data
  962. memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);
  963. // set up fields of header
  964. region_data->rdh.dwSize          = sizeof(RGNDATAHEADER);
  965. region_data->rdh.iType           = RDH_RECTANGLES;
  966. region_data->rdh.nCount          = num_rects;
  967. region_data->rdh.nRgnSize        = num_rects*sizeof(RECT);
  968. region_data->rdh.rcBound.left    =  64000;
  969. region_data->rdh.rcBound.top     =  64000;
  970. region_data->rdh.rcBound.right   = -64000;
  971. region_data->rdh.rcBound.bottom  = -64000;
  972. // find bounds of all clipping regions
  973. for (index=0; index<num_rects; index++)
  974.     {
  975.     // test if the next rectangle unioned with the current bound is larger
  976.     if (clip_list[index].left < region_data->rdh.rcBound.left)
  977.        region_data->rdh.rcBound.left = clip_list[index].left;
  978.     if (clip_list[index].right > region_data->rdh.rcBound.right)
  979.        region_data->rdh.rcBound.right = clip_list[index].right;
  980.     if (clip_list[index].top < region_data->rdh.rcBound.top)
  981.        region_data->rdh.rcBound.top = clip_list[index].top;
  982.     if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)
  983.        region_data->rdh.rcBound.bottom = clip_list[index].bottom;
  984.     } // end for index
  985. // now we have computed the bounding rectangle region and set up the data
  986. // now let's set the clipping list
  987. if (FAILED(lpddclipper->SetClipList(region_data, 0)))
  988.    {
  989.    // release memory and return error
  990.    free(region_data);
  991.    return(NULL);
  992.    } // end if
  993. // now attach the clipper to the surface
  994. if (FAILED(lpdds->SetClipper(lpddclipper)))
  995.    {
  996.    // release memory and return error
  997.    free(region_data);
  998.    return(NULL);
  999.    } // end if
  1000. // all is well, so release memory and send back the pointer to the new clipper
  1001. free(region_data);
  1002. return(lpddclipper);
  1003. } // end DDraw_Attach_Clipper
  1004. ///////////////////////////////////////////////////////////   
  1005.    
  1006. LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width, 
  1007.                                           int height, 
  1008.                                           int mem_flags, 
  1009.                                           USHORT color_key_value)
  1010. {
  1011. // this function creates an offscreen plain surface
  1012. DDSURFACEDESC2 ddsd;         // working description
  1013. LPDIRECTDRAWSURFACE7 lpdds;  // temporary surface
  1014.     
  1015. // set to access caps, width, and height
  1016. memset(&ddsd,0,sizeof(ddsd));
  1017. ddsd.dwSize  = sizeof(ddsd);
  1018. ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  1019. // set dimensions of the new bitmap surface
  1020. ddsd.dwWidth  =  width;
  1021. ddsd.dwHeight =  height;
  1022. // set surface to offscreen plain
  1023. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
  1024. // create the surface
  1025. if (FAILED(lpdd->CreateSurface(&ddsd,&lpdds,NULL)))
  1026.    return(NULL);
  1027. // set color key to default color 000
  1028. // note that if this is a 8bit bob then palette index 0 will be 
  1029. // transparent by default
  1030. // note that if this is a 16bit bob then RGB value 000 will be 
  1031. // transparent
  1032. DDCOLORKEY color_key; // used to set color key
  1033. color_key.dwColorSpaceLowValue  = color_key_value;
  1034. color_key.dwColorSpaceHighValue = color_key_value;
  1035. // now set the color key for source blitting
  1036. lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);
  1037. // return surface
  1038. return(lpdds);
  1039. } // end DDraw_Create_Surface
  1040. ///////////////////////////////////////////////////////////   
  1041.    
  1042. int DDraw_Flip(void)
  1043. {
  1044. // this function flip the primary surface with the secondary surface
  1045. // test if either of the buffers are locked
  1046. if (primary_buffer || back_buffer)
  1047.    return(0);
  1048. // flip pages
  1049. if (!screen_windowed)
  1050.    while(FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));
  1051. else
  1052.    {
  1053.    RECT    dest_rect;    // used to compute destination rectangle
  1054.    // get the window's rectangle in screen coordinates
  1055.    GetWindowRect(main_window_handle, &dest_rect);   
  1056.    // compute the destination rectangle
  1057.    dest_rect.left   +=window_client_x0;
  1058.    dest_rect.top    +=window_client_y0;
  1059.    dest_rect.right  =dest_rect.left+screen_width-1;
  1060.    dest_rect.bottom =dest_rect.top +screen_height-1;
  1061.    // clip the screen coords 
  1062.        
  1063.    // blit the entire back surface to the primary
  1064.    if (FAILED(lpddsprimary->Blt(&dest_rect, lpddsback,NULL,DDBLT_WAIT,NULL)))
  1065.        return(0);    
  1066.    } // end if
  1067. // return success
  1068. return(1);
  1069. } // end DDraw_Flip
  1070. ///////////////////////////////////////////////////////////   
  1071.    
  1072. int DDraw_Wait_For_Vsync(void)
  1073. {
  1074. // this function waits for a vertical blank to begin
  1075.     
  1076. lpdd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);
  1077. // return success
  1078. return(1);
  1079. } // end DDraw_Wait_For_Vsync
  1080. ///////////////////////////////////////////////////////////   
  1081.    
  1082. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds, USHORT color, RECT *client)
  1083. {
  1084. DDBLTFX ddbltfx; // this contains the DDBLTFX structure
  1085. // clear out the structure and set the size field 
  1086. DDRAW_INIT_STRUCT(ddbltfx);
  1087. // set the dwfillcolor field to the desired color
  1088. ddbltfx.dwFillColor = color; 
  1089. // ready to blt to surface
  1090. lpdds->Blt(client,     // ptr to dest rectangle
  1091.            NULL,       // ptr to source surface, NA            
  1092.            NULL,       // ptr to source rectangle, NA
  1093.            DDBLT_COLORFILL | DDBLT_WAIT,   // fill and wait                   
  1094.            &ddbltfx);  // ptr to DDBLTFX structure
  1095. // return success
  1096. return(1);
  1097. } // end DDraw_Fill_Surface
  1098. ///////////////////////////////////////////////////////////   
  1099.    
  1100. UCHAR *DDraw_Lock_Surface(LPDIRECTDRAWSURFACE7 lpdds, int *lpitch)
  1101. {
  1102. // this function locks the sent surface and returns a pointer to it
  1103. // is this surface valid
  1104. if (!lpdds)
  1105.    return(NULL);
  1106. // lock the surface
  1107. DDRAW_INIT_STRUCT(ddsd);
  1108. lpdds->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1109. // set the memory pitch
  1110. if (lpitch)
  1111.    *lpitch = ddsd.lPitch;
  1112. // return pointer to surface
  1113. return((UCHAR *)ddsd.lpSurface);
  1114. } // end DDraw_Lock_Surface
  1115. ///////////////////////////////////////////////////////////   
  1116.    
  1117. int DDraw_Unlock_Surface(LPDIRECTDRAWSURFACE7 lpdds)
  1118. {
  1119. // this unlocks a general surface
  1120. // is this surface valid
  1121. if (!lpdds)
  1122.    return(0);
  1123. // unlock the surface memory
  1124. lpdds->Unlock(NULL);
  1125. // return success
  1126. return(1);
  1127. } // end DDraw_Unlock_Surface
  1128. ///////////////////////////////////////////////////////////
  1129. UCHAR *DDraw_Lock_Primary_Surface(void)
  1130. {
  1131. // this function locks the priamary surface and returns a pointer to it
  1132. // and updates the global variables primary_buffer, and primary_lpitch
  1133. // is this surface already locked
  1134. if (primary_buffer)
  1135.    {
  1136.    // return to current lock
  1137.    return(primary_buffer);
  1138.    } // end if
  1139. // lock the primary surface
  1140. DDRAW_INIT_STRUCT(ddsd);
  1141. lpddsprimary->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1142. // set globals
  1143. primary_buffer = (UCHAR *)ddsd.lpSurface;
  1144. primary_lpitch = ddsd.lPitch;
  1145. // return pointer to surface
  1146. return(primary_buffer);
  1147. } // end DDraw_Lock_Primary_Surface
  1148. ///////////////////////////////////////////////////////////   
  1149.    
  1150. int DDraw_Unlock_Primary_Surface(void)
  1151. {
  1152. // this unlocks the primary
  1153. // is this surface valid
  1154. if (!primary_buffer)
  1155.    return(0);
  1156. // unlock the primary surface
  1157. lpddsprimary->Unlock(NULL);
  1158. // reset the primary surface
  1159. primary_buffer = NULL;
  1160. primary_lpitch = 0;
  1161. // return success
  1162. return(1);
  1163. } // end DDraw_Unlock_Primary_Surface
  1164. //////////////////////////////////////////////////////////
  1165. UCHAR *DDraw_Lock_Back_Surface(void)
  1166. {
  1167. // this function locks the secondary back surface and returns a pointer to it
  1168. // and updates the global variables secondary buffer, and back_lpitch
  1169. // is this surface already locked
  1170. if (back_buffer)
  1171.    {
  1172.    // return to current lock
  1173.    return(back_buffer);
  1174.    } // end if
  1175. // lock the primary surface
  1176. DDRAW_INIT_STRUCT(ddsd);
  1177. lpddsback->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1178. // set globals
  1179. back_buffer = (UCHAR *)ddsd.lpSurface;
  1180. back_lpitch = ddsd.lPitch;
  1181. // return pointer to surface
  1182. return(back_buffer);
  1183. } // end DDraw_Lock_Back_Surface
  1184. ///////////////////////////////////////////////////////////   
  1185.    
  1186. int DDraw_Unlock_Back_Surface(void)
  1187. {
  1188. // this unlocks the secondary
  1189. // is this surface valid
  1190. if (!back_buffer)
  1191.    return(0);
  1192. // unlock the secondary surface
  1193. lpddsback->Unlock(NULL);
  1194. // reset the secondary surface
  1195. back_buffer = NULL;
  1196. back_lpitch = 0;
  1197. // return success
  1198. return(1);
  1199. } // end DDraw_Unlock_Back_Surface
  1200. ///////////////////////////////////////////////////////////
  1201. DWORD Get_Clock(void)
  1202. {
  1203. // this function returns the current tick count
  1204. // return time
  1205. return(GetTickCount());
  1206. } // end Get_Clock
  1207. ///////////////////////////////////////////////////////////
  1208. DWORD Start_Clock(void)
  1209. {
  1210. // this function starts the clock, that is, saves the current
  1211. // count, use in conjunction with Wait_Clock()
  1212. return(start_clock_count = Get_Clock());
  1213. } // end Start_Clock
  1214. ////////////////////////////////////////////////////////////
  1215. DWORD Wait_Clock(DWORD count)
  1216. {
  1217. // this function is used to wait for a specific number of clicks
  1218. // since the call to Start_Clock
  1219. while((Get_Clock() - start_clock_count) < count);
  1220. return(Get_Clock());
  1221. } // end Wait_Clock
  1222. ///////////////////////////////////////////////////////////
  1223. int Draw_Clip_Line16(int x0,int y0, int x1, int y1, int color, 
  1224.                     UCHAR *dest_buffer, int lpitch)
  1225. {
  1226. // this function draws a clipped line
  1227. int cxs, cys,
  1228. cxe, cye;
  1229. // clip and draw each line
  1230. cxs = x0;
  1231. cys = y0;
  1232. cxe = x1;
  1233. cye = y1;
  1234. // clip the line
  1235. if (Clip_Line(cxs,cys,cxe,cye))
  1236. Draw_Line16(cxs, cys, cxe,cye,color,dest_buffer,lpitch);
  1237. // return success
  1238. return(1);
  1239. } // end Draw_Clip_Line16
  1240. ///////////////////////////////////////////////////////////
  1241. int Draw_Clip_Line(int x0,int y0, int x1, int y1, int color, 
  1242.                     UCHAR *dest_buffer, int lpitch)
  1243. {
  1244. // this function draws a wireframe triangle
  1245. int cxs, cys,
  1246. cxe, cye;
  1247. // clip and draw each line
  1248. cxs = x0;
  1249. cys = y0;
  1250. cxe = x1;
  1251. cye = y1;
  1252. // clip the line
  1253. if (Clip_Line(cxs,cys,cxe,cye))
  1254. Draw_Line(cxs, cys, cxe,cye,color,dest_buffer,lpitch);
  1255. // return success
  1256. return(1);
  1257. } // end Draw_Clip_Line
  1258. ///////////////////////////////////////////////////////////
  1259. int Clip_Line(int &x1,int &y1,int &x2, int &y2)
  1260. {
  1261. // this function clips the sent line using the globally defined clipping
  1262. // region
  1263. // internal clipping codes
  1264. #define CLIP_CODE_C  0x0000
  1265. #define CLIP_CODE_N  0x0008
  1266. #define CLIP_CODE_S  0x0004
  1267. #define CLIP_CODE_E  0x0002
  1268. #define CLIP_CODE_W  0x0001
  1269. #define CLIP_CODE_NE 0x000a
  1270. #define CLIP_CODE_SE 0x0006
  1271. #define CLIP_CODE_NW 0x0009 
  1272. #define CLIP_CODE_SW 0x0005
  1273. int xc1=x1, 
  1274.     yc1=y1, 
  1275. xc2=x2, 
  1276. yc2=y2;
  1277. int p1_code=0, 
  1278.     p2_code=0;
  1279. // determine codes for p1 and p2
  1280. if (y1 < min_clip_y)
  1281. p1_code|=CLIP_CODE_N;
  1282. else
  1283. if (y1 > max_clip_y)
  1284. p1_code|=CLIP_CODE_S;
  1285. if (x1 < min_clip_x)
  1286. p1_code|=CLIP_CODE_W;
  1287. else
  1288. if (x1 > max_clip_x)
  1289. p1_code|=CLIP_CODE_E;
  1290. if (y2 < min_clip_y)
  1291. p2_code|=CLIP_CODE_N;
  1292. else
  1293. if (y2 > max_clip_y)
  1294. p2_code|=CLIP_CODE_S;
  1295. if (x2 < min_clip_x)
  1296. p2_code|=CLIP_CODE_W;
  1297. else
  1298. if (x2 > max_clip_x)
  1299. p2_code|=CLIP_CODE_E;
  1300. // try and trivially reject
  1301. if ((p1_code & p2_code)) 
  1302. return(0);
  1303. // test for totally visible, if so leave points untouched
  1304. if (p1_code==0 && p2_code==0)
  1305. return(1);
  1306. // determine end clip point for p1
  1307. switch(p1_code)
  1308.   {
  1309.   case CLIP_CODE_C: break;
  1310.   case CLIP_CODE_N:
  1311.    {
  1312.    yc1 = min_clip_y;
  1313.    xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1314.    } break;
  1315.   case CLIP_CODE_S:
  1316.    {
  1317.    yc1 = max_clip_y;
  1318.    xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  1319.    } break;
  1320.   case CLIP_CODE_W:
  1321.    {
  1322.    xc1 = min_clip_x;
  1323.    yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  1324.    } break;
  1325.   case CLIP_CODE_E:
  1326.    {
  1327.    xc1 = max_clip_x;
  1328.    yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1329.    } break;
  1330. // these cases are more complex, must compute 2 intersections
  1331.   case CLIP_CODE_NE:
  1332.    {
  1333.    // north hline intersection
  1334.    yc1 = min_clip_y;
  1335.    xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1336.    // test if intersection is valid, of so then done, else compute next
  1337. if (xc1 < min_clip_x || xc1 > max_clip_x)
  1338. {
  1339. // east vline intersection
  1340. xc1 = max_clip_x;
  1341. yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1342. } // end if
  1343.    } break;
  1344.   
  1345.   case CLIP_CODE_SE:
  1346.           {
  1347.    // south hline intersection
  1348.    yc1 = max_clip_y;
  1349.    xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  1350.    // test if intersection is valid, of so then done, else compute next
  1351.    if (xc1 < min_clip_x || xc1 > max_clip_x)
  1352.       {
  1353.   // east vline intersection
  1354.   xc1 = max_clip_x;
  1355.   yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1356.   } // end if
  1357.    } break;
  1358.     
  1359.   case CLIP_CODE_NW: 
  1360.           {
  1361.    // north hline intersection
  1362.    yc1 = min_clip_y;
  1363.    xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1364.    
  1365.    // test if intersection is valid, of so then done, else compute next
  1366.    if (xc1 < min_clip_x || xc1 > max_clip_x)
  1367.       {
  1368.   xc1 = min_clip_x;
  1369.       yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  1370.   } // end if
  1371.    } break;
  1372.      
  1373.   case CLIP_CODE_SW:
  1374.    {
  1375.    // south hline intersection
  1376.    yc1 = max_clip_y;
  1377.    xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  1378.    
  1379.    // test if intersection is valid, of so then done, else compute next
  1380.    if (xc1 < min_clip_x || xc1 > max_clip_x)
  1381.       {
  1382.   xc1 = min_clip_x;
  1383.       yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  1384.   } // end if
  1385.    } break;
  1386.   default:break;
  1387.   } // end switch
  1388. // determine clip point for p2
  1389. switch(p2_code)
  1390.   {
  1391.   case CLIP_CODE_C: break;
  1392.   case CLIP_CODE_N:
  1393.    {
  1394.    yc2 = min_clip_y;
  1395.    xc2 = x2 + (min_clip_y-y2)*(x1-x2)/(y1-y2);
  1396.    } break;
  1397.   case CLIP_CODE_S:
  1398.    {
  1399.    yc2 = max_clip_y;
  1400.    xc2 = x2 + (max_clip_y-y2)*(x1-x2)/(y1-y2);
  1401.    } break;
  1402.   case CLIP_CODE_W:
  1403.    {
  1404.    xc2 = min_clip_x;
  1405.    yc2 = y2 + (min_clip_x-x2)*(y1-y2)/(x1-x2);
  1406.    } break;
  1407.   case CLIP_CODE_E:
  1408.    {
  1409.    xc2 = max_clip_x;
  1410.    yc2 = y2 + (max_clip_x-x2)*(y1-y2)/(x1-x2);
  1411.    } break;
  1412. // these cases are more complex, must compute 2 intersections
  1413.   case CLIP_CODE_NE:
  1414.    {
  1415.    // north hline intersection
  1416.    yc2 = min_clip_y;
  1417.    xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
  1418.    // test if intersection is valid, of so then done, else compute next
  1419. if (xc2 < min_clip_x || xc2 > max_clip_x)
  1420. {
  1421. // east vline intersection
  1422. xc2 = max_clip_x;
  1423. yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
  1424. } // end if
  1425.    } break;
  1426.   
  1427.   case CLIP_CODE_SE:
  1428.           {
  1429.    // south hline intersection
  1430.    yc2 = max_clip_y;
  1431.    xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);
  1432.    // test if intersection is valid, of so then done, else compute next
  1433.    if (xc2 < min_clip_x || xc2 > max_clip_x)
  1434.       {
  1435.   // east vline intersection
  1436.   xc2 = max_clip_x;
  1437.   yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
  1438.   } // end if
  1439.    } break;
  1440.     
  1441.   case CLIP_CODE_NW: 
  1442.           {
  1443.    // north hline intersection
  1444.    yc2 = min_clip_y;
  1445.    xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
  1446.    
  1447.    // test if intersection is valid, of so then done, else compute next
  1448.    if (xc2 < min_clip_x || xc2 > max_clip_x)
  1449.       {
  1450.   xc2 = min_clip_x;
  1451.       yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
  1452.   } // end if
  1453.    } break;
  1454.      
  1455.   case CLIP_CODE_SW:
  1456.    {
  1457.    // south hline intersection
  1458.    yc2 = max_clip_y;
  1459.    xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);
  1460.    
  1461.    // test if intersection is valid, of so then done, else compute next
  1462.    if (xc2 < min_clip_x || xc2 > max_clip_x)
  1463.       {
  1464.   xc2 = min_clip_x;
  1465.       yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
  1466.   } // end if
  1467.    } break;
  1468.   default:break;
  1469.   } // end switch
  1470. // do bounds check
  1471. if ((xc1 < min_clip_x) || (xc1 > max_clip_x) ||
  1472. (yc1 < min_clip_y) || (yc1 > max_clip_y) ||
  1473. (xc2 < min_clip_x) || (xc2 > max_clip_x) ||
  1474. (yc2 < min_clip_y) || (yc2 > max_clip_y) )
  1475. {
  1476. return(0);
  1477. } // end if
  1478. // store vars back
  1479. x1 = xc1;
  1480. y1 = yc1;
  1481. x2 = xc2;
  1482. y2 = yc2;
  1483. return(1);
  1484. } // end Clip_Line
  1485. ///////////////////////////////////////////////////////////
  1486. int Draw_Line(int x0, int y0, // starting position 
  1487.               int x1, int y1, // ending position
  1488.               int color,     // color index
  1489.               UCHAR *vb_start, int lpitch) // video buffer and memory pitch
  1490. {
  1491. // this function draws a line from xo,yo to x1,y1 using differential error
  1492. // terms (based on Bresenahams work)
  1493. int dx,             // difference in x's
  1494.     dy,             // difference in y's
  1495.     dx2,            // dx,dy * 2
  1496.     dy2, 
  1497.     x_inc,          // amount in pixel space to move during drawing
  1498.     y_inc,          // amount in pixel space to move during drawing
  1499.     error,          // the discriminant i.e. error i.e. decision variable
  1500.     index;          // used for looping
  1501. // pre-compute first pixel address in video buffer
  1502. vb_start = vb_start + x0 + y0*lpitch;
  1503. // compute horizontal and vertical deltas
  1504. dx = x1-x0;
  1505. dy = y1-y0;
  1506. // test which direction the line is going in i.e. slope angle
  1507. if (dx>=0)
  1508.    {
  1509.    x_inc = 1;
  1510.    } // end if line is moving right
  1511. else
  1512.    {
  1513.    x_inc = -1;
  1514.    dx    = -dx;  // need absolute value
  1515.    } // end else moving left
  1516. // test y component of slope
  1517. if (dy>=0)
  1518.    {
  1519.    y_inc = lpitch;
  1520.    } // end if line is moving down
  1521. else
  1522.    {
  1523.    y_inc = -lpitch;
  1524.    dy    = -dy;  // need absolute value
  1525.    } // end else moving up
  1526. // compute (dx,dy) * 2
  1527. dx2 = dx << 1;
  1528. dy2 = dy << 1;
  1529. // now based on which delta is greater we can draw the line
  1530. if (dx > dy)
  1531.    {
  1532.    // initialize error term
  1533.    error = dy2 - dx; 
  1534.    // draw the line
  1535.    for (index=0; index <= dx; index++)
  1536.        {
  1537.        // set the pixel
  1538.        *vb_start = color;
  1539.        // test if error has overflowed
  1540.        if (error >= 0) 
  1541.           {
  1542.           error-=dx2;
  1543.           // move to next line
  1544.           vb_start+=y_inc;
  1545.    } // end if error overflowed
  1546.        // adjust the error term
  1547.        error+=dy2;
  1548.        // move to the next pixel
  1549.        vb_start+=x_inc;
  1550.        } // end for
  1551.    } // end if |slope| <= 1
  1552. else
  1553.    {
  1554.    // initialize error term
  1555.    error = dx2 - dy; 
  1556.    // draw the line
  1557.    for (index=0; index <= dy; index++)
  1558.        {
  1559.        // set the pixel
  1560.        *vb_start = color;
  1561.        // test if error overflowed
  1562.        if (error >= 0)
  1563.           {
  1564.           error-=dy2;
  1565.           // move to next line
  1566.           vb_start+=x_inc;
  1567.           } // end if error overflowed
  1568.        // adjust the error term
  1569.        error+=dx2;
  1570.        // move to the next pixel
  1571.        vb_start+=y_inc;
  1572.        } // end for
  1573.    } // end else |slope| > 1
  1574. // return success
  1575. return(1);
  1576. } // end Draw_Line
  1577. ///////////////////////////////////////////////////////////
  1578. int Draw_Line16(int x0, int y0, // starting position 
  1579.                 int x1, int y1, // ending position
  1580.                 int color,     // color index
  1581.                 UCHAR *vb_start, int lpitch) // video buffer and memory pitch
  1582. {
  1583. // this function draws a line from xo,yo to x1,y1 using differential error
  1584. // terms (based on Bresenahams work)
  1585. int dx,             // difference in x's
  1586.     dy,             // difference in y's
  1587.     dx2,            // dx,dy * 2
  1588.     dy2, 
  1589.     x_inc,          // amount in pixel space to move during drawing
  1590.     y_inc,          // amount in pixel space to move during drawing
  1591.     error,          // the discriminant i.e. error i.e. decision variable
  1592.     index;          // used for looping
  1593. int lpitch_2 = lpitch >> 1; // USHORT strided lpitch
  1594. // pre-compute first pixel address in video buffer based on 16bit data
  1595. USHORT *vb_start2 = (USHORT *)vb_start + x0 + y0*lpitch_2;
  1596. // compute horizontal and vertical deltas
  1597. dx = x1-x0;
  1598. dy = y1-y0;
  1599. // test which direction the line is going in i.e. slope angle
  1600. if (dx>=0)
  1601.    {
  1602.    x_inc = 1;
  1603.    } // end if line is moving right
  1604. else
  1605.    {
  1606.    x_inc = -1;
  1607.    dx    = -dx;  // need absolute value
  1608.    } // end else moving left
  1609. // test y component of slope
  1610. if (dy>=0)
  1611.    {
  1612.    y_inc = lpitch_2;
  1613.    } // end if line is moving down
  1614. else
  1615.    {
  1616.    y_inc = -lpitch_2;
  1617.    dy    = -dy;  // need absolute value
  1618.    } // end else moving up
  1619. // compute (dx,dy) * 2
  1620. dx2 = dx << 1;
  1621. dy2 = dy << 1;
  1622. // now based on which delta is greater we can draw the line
  1623. if (dx > dy)
  1624.    {
  1625.    // initialize error term
  1626.    error = dy2 - dx; 
  1627.    // draw the line
  1628.    for (index=0; index <= dx; index++)
  1629.        {
  1630.        // set the pixel
  1631.        *vb_start2 = (USHORT)color;
  1632.        // test if error has overflowed
  1633.        if (error >= 0) 
  1634.           {
  1635.           error-=dx2;
  1636.           // move to next line
  1637.           vb_start2+=y_inc;
  1638.    } // end if error overflowed
  1639.        // adjust the error term
  1640.        error+=dy2;
  1641.        // move to the next pixel
  1642.        vb_start2+=x_inc;
  1643.        } // end for
  1644.    } // end if |slope| <= 1
  1645. else
  1646.    {
  1647.    // initialize error term
  1648.    error = dx2 - dy; 
  1649.    // draw the line
  1650.    for (index=0; index <= dy; index++)
  1651.        {
  1652.        // set the pixel
  1653.        *vb_start2 = (USHORT)color;
  1654.        // test if error overflowed
  1655.        if (error >= 0)
  1656.           {
  1657.           error-=dy2;
  1658.           // move to next line
  1659.           vb_start2+=x_inc;
  1660.           } // end if error overflowed
  1661.        // adjust the error term
  1662.        error+=dx2;
  1663.        // move to the next pixel
  1664.        vb_start2+=y_inc;
  1665.        } // end for
  1666.    } // end else |slope| > 1
  1667. // return success
  1668. return(1);
  1669. } // end Draw_Line16
  1670. ///////////////////////////////////////////////////////////
  1671. int Draw_Pixel(int x, int y,int color,
  1672.                UCHAR *video_buffer, int lpitch)
  1673. {
  1674. // this function plots a single pixel at x,y with color
  1675. video_buffer[x + y*lpitch] = color;
  1676. // return success
  1677. return(1);
  1678. } // end Draw_Pixel
  1679. ///////////////////////////////////////////////////////////   
  1680.    
  1681. int Draw_Pixel16(int x, int y,int color,
  1682.                         UCHAR *video_buffer, int lpitch)
  1683. {
  1684. // this function plots a single pixel at x,y with color
  1685. ((USHORT *)video_buffer)[x + y*(lpitch >> 1)] = color;
  1686. // return success
  1687. return(1);
  1688. } // end Draw_Pixel16
  1689. ///////////////////////////////////////////////////////////   
  1690. int Draw_Rectangle(int x1, int y1, int x2, int y2, int color,
  1691.                    LPDIRECTDRAWSURFACE7 lpdds)
  1692. {
  1693. // this function uses directdraw to draw a filled rectangle
  1694. DDBLTFX ddbltfx; // this contains the DDBLTFX structure
  1695. RECT fill_area;  // this contains the destination rectangle
  1696. // clear out the structure and set the size field 
  1697. DDRAW_INIT_STRUCT(ddbltfx);
  1698. // set the dwfillcolor field to the desired color
  1699. ddbltfx.dwFillColor = color; 
  1700. // fill in the destination rectangle data (your data)
  1701. fill_area.top    = y1;
  1702. fill_area.left   = x1;
  1703. fill_area.bottom = y2;
  1704. fill_area.right  = x2;
  1705. // ready to blt to surface, in this case blt to primary
  1706. lpdds->Blt(&fill_area, // ptr to dest rectangle
  1707.            NULL,       // ptr to source surface, NA            
  1708.            NULL,       // ptr to source rectangle, NA
  1709.            DDBLT_COLORFILL | DDBLT_WAIT,   // fill and wait                   
  1710.            &ddbltfx);  // ptr to DDBLTFX structure
  1711. // return success
  1712. return(1);
  1713. } // end Draw_Rectangle
  1714. ///////////////////////////////////////////////////////////
  1715.    
  1716. int Set_Palette_Entry(int color_index, LPPALETTEENTRY color)
  1717. {
  1718. // this function sets a palette color in the palette
  1719. lpddpal->SetEntries(0,color_index,1,color);
  1720. // set data in shadow palette
  1721. memcpy(&palette[color_index],color,sizeof(PALETTEENTRY));
  1722. // return success
  1723. return(1);
  1724. } // end Set_Palette_Entry
  1725. ///////////////////////////////////////////////////////////   
  1726.    
  1727. int Get_Palette_Entry(int color_index,LPPALETTEENTRY color)
  1728. {
  1729. // this function retrieves a palette entry from the color
  1730. // palette
  1731. // copy data out from shadow palette
  1732. memcpy(color, &palette[color_index],sizeof(PALETTEENTRY));
  1733. // return success
  1734. return(1);
  1735. } // end Get_Palette_Entry
  1736. ///////////////////////////////////////////////////////////
  1737.    
  1738. int Load_Palette_From_File(char *filename, LPPALETTEENTRY palette)
  1739. {
  1740. // this function loads a palette from disk into a palette
  1741. // structure, but does not set the pallette
  1742. FILE *fp_file; // working file
  1743. // try and open file
  1744. if ((fp_file = fopen(filename,"r"))==NULL)
  1745.    return(0);
  1746. // read in all 256 colors RGBF
  1747. for (int index=0; index<MAX_COLORS_PALETTE; index++)
  1748.     {
  1749.     // read the next entry in
  1750.     fscanf(fp_file,"%d %d %d %d",&palette[index].peRed,
  1751.                                  &palette[index].peGreen,
  1752.                                  &palette[index].peBlue,                                
  1753.                                  &palette[index].peFlags);
  1754.     } // end for index
  1755. // close the file
  1756. fclose(fp_file);
  1757. // return success
  1758. return(1);
  1759. } // end Load_Palette_From_Disk
  1760. ///////////////////////////////////////////////////////////   
  1761.    
  1762. int Save_Palette_To_File(char *filename, LPPALETTEENTRY palette)
  1763. {
  1764. // this function saves a palette to disk
  1765. FILE *fp_file; // working file
  1766. // try and open file
  1767. if ((fp_file = fopen(filename,"w"))==NULL)
  1768.    return(0);
  1769. // write in all 256 colors RGBF
  1770. for (int index=0; index<MAX_COLORS_PALETTE; index++)
  1771.     {
  1772.     // read the next entry in
  1773.     fprintf(fp_file,"n%d %d %d %d",palette[index].peRed,
  1774.                                     palette[index].peGreen,
  1775.                                     palette[index].peBlue,                                
  1776.                                     palette[index].peFlags);
  1777.     } // end for index
  1778. // close the file
  1779. fclose(fp_file);
  1780. // return success
  1781. return(1);
  1782. } // end Save_Palette_To_Disk
  1783. ///////////////////////////////////////////////////////////
  1784. int Save_Palette(LPPALETTEENTRY sav_palette)
  1785. {
  1786. // this function saves the current palette 
  1787. memcpy(sav_palette, palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  1788. // return success
  1789. return(1);
  1790. } // end Save_Palette
  1791. ///////////////////////////////////////////////////////////   
  1792.    
  1793. int Set_Palette(LPPALETTEENTRY set_palette)
  1794. {
  1795. // this function writes the sent palette
  1796. // first save the new palette in shadow
  1797. memcpy(palette, set_palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  1798. // now set the new palette
  1799. lpddpal->SetEntries(0,0,MAX_COLORS_PALETTE,palette);
  1800. // return success
  1801. return(1);
  1802. } // end Set_Palette
  1803. ///////////////////////////////////////////////////////////
  1804. int Rotate_Colors(int start_index, int end_index)
  1805. {
  1806. // this function rotates the color between start and end
  1807. int colors = end_index - start_index + 1;
  1808. PALETTEENTRY work_pal[MAX_COLORS_PALETTE]; // working palette
  1809. // get the color palette
  1810. lpddpal->GetEntries(0,start_index,colors,work_pal);
  1811. // shift the colors
  1812. lpddpal->SetEntries(0,start_index+1,colors-1,work_pal);
  1813. // fix up the last color
  1814. lpddpal->SetEntries(0,start_index,1,&work_pal[colors - 1]);
  1815. // update shadow palette
  1816. lpddpal->GetEntries(0,0,MAX_COLORS_PALETTE,palette);
  1817. // return success
  1818. return(1);
  1819. } // end Rotate_Colors
  1820. ///////////////////////////////////////////////////////////   
  1821.    
  1822. int Blink_Colors(int command, BLINKER_PTR new_light, int id)
  1823. {
  1824. // this function blinks a set of lights
  1825. static BLINKER lights[256]; // supports up to 256 blinking lights
  1826. static int initialized = 0; // tracks if function has initialized
  1827. // test if this is the first time function has ran
  1828. if (!initialized)
  1829.    {
  1830.    // set initialized
  1831.    initialized = 1;
  1832.    // clear out all structures
  1833.    memset((void *)lights,0, sizeof(lights));
  1834.    } // end if
  1835. // now test what command user is sending
  1836. switch (command)
  1837.        {
  1838.        case BLINKER_ADD: // add a light to the database
  1839.             {
  1840.             // run thru database and find an open light
  1841.             for (int index=0; index < 256; index++)
  1842.                 {
  1843.                 // is this light available?
  1844.                 if (lights[index].state == 0)
  1845.                    {
  1846.                    // set light up
  1847.                    lights[index] = *new_light;
  1848.                    // set internal fields up
  1849.                    lights[index].counter =  0;
  1850.                    lights[index].state   = -1; // off
  1851.                    // update palette entry
  1852.                    lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].off_color);
  1853.  
  1854.                    // return id to caller
  1855.                    return(index);
  1856.                    } // end if
  1857.                 } // end for index
  1858.             } break;
  1859.        case BLINKER_DELETE: // delete the light indicated by id
  1860.             {
  1861.             // delete the light sent in id 
  1862.             if (lights[id].state != 0)
  1863.                {
  1864.                // kill the light
  1865.                memset((void *)&lights[id],0,sizeof(BLINKER));
  1866.                // return id
  1867.                return(id);
  1868.  
  1869.                } // end if
  1870.             else
  1871.                 return(-1); // problem
  1872.             } break;
  1873.        case BLINKER_UPDATE: // update the light indicated by id
  1874.             { 
  1875.             // make sure light is active
  1876.             if (lights[id].state != 0)
  1877.                {
  1878.                // update on/off parms only
  1879.                lights[id].on_color  = new_light->on_color; 
  1880.                lights[id].off_color = new_light->off_color;
  1881.                lights[id].on_time   = new_light->on_time;
  1882.                lights[id].off_time  = new_light->off_time; 
  1883.                // update palette entry
  1884.                if (lights[id].state == -1)
  1885.                   lpddpal->SetEntries(0,lights[id].color_index,1,&lights[id].off_color);
  1886.                else
  1887.                   lpddpal->SetEntries(0,lights[id].color_index,1,&lights[id].on_color);
  1888.                // return id
  1889.                return(id);
  1890.  
  1891.                } // end if
  1892.             else
  1893.                 return(-1); // problem
  1894.             } break;
  1895.        case BLINKER_RUN: // run the algorithm
  1896.             {
  1897.             // run thru database and process each light
  1898.             for (int index=0; index < 256; index++)
  1899.                 {
  1900.                 // is this active?
  1901.                 if (lights[index].state == -1)
  1902.                    {
  1903.                    // update counter
  1904.                    if (++lights[index].counter >= lights[index].off_time)
  1905.                       {
  1906.                       // reset counter
  1907.                       lights[index].counter = 0;
  1908.                       // change states 
  1909.                       lights[index].state = -lights[index].state;               
  1910.  
  1911.                       // update color
  1912.                       lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].on_color);
  1913.  
  1914.                       } // end if
  1915.                  
  1916.                    } // end if
  1917.                 else
  1918.                 if (lights[index].state == 1)
  1919.                    {
  1920.                    // update counter
  1921.                    if (++lights[index].counter >= lights[index].on_time)
  1922.                       {
  1923.                       // reset counter
  1924.                       lights[index].counter = 0;
  1925.                       // change states 
  1926.                       lights[index].state = -lights[index].state;               
  1927.  
  1928.                       // update color
  1929.                       lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].off_color);
  1930.  
  1931.                       } // end if
  1932.                    } // end else if
  1933.                  
  1934.                 } // end for index
  1935.             } break;
  1936.        default: break;
  1937.        } // end switch
  1938. // return success
  1939. return(1);
  1940. } // end Blink_Colors
  1941. ///////////////////////////////////////////////////////////
  1942. int Draw_Text_GDI(char *text, int x,int y,COLORREF color, LPDIRECTDRAWSURFACE7 lpdds)
  1943. {
  1944. // this function draws the sent text on the sent surface 
  1945. // using color index as the color in the palette
  1946. HDC xdc; // the working dc
  1947. // get the dc from surface
  1948. if (FAILED(lpdds->GetDC(&xdc)))
  1949.    return(0);
  1950. // set the colors for the text up
  1951. SetTextColor(xdc,color);
  1952. // set background mode to transparent so black isn't copied
  1953. SetBkMode(xdc, TRANSPARENT);
  1954. // draw the text a
  1955. TextOut(xdc,x,y,text,strlen(text));
  1956. // release the dc
  1957. lpdds->ReleaseDC(xdc);
  1958. // return success
  1959. return(1);
  1960. } // end Draw_Text_GDI
  1961. ///////////////////////////////////////////////////////////
  1962. int Draw_Text_GDI(char *text, int x,int y,int color, LPDIRECTDRAWSURFACE7 lpdds)
  1963. {
  1964. // this function draws the sent text on the sent surface 
  1965. // using color index as the color in the palette
  1966. HDC xdc; // the working dc
  1967. // get the dc from surface
  1968. if (FAILED(lpdds->GetDC(&xdc)))
  1969.    return(0);
  1970. // set the colors for the text up
  1971. SetTextColor(xdc,RGB(palette[color].peRed,palette[color].peGreen,palette[color].peBlue) );
  1972. // set background mode to transparent so black isn't copied
  1973. SetBkMode(xdc, TRANSPARENT);
  1974. // draw the text a
  1975. TextOut(xdc,x,y,text,strlen(text));
  1976. // release the dc
  1977. lpdds->ReleaseDC(xdc);
  1978. // return success
  1979. return(1);
  1980. } // end Draw_Text_GDI
  1981. ///////////////////////////////////////////////////////////
  1982. int Open_Error_File(char *filename, FILE *fp_override)
  1983. {
  1984. // this function creates the output error file
  1985. // is user requesting special file handle? stdout, stderr, etc.?
  1986. if (fp_override)
  1987. {
  1988. fp_error = fp_override;
  1989. }
  1990. else
  1991. {
  1992. // test if this file is valid
  1993. if ((fp_error = fopen(filename,"w"))==NULL)
  1994.    return(0);
  1995. }
  1996. // get the current time
  1997. struct _timeb timebuffer;
  1998. char *timeline;
  1999. char timestring[280];
  2000. _ftime(&timebuffer);
  2001. timeline = ctime(&(timebuffer.time));
  2002. sprintf(timestring, "%.19s.%hu, %s", timeline, timebuffer.millitm, &timeline[20]);
  2003. // write out error header with time
  2004. Write_Error("nOpening Error Output File (%s) on %sn",filename,timestring);
  2005. // now the file is created, re-open with append mode
  2006. if (!fp_override)
  2007. {
  2008. fclose(fp_error);
  2009. if ((fp_error = fopen(filename,"a+"))==NULL)
  2010.    return(0);
  2011. }
  2012. // return success
  2013. return(1);
  2014. } // end Open_Error_File
  2015. ///////////////////////////////////////////////////////////
  2016. int Close_Error_File(void)
  2017. {
  2018. // this function closes the error file
  2019. if (fp_error)
  2020.     {
  2021.     // write close file string
  2022.     Write_Error("nClosing Error Output File.");
  2023.     if (fp_error!=stdout || fp_error!=stderr)
  2024.     {
  2025.     // close the file handle
  2026.     fclose(fp_error);
  2027.     } 
  2028.     
  2029.     fp_error = NULL;
  2030.     // return success
  2031.     return(1);
  2032.     } // end if
  2033. else
  2034.    return(0);
  2035. } // end Close_Error_File
  2036. ///////////////////////////////////////////////////////////
  2037. int Write_Error(char *string, ...)
  2038. {
  2039. // this function prints out the error string to the error file
  2040. char buffer[1024]; // working buffer
  2041. va_list arglist; // variable argument list
  2042. // make sure both the error file and string are valid
  2043. if (!string || !fp_error)
  2044.    return(0);
  2045. // print out the string using the variable number of arguments on stack
  2046. va_start(arglist,string);
  2047. vsprintf(buffer,string,arglist);
  2048. va_end(arglist);
  2049. // write string to file
  2050. fprintf(fp_error,buffer);
  2051. // flush buffer incase the system bails
  2052. fflush(fp_error);
  2053. // return success
  2054. return(1);
  2055. } // end Write_Error
  2056. ///////////////////////////////////////////////////////////////////////////////
  2057. int Create_Bitmap(BITMAP_IMAGE_PTR image, int x, int y, int width, int height, int bpp)
  2058. {
  2059. // this function is used to intialize a bitmap, 8 or 16 bit
  2060. // allocate the memory
  2061. if (!(image->buffer = (UCHAR *)malloc(width*height*(bpp>>3))))
  2062.    return(0);
  2063. // initialize variables
  2064. image->state     = BITMAP_STATE_ALIVE;
  2065. image->attr      = 0;
  2066. image->width     = width;
  2067. image->height    = height;
  2068. image->bpp       = bpp;
  2069. image->x         = x;
  2070. image->y         = y;
  2071. image->num_bytes = width*height*(bpp>>3);
  2072. // clear memory out
  2073. memset(image->buffer,0,width*height*(bpp>>3));
  2074. // return success
  2075. return(1);
  2076. } // end Create_Bitmap
  2077. ///////////////////////////////////////////////////////////////////////////////
  2078. int Destroy_Bitmap(BITMAP_IMAGE_PTR image)
  2079. {
  2080. // this function releases the memory associated with a bitmap
  2081. if (image && image->buffer)
  2082.    {
  2083.    // free memory and reset vars
  2084.    free(image->buffer);
  2085.    // set all vars in structure to 0
  2086.    memset(image,0,sizeof(BITMAP_IMAGE));
  2087.    // return success
  2088.    return(1);
  2089.    } // end if
  2090. else  // invalid entry pointer of the object wasn't initialized
  2091.    return(0);
  2092. } // end Destroy_Bitmap
  2093. ///////////////////////////////////////////////////////////
  2094. int Draw_Bitmap(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
  2095. {
  2096. // this function draws the bitmap onto the destination memory surface
  2097. // if transparent is 1 then color 0 (8bit) or 0.0.0 (16bit) will be transparent
  2098. // note this function does NOT clip, so be carefull!!!
  2099. // test if this bitmap is loaded
  2100. if (!(source_bitmap->attr & BITMAP_ATTR_LOADED))
  2101.    return(0);
  2102.     UCHAR *dest_addr,   // starting address of bitmap in destination
  2103.           *source_addr; // starting adddress of bitmap data in source
  2104.     UCHAR pixel;        // used to hold pixel value
  2105.     int index,          // looping vars
  2106.         pixel_x;
  2107.    // compute starting destination address
  2108.    dest_addr = dest_buffer + source_bitmap->y*lpitch + source_bitmap->x;
  2109.    // compute the starting source address
  2110.    source_addr = source_bitmap->buffer;
  2111.    // is this bitmap transparent
  2112.    if (transparent)
  2113.    {
  2114.    // copy each line of bitmap into destination with transparency
  2115.    for (index=0; index<source_bitmap->height; index++)
  2116.        {
  2117.        // copy the memory
  2118.        for (pixel_x=0; pixel_x<source_bitmap->width; pixel_x++)
  2119.            {
  2120.            if ((pixel = source_addr[pixel_x])!=0)
  2121.                dest_addr[pixel_x] = pixel;
  2122.            } // end if
  2123.        // advance all the pointers
  2124.        dest_addr   += lpitch;
  2125.        source_addr += source_bitmap->width;
  2126.        } // end for index
  2127.    } // end if
  2128.    else
  2129.       {
  2130.       // non-transparent version
  2131.       // copy each line of bitmap into destination
  2132.       for (index=0; index < source_bitmap->height; index++)
  2133.           {
  2134.           // copy the memory
  2135.           memcpy(dest_addr, source_addr, source_bitmap->width);
  2136.           // advance all the pointers
  2137.           dest_addr   += lpitch;
  2138.           source_addr += source_bitmap->width;
  2139.           } // end for index
  2140.        } // end else
  2141.    // return success
  2142.    return(1);
  2143. } // end Draw_Bitmap
  2144. ///////////////////////////////////////////////////////////////
  2145. int Draw_Bitmap16(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
  2146. {
  2147. // this function draws the bitmap onto the destination memory surface
  2148. // if transparent is 1 then color 0 (8bit) or 0.0.0 (16bit) will be transparent
  2149. // note this function does NOT clip, so be carefull!!!
  2150. // test if this bitmap is loaded
  2151. if (!(source_bitmap->attr & BITMAP_ATTR_LOADED))
  2152.    return(0);
  2153.    USHORT *dest_addr,   // starting address of bitmap in destination
  2154.           *source_addr; // starting adddress of bitmap data in source
  2155.    USHORT pixel;        // used to hold pixel value
  2156.    int index,           // looping vars
  2157.        pixel_x,
  2158.        lpitch_2 = lpitch >> 1; // lpitch in USHORT terms
  2159.    // compute starting destination address
  2160.    dest_addr = ((USHORT *)dest_buffer) + source_bitmap->y*lpitch_2 + source_bitmap->x;
  2161.    // compute the starting source address
  2162.    source_addr = (USHORT *)source_bitmap->buffer;
  2163.    // is this bitmap transparent
  2164.    if (transparent)
  2165.    {
  2166.    // copy each line of bitmap into destination with transparency
  2167.    for (index=0; index<source_bitmap->height; index++)
  2168.        {
  2169.        // copy the memory
  2170.        for (pixel_x=0; pixel_x<source_bitmap->width; pixel_x++)
  2171.            {
  2172.            if ((pixel = source_addr[pixel_x])!=0)
  2173.                dest_addr[pixel_x] = pixel;
  2174.            } // end if
  2175.        // advance all the pointers
  2176.        dest_addr   += lpitch_2;
  2177.        source_addr += source_bitmap->width;
  2178.        } // end for index
  2179.    } // end if
  2180.    else
  2181.       {
  2182.       // non-transparent version
  2183.       // copy each line of bitmap into destination
  2184.       int source_bytes_per_line = source_bitmap->width*2;
  2185.       for (index=0; index < source_bitmap->height; index++)
  2186.           {
  2187.           // copy the memory
  2188.           memcpy(dest_addr, source_addr, source_bytes_per_line);
  2189.           // advance all the pointers
  2190.           dest_addr   += lpitch_2;
  2191.           source_addr += source_bitmap->width;
  2192.           } // end for index
  2193.       } // end else
  2194.    // return success
  2195.    return(1);
  2196. } // end Draw_Bitmap16
  2197. ///////////////////////////////////////////////////////////////////////////////
  2198. int Load_Image_Bitmap(BITMAP_IMAGE_PTR image,  // bitmap image to load with data
  2199.                       BITMAP_FILE_PTR bitmap,  // bitmap to scan image data from
  2200.                       int cx,int cy,   // cell or absolute pos. to scan image from
  2201.                       int mode)        // if 0 then cx,cy is cell position, else 
  2202.                                        // cx,cy are absolute coords
  2203. {
  2204. // this function extracts a bitmap out of a bitmap file
  2205. // is this a valid bitmap
  2206. if (!image)
  2207.    return(0);
  2208. UCHAR *source_ptr,   // working pointers
  2209.       *dest_ptr;
  2210. // test the mode of extraction, cell based or absolute
  2211. if (mode==BITMAP_EXTRACT_MODE_CELL)
  2212.    {
  2213.    // re-compute x,y
  2214.    cx = cx*(image->width+1) + 1;
  2215.    cy = cy*(image->height+1) + 1;
  2216.    } // end if
  2217. // extract bitmap data
  2218. source_ptr = bitmap->buffer +
  2219.       cy*bitmap->bitmapinfoheader.biWidth+cx;
  2220. // assign a pointer to the bimap image
  2221. dest_ptr = (UCHAR *)image->buffer;
  2222. // iterate thru each scanline and copy bitmap
  2223. for (int index_y=0; index_y<image->height; index_y++)
  2224.     {
  2225.     // copy next line of data to destination
  2226.     memcpy(dest_ptr, source_ptr,image->width);
  2227.     // advance pointers
  2228.     dest_ptr   += image->width;
  2229.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  2230.     } // end for index_y
  2231. // set state to loaded
  2232. image->attr |= BITMAP_ATTR_LOADED;
  2233. // return success
  2234. return(1);
  2235. } // end Load_Image_Bitmap
  2236. ///////////////////////////////////////////////////////////
  2237. int Load_Image_Bitmap16(BITMAP_IMAGE_PTR image,  // bitmap image to load with data
  2238.                         BITMAP_FILE_PTR bitmap,  // bitmap to scan image data from
  2239.                         int cx,int cy,   // cell or absolute pos. to scan image from
  2240.                         int mode)        // if 0 then cx,cy is cell position, else 
  2241.                                        // cx,cy are absolute coords
  2242. {
  2243. // this function extracts a 16-bit bitmap out of a 16-bit bitmap file
  2244. // is this a valid bitmap
  2245. if (!image)
  2246.    return(0);
  2247. // must be a 16bit bitmap
  2248. USHORT *source_ptr,   // working pointers
  2249.        *dest_ptr;
  2250. // test the mode of extraction, cell based or absolute
  2251. if (mode==BITMAP_EXTRACT_MODE_CELL)
  2252.    {
  2253.    // re-compute x,y
  2254.    cx = cx*(image->width+1) + 1;
  2255.    cy = cy*(image->height+1) + 1;
  2256.    } // end if
  2257. // extract bitmap data
  2258. source_ptr = (USHORT *)bitmap->buffer + 
  2259.              cy*bitmap->bitmapinfoheader.biWidth+cx;
  2260. // assign a pointer to the bimap image
  2261. dest_ptr = (USHORT *)image->buffer;
  2262. int bytes_per_line = image->width*2;
  2263. // iterate thru each scanline and copy bitmap
  2264. for (int index_y=0; index_y < image->height; index_y++)
  2265.     {
  2266.     // copy next line of data to destination
  2267.     memcpy(dest_ptr, source_ptr,bytes_per_line);
  2268.     // advance pointers
  2269.     dest_ptr   += image->width;
  2270.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  2271.     } // end for index_y
  2272. // set state to loaded
  2273. image->attr |= BITMAP_ATTR_LOADED;
  2274. // return success
  2275. return(1);
  2276. } // end Load_Image_Bitmap16
  2277. ///////////////////////////////////////////////////////////
  2278. int Scroll_Bitmap(BITMAP_IMAGE_PTR image, int dx, int dy)
  2279. {
  2280. // this function scrolls a bitmap
  2281. BITMAP_IMAGE temp_image; // temp image buffer
  2282. // are the parms valid 
  2283. if (!image || (dx==0 && dy==0))
  2284.    return(0);
  2285. // scroll on x-axis first
  2286. if (dx!=0)
  2287. {
  2288. // step 1: normalize scrolling amount
  2289. dx %= image->width;
  2290. // step 2: which way?
  2291. if (dx > 0)
  2292.    {
  2293.    // scroll right
  2294.    // create bitmap to hold region that is scrolled around
  2295.    Create_Bitmap(&temp_image, 0, 0, dx, image->height, image->bpp);
  2296.    // copy region we are going to scroll and wrap around
  2297.    Copy_Bitmap(&temp_image,0,0, 
  2298.                 image, image->width-dx,0, 
  2299.                 dx, image->height);
  2300.    // set some pointers up
  2301.    UCHAR *source_ptr = image->buffer;  // start of each line
  2302.    int shift         = (image->bpp >> 3)*dx;
  2303.    // now scroll image to right "scroll" pixels
  2304.    for (int y=0; y < image->height; y++)
  2305.        {
  2306.        // scroll the line over
  2307.        memmove(source_ptr+shift, source_ptr, (image->width-dx)*(image->bpp >> 3));
  2308.     
  2309.        // advance to the next line
  2310.        source_ptr+=((image->bpp >> 3)*image->width);
  2311.        } // end for
  2312.    
  2313.    // and now copy it back
  2314.    Copy_Bitmap(image, 0,0, &temp_image,0,0, 
  2315.                dx, image->height);           
  2316.    } // end if
  2317. else
  2318.    {
  2319.    // scroll left
  2320.    dx = -dx; // invert sign
  2321.    // create bitmap to hold region that is scrolled around
  2322.    Create_Bitmap(&temp_image, 0, 0, dx, image->height, image->bpp);
  2323.    // copy region we are going to scroll and wrap around
  2324.    Copy_Bitmap(&temp_image,0,0, 
  2325.                 image, 0,0, 
  2326.                 dx, image->height);
  2327.    // set some pointers up
  2328.    UCHAR *source_ptr = image->buffer;  // start of each line
  2329.    int shift         = (image->bpp >> 3)*dx;
  2330.    // now scroll image to left "scroll" pixels
  2331.    for (int y=0; y < image->height; y++)
  2332.        {
  2333.        // scroll the line over
  2334.        memmove(source_ptr, source_ptr+shift, (image->width-dx)*(image->bpp >> 3));
  2335.     
  2336.        // advance to the next line
  2337.        source_ptr+=((image->bpp >> 3)*image->width);
  2338.        } // end for
  2339.    
  2340.    // and now copy it back
  2341.    Copy_Bitmap(image, image->width-dx,0, &temp_image,0,0, 
  2342.                dx, image->height);           
  2343.    } // end else
  2344. } // end scroll on x-axis
  2345. // return success
  2346. return(1);
  2347. } // end Scroll_Bitmap
  2348. ///////////////////////////////////////////////////////////
  2349. int Copy_Bitmap(BITMAP_IMAGE_PTR dest_bitmap, int dest_x, int dest_y, 
  2350.                 BITMAP_IMAGE_PTR source_bitmap, int source_x, int source_y, 
  2351.                 int width, int height)
  2352. {
  2353. // this function copies a bitmap from one source to another
  2354. // make sure the pointers are at least valid
  2355. if (!dest_bitmap || !source_bitmap)
  2356.    return(0);
  2357. // do some computations
  2358. int bytes_per_pixel = (source_bitmap->bpp >> 3);
  2359. // create some pointers
  2360. UCHAR *source_ptr = source_bitmap->buffer + (source_x + source_y*source_bitmap->width)*bytes_per_pixel;
  2361. UCHAR *dest_ptr   = dest_bitmap->buffer   + (dest_x   + dest_y  *dest_bitmap->width)  *bytes_per_pixel;
  2362. // now copying is easy :)
  2363. for (int y = 0; y < height; y++)
  2364.     {
  2365.     // copy this line
  2366.     memcpy(dest_ptr, source_ptr, bytes_per_pixel*width);
  2367.     // advance the pointers
  2368.     source_ptr+=(source_bitmap->width*bytes_per_pixel);
  2369.     dest_ptr  +=(dest_bitmap->width*bytes_per_pixel);
  2370.     } // end for
  2371. // return success
  2372. return(1);
  2373. } // end Copy_Bitmap
  2374. ///////////////////////////////////////////////////////////
  2375. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
  2376. {
  2377. // this function opens a bitmap file and loads the data into bitmap
  2378. int file_handle,  // the file handle
  2379.     index;        // looping index
  2380. UCHAR   *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
  2381. OFSTRUCT file_data;          // the file data information
  2382. // open the file if it exists
  2383. if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
  2384.    return(0);
  2385. // now load the bitmap file header
  2386. _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
  2387. // test if this is a bitmap file
  2388. if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
  2389.    {
  2390.    // close the file
  2391.    _lclose(file_handle);
  2392.    // return error
  2393.    return(0);
  2394.    } // end if
  2395. // now we know this is a bitmap, so read in all the sections
  2396. // first the bitmap infoheader
  2397. // now load the bitmap file header
  2398. _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
  2399. // now load the color palette if there is one
  2400. if (bitmap->bitmapinfoheader.biBitCount == 8)
  2401.    {
  2402.    _lread(file_handle, &bitmap->palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  2403.    // now set all the flags in the palette correctly and fix the reversed 
  2404.    // BGR RGBQUAD data format
  2405.    for (index=0; index < MAX_COLORS_PALETTE; index++)
  2406.        {
  2407.        // reverse the red and green fields
  2408.        int temp_color                = bitmap->palette[index].peRed;
  2409.        bitmap->palette[index].peRed  = bitmap->palette[index].peBlue;
  2410.        bitmap->palette[index].peBlue = temp_color;
  2411.        
  2412.        // always set the flags word to this
  2413.        bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
  2414.        } // end for index
  2415.     } // end if
  2416. // finally the image data itself
  2417. _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
  2418. // now read in the image
  2419. if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16) 
  2420.    {
  2421.    // delete the last image if there was one
  2422.    if (bitmap->buffer)
  2423.        free(bitmap->buffer);
  2424.    // allocate the memory for the image
  2425.    if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  2426.       {
  2427.       // close the file
  2428.       _lclose(file_handle);
  2429.       // return error
  2430.       return(0);
  2431.       } // end if
  2432.    // now read it in
  2433.    _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
  2434.    } // end if
  2435. else
  2436. if (bitmap->bitmapinfoheader.biBitCount==24)
  2437.    {
  2438.    // allocate temporary buffer to load 24 bit image
  2439.    if (!(temp_buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  2440.       {
  2441.       // close the file
  2442.       _lclose(file_handle);
  2443.       // return error
  2444.       return(0);
  2445.       } // end if
  2446.    
  2447.    // allocate final 16 bit storage buffer
  2448.    if (!(bitmap->buffer=(UCHAR *)malloc(2*bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight)))
  2449.       {
  2450.       // close the file
  2451.       _lclose(file_handle);
  2452.       // release working buffer
  2453.       free(temp_buffer);
  2454.       // return error
  2455.       return(0);
  2456.       } // end if
  2457.    // now read the file in
  2458.    _lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);
  2459.    // now convert each 24 bit RGB value into a 16 bit value
  2460.    for (index=0; index < bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight; index++)
  2461.        {
  2462.        // build up 16 bit color word
  2463.        USHORT color;
  2464.        
  2465.        // build pixel based on format of directdraw surface
  2466.        if (dd_pixel_format==DD_PIXEL_FORMAT555)
  2467.            {
  2468.            // extract RGB components (in BGR order), note the scaling
  2469.            UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
  2470.                  green = (temp_buffer[index*3 + 1] >> 3),
  2471.                  red   = (temp_buffer[index*3 + 2] >> 3); 
  2472.            // use the 555 macro
  2473.            color = _RGB16BIT555(red,green,blue);
  2474.            } // end if 555
  2475.        else
  2476.        if (dd_pixel_format==DD_PIXEL_FORMAT565) 
  2477.           {
  2478.           // extract RGB components (in BGR order), note the scaling
  2479.            UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
  2480.                  green = (temp_buffer[index*3 + 1] >> 2),
  2481.                  red   = (temp_buffer[index*3 + 2] >> 3);
  2482.            // use the 565 macro
  2483.            color = _RGB16BIT565(red,green,blue);
  2484.           } // end if 565
  2485.        // write color to buffer
  2486.        ((USHORT *)bitmap->buffer)[index] = color;
  2487.        } // end for index