home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / Source / GPCHAP11 / Prog11_4_16b.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-04-27  |  20.2 KB  |  681 lines

  1. // PROG11_4_16b.CPP - a demo of bit blitting using clipping
  2. // 16bit version
  3.  
  4. // INCLUDES ///////////////////////////////////////////////
  5. #define WIN32_LEAN_AND_MEAN  
  6. #define INITGUID
  7.  
  8. #include <windows.h>   // include important windows stuff
  9. #include <windowsx.h> 
  10. #include <mmsystem.h>
  11. #include <iostream.h> // include important C/C++ stuff
  12. #include <conio.h>
  13. #include <stdlib.h>
  14. #include <malloc.h>
  15. #include <memory.h>
  16. #include <string.h>
  17. #include <stdarg.h>
  18. #include <stdio.h>
  19. #include <math.h>
  20. #include <io.h>
  21. #include <fcntl.h>
  22.  
  23. #include <ddraw.h>  // directX includes
  24.  
  25. // DEFINES ////////////////////////////////////////////////
  26.  
  27. // defines for windows 
  28. #define WINDOW_CLASS_NAME "WINXCLASS"  // class name
  29.  
  30. #define WINDOW_WIDTH  640         // size of window
  31. #define WINDOW_HEIGHT 480
  32. #define SCREEN_WIDTH  640         // size of screen
  33. #define SCREEN_HEIGHT 480
  34. #define SCREEN_BPP    16           // bits per pixel
  35.  
  36. #define BITMAP_ID     0x4D42      // universal id for a bitmap
  37.  
  38. // MACROS /////////////////////////////////////////////////
  39.  
  40. // these read the keyboard asynchronously
  41. #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
  42. #define KEY_UP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
  43.  
  44. // this builds a 16 bit color value in 5.5.5 format (1-bit alpha mode)
  45. #define _RGB16BIT555(r,g,b) ((b & 31) + ((g & 31) << 5) + ((r & 31) << 10))
  46.  
  47. // this builds a 16 bit color value in 5.6.5 format (green dominate mode)
  48. #define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))
  49.  
  50. // TYPES //////////////////////////////////////////////////
  51.  
  52. typedef unsigned short USHORT;
  53. typedef unsigned short WORD;
  54. typedef unsigned char  UCHAR;
  55. typedef unsigned char  BYTE;
  56.  
  57. // container structure for bitmaps .BMP file
  58. typedef struct BITMAP_FILE_TAG
  59.         {
  60.         BITMAPFILEHEADER bitmapfileheader;  // this contains the bitmapfile header
  61.         BITMAPINFOHEADER bitmapinfoheader;  // this is all the info including the palette
  62.         PALETTEENTRY     palette[256];      // we will store the palette here
  63.         UCHAR            *buffer;           // this is a pointer to the data
  64.  
  65.         } BITMAP_FILE, *BITMAP_FILE_PTR;
  66.  
  67. // PROTOTYPES /////////////////////////////////////////////
  68.  
  69. // game console
  70. int Game_Init(void *parms=NULL);
  71. int Game_Shutdown(void *parms=NULL);
  72. int Game_Main(void *parms=NULL);
  73.  
  74. // bitmap functions
  75. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);
  76. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap);
  77. int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height);
  78.  
  79. // clipping stuff
  80. LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,int num_rects,LPRECT clip_list);
  81.  
  82. // GLOBALS ////////////////////////////////////////////////
  83.  
  84. HWND main_window_handle = NULL; // save the window handle
  85. HINSTANCE main_instance = NULL; // save the instance
  86. char buffer[80];                // used to print text
  87.  
  88. LPDIRECTDRAW7        lpdd         = NULL;  // dd object
  89. LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;  // dd primary surface
  90. LPDIRECTDRAWSURFACE7 lpddsback    = NULL;  // dd back surface
  91. LPDIRECTDRAWPALETTE  lpddpal      = NULL;  // a pointer to the created dd palette
  92. LPDIRECTDRAWCLIPPER  lpddclipper  = NULL;  // a dd clipper
  93. PALETTEENTRY         palette[256];         // color palette
  94. DDSURFACEDESC2       ddsd;                 // a direct draw surface description struct
  95. DDSCAPS2             ddscaps;              // a direct draw surface capabilities struct
  96. HRESULT              ddrval;               // result back from dd calls
  97. USHORT               *primary_buffer = NULL; // primary video buffer
  98. USHORT               *back_buffer    = NULL; // secondary back buffer
  99. BITMAP_FILE          bitmap16bit,            // a 16 bit bitmap file
  100.                      bitmap8bit;             // a 8 bit bitmap file
  101.  
  102. // FUNCTIONS //////////////////////////////////////////////
  103.  
  104. LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,
  105.                                       int num_rects,
  106.                                       LPRECT clip_list)
  107.  
  108. {
  109. // this function creates a clipper from the sent clip list and attaches
  110. // it to the sent surface
  111.  
  112. int index;                         // looping var
  113. LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly created dd clipper
  114. LPRGNDATA region_data;             // pointer to the region data that contains
  115.                                    // the header and clip list
  116.  
  117. // first create the direct draw clipper
  118. if ((lpdd->CreateClipper(0,&lpddclipper,NULL))!=DD_OK)
  119.    return(NULL);
  120.  
  121. // now create the clip list from the sent data
  122.  
  123. // first allocate memory for region data
  124. region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));
  125.  
  126. // now copy the rects into region data
  127. memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);
  128.  
  129. // set up fields of header
  130. region_data->rdh.dwSize          = sizeof(RGNDATAHEADER);
  131. region_data->rdh.iType           = RDH_RECTANGLES;
  132. region_data->rdh.nCount          = num_rects;
  133. region_data->rdh.nRgnSize        = num_rects*sizeof(RECT);
  134.  
  135. region_data->rdh.rcBound.left    =  64000;
  136. region_data->rdh.rcBound.top     =  64000;
  137. region_data->rdh.rcBound.right   = -64000;
  138. region_data->rdh.rcBound.bottom  = -64000;
  139.  
  140. // find bounds of all clipping regions
  141. for (index=0; index<num_rects; index++)
  142.     {
  143.     // test if the next rectangle unioned with the current bound is larger
  144.     if (clip_list[index].left < region_data->rdh.rcBound.left)
  145.        region_data->rdh.rcBound.left = clip_list[index].left;
  146.  
  147.     if (clip_list[index].right > region_data->rdh.rcBound.right)
  148.        region_data->rdh.rcBound.right = clip_list[index].right;
  149.  
  150.     if (clip_list[index].top < region_data->rdh.rcBound.top)
  151.        region_data->rdh.rcBound.top = clip_list[index].top;
  152.  
  153.     if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)
  154.        region_data->rdh.rcBound.bottom = clip_list[index].bottom;
  155.  
  156.     } // end for index
  157.  
  158. // now we have computed the bounding rectangle region and set up the data
  159. // now let's set the clipping list
  160.  
  161. if ((lpddclipper->SetClipList(region_data, 0))!=DD_OK)
  162.    {
  163.    // release memory and return error
  164.    free(region_data);
  165.    return(NULL);
  166.    } // end if
  167.  
  168. // now attach the clipper to the surface
  169. if ((lpdds->SetClipper(lpddclipper))!=DD_OK)
  170.    {
  171.    // release memory and return error
  172.    free(region_data);
  173.    return(NULL);
  174.    } // end if
  175.  
  176. // all is well, so release memory and send back the pointer to the new clipper
  177. free(region_data);
  178. return(lpddclipper);
  179.  
  180. } // end DD_Attach_Clipper
  181.  
  182. /////////////////////////////////////////////////////////////////////////////////
  183.  
  184. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
  185. {
  186. // this function opens a bitmap file and loads the data into bitmap
  187.  
  188. int file_handle,  // the file handle
  189.     index;        // looping index
  190.  
  191. UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
  192. OFSTRUCT file_data;        // the file data information
  193.  
  194. // open the file if it exists
  195. if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
  196.    return(0);
  197.  
  198. // now load the bitmap file header
  199. _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
  200.  
  201. // test if this is a bitmap file
  202. if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
  203.    {
  204.    // close the file
  205.    _lclose(file_handle);
  206.  
  207.    // return error
  208.    return(0);
  209.    } // end if
  210.  
  211. // now we know this is a bitmap, so read in all the sections
  212.  
  213. // first the bitmap infoheader
  214.  
  215. // now load the bitmap file header
  216. _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
  217.  
  218. // now load the color palette if there is one
  219. if (bitmap->bitmapinfoheader.biBitCount == 8)
  220.    {
  221.    _lread(file_handle, &bitmap->palette,256*sizeof(PALETTEENTRY));
  222.  
  223.    // now set all the flags in the palette correctly and fix the reversed 
  224.    // BGR RGBQUAD data format
  225.    for (index=0; index < 256; index++)
  226.        {
  227.        // reverse the red and green fields
  228.        int temp_color = bitmap->palette[index].peRed;
  229.        bitmap->palette[index].peRed  = bitmap->palette[index].peBlue;
  230.        bitmap->palette[index].peBlue = temp_color;
  231.        
  232.        // always set the flags word to this
  233.        bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
  234.        } // end for index
  235.  
  236.     } // end if
  237.  
  238. // finally the image data itself
  239. _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
  240.  
  241. // now read in the image, if the image is 8 or 16 bit then simply read it
  242. // but if its 24 bit then read it into a temporary area and then convert
  243. // it to a 16 bit image
  244.  
  245. if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16)
  246.    {
  247.    // allocate the memory for the image
  248.    if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  249.       {
  250.       // close the file
  251.       _lclose(file_handle);
  252.  
  253.       // return error
  254.       return(0);
  255.       } // end if
  256.  
  257.    // now read it in
  258.    _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
  259.  
  260.    } // end if
  261. else
  262.    {
  263.    // this must be a 24 bit image, load it in and convert it to 16 bit
  264. //   printf("\nconverting 24 bit image...");
  265.  
  266.    // allocate temporary buffer
  267.    if (!(temp_buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  268.       {
  269.       // close the file
  270.       _lclose(file_handle);
  271.  
  272.       // return error
  273.       return(0);
  274.       } // end if
  275.    
  276.    // allocate final 16 bit storage buffer
  277.    if (!(bitmap->buffer=(UCHAR *)malloc(2*bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight)))
  278.       {
  279.       // close the file
  280.       _lclose(file_handle);
  281.  
  282.       // release working buffer
  283.       free(temp_buffer);
  284.  
  285.       // return error
  286.       return(0);
  287.       } // end if
  288.  
  289.    // now read it in
  290.    _lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);
  291.  
  292.    // now convert each 24 bit RGB value into a 16 bit value
  293.    for (index=0; index<bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight; index++)
  294.        {
  295.        // extract RGB components (note they are in memory BGR)
  296.        // also, assume 5.6.5 format, so scale appropriately
  297.        UCHAR red    = (temp_buffer[index*3 + 2] >> 3), // 5 bits
  298.              green  = (temp_buffer[index*3 + 1] >> 2), // 6 bits, change to 3 for 5 bits
  299.              blue   = (temp_buffer[index*3 + 0] >> 3); // 5 bits
  300.  
  301.        // build up 16 bit color word assume 5.6.5 format
  302.        USHORT color = _RGB16BIT565(red,green,blue);
  303.  
  304.        // write color to buffer
  305.        ((USHORT *)bitmap->buffer)[index] = color;
  306.  
  307.        } // end for index
  308.  
  309.    // finally write out the correct number of bits
  310.    bitmap->bitmapinfoheader.biBitCount=16;
  311.  
  312.    } // end if
  313.  
  314. #if 0
  315. // write the file info out 
  316. printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
  317.         filename,
  318.         bitmap->bitmapinfoheader.biSizeImage,
  319.         bitmap->bitmapinfoheader.biWidth,
  320.         bitmap->bitmapinfoheader.biHeight,
  321.         bitmap->bitmapinfoheader.biBitCount,
  322.         bitmap->bitmapinfoheader.biClrUsed,
  323.         bitmap->bitmapinfoheader.biClrImportant);
  324. #endif
  325.  
  326. // close the file
  327. _lclose(file_handle);
  328.  
  329. // flip the bitmap
  330. Flip_Bitmap(bitmap->buffer, 
  331.             bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8), 
  332.             bitmap->bitmapinfoheader.biHeight);
  333.  
  334. // return success
  335. return(1);
  336.  
  337. } // end Load_Bitmap_File
  338.  
  339. ///////////////////////////////////////////////////////////
  340.  
  341. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
  342. {
  343. // this function releases all memory associated with "bitmap"
  344. if (bitmap->buffer)
  345.    {
  346.    // release memory
  347.    free(bitmap->buffer);
  348.  
  349.    // reset pointer
  350.    bitmap->buffer = NULL;
  351.  
  352.    } // end if
  353.  
  354. // return success
  355. return(1);
  356.  
  357. } // end Unload_Bitmap_File
  358.  
  359. ///////////////////////////////////////////////////////////
  360.  
  361. int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
  362. {
  363. // this function is used to flip upside down .BMP images
  364.  
  365. UCHAR *buffer; // used to perform the image processing
  366. int index;     // looping index
  367.  
  368. // allocate the temporary buffer
  369. if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
  370.    return(0);
  371.  
  372. // copy image to work area
  373. memcpy(buffer,image,bytes_per_line*height);
  374.  
  375. // flip vertically
  376. for (index=0; index < height; index++)
  377.     memcpy(&image[((height-1) - index)*bytes_per_line],
  378.            &buffer[index*bytes_per_line], bytes_per_line);
  379.  
  380. // release the memory
  381. free(buffer);
  382.  
  383. // return success
  384. return(1);
  385.  
  386. } // end Flip_Bitmap
  387.  
  388. ///////////////////////////////////////////////////////////
  389.  
  390. LRESULT CALLBACK WindowProc(HWND hwnd, 
  391.                             UINT msg, 
  392.                             WPARAM wparam, 
  393.                             LPARAM lparam)
  394. {
  395. // this is the main message handler of the system
  396. PAINTSTRUCT    ps;           // used in WM_PAINT
  397. HDC            hdc;       // handle to a device context
  398.  
  399. // what is the message 
  400. switch(msg)
  401.     {    
  402.     case WM_CREATE: 
  403.         {
  404.         // do initialization stuff here
  405.         return(0);
  406.         } break;
  407.  
  408.     case WM_PAINT:
  409.          {
  410.          // start painting
  411.          hdc = BeginPaint(hwnd,&ps);
  412.  
  413.          // end painting
  414.          EndPaint(hwnd,&ps);
  415.          return(0);
  416.         } break;
  417.  
  418.     case WM_DESTROY: 
  419.         {
  420.         // kill the application            
  421.         PostQuitMessage(0);
  422.         return(0);
  423.         } break;
  424.  
  425.     default:break;
  426.  
  427.     } // end switch
  428.  
  429. // process any messages that we didn't take care of 
  430. return (DefWindowProc(hwnd, msg, wparam, lparam));
  431.  
  432. } // end WinProc
  433.  
  434. // WINMAIN ////////////////////////////////////////////////
  435.  
  436. int WINAPI WinMain(    HINSTANCE hinstance,
  437.                     HINSTANCE hprevinstance,
  438.                     LPSTR lpcmdline,
  439.                     int ncmdshow)
  440. {
  441.  
  442. WNDCLASS winclass;    // this will hold the class we create
  443. HWND     hwnd;        // generic window handle
  444. MSG         msg;        // generic message
  445. HDC      hdc;       // generic dc
  446. PAINTSTRUCT ps;     // generic paintstruct
  447.  
  448. // first fill in the window class stucture
  449. winclass.style            = CS_DBLCLKS | CS_OWNDC | 
  450.                           CS_HREDRAW | CS_VREDRAW;
  451. winclass.lpfnWndProc    = WindowProc;
  452. winclass.cbClsExtra        = 0;
  453. winclass.cbWndExtra        = 0;
  454. winclass.hInstance        = hinstance;
  455. winclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
  456. winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  457. winclass.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
  458. winclass.lpszMenuName    = NULL; 
  459. winclass.lpszClassName    = WINDOW_CLASS_NAME;
  460.  
  461. // register the window class
  462. if (!RegisterClass(&winclass))
  463.     return(0);
  464.  
  465. // create the window, note the use of WS_POPUP
  466. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  467.                           "WinX Game Console",     // title
  468.                           WS_POPUP | WS_VISIBLE,
  469.                            0,0,       // x,y
  470.                           WINDOW_WIDTH,  // width
  471.                           WINDOW_HEIGHT, // height
  472.                           NULL,       // handle to parent 
  473.                           NULL,       // handle to menu
  474.                           hinstance,// instance
  475.                           NULL)))    // creation parms
  476. return(0);
  477.  
  478. // hide the mouse
  479. ShowCursor(FALSE);
  480.  
  481. // save the window handle and instance in a global
  482. main_window_handle = hwnd;
  483. main_instance      = hinstance;
  484.  
  485. // perform all game console specific initialization
  486. Game_Init();
  487.  
  488. // enter main event loop
  489. while(1)
  490.     {
  491.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  492.         { 
  493.         // test if this is a quit
  494.         if (msg.message == WM_QUIT)
  495.            break;
  496.     
  497.         // translate any accelerator keys
  498.         TranslateMessage(&msg);
  499.  
  500.         // send the message to the window proc
  501.         DispatchMessage(&msg);
  502.         } // end if
  503.     
  504.     // main game processing goes here
  505.     Game_Main();
  506.  
  507.     } // end while
  508.  
  509. // shutdown game and release all resources
  510. Game_Shutdown();
  511.  
  512. // return to Windows like this
  513. return(msg.wParam);
  514.  
  515. } // end WinMain
  516.  
  517. // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  518.  
  519. int Game_Init(void *parms)
  520. {
  521. // this function is where you do all the initialization 
  522. // for your game
  523.  
  524. // create object and test for error
  525. if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)!=DD_OK)
  526.    return(0);
  527.  
  528. // set cooperation level to windowed mode normal
  529. if (lpdd->SetCooperativeLevel(main_window_handle,
  530.            DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 
  531.            DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)!=DD_OK)
  532.     return(0);
  533.  
  534. // set the display mode
  535. if (lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,0,0)!=DD_OK)
  536.    return(0);
  537.  
  538. // Create the primary surface
  539. memset(&ddsd,0,sizeof(ddsd));
  540. ddsd.dwSize = sizeof(ddsd);
  541. ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  542.  
  543. // we need to let dd know that we want a complex 
  544. // flippable surface structure, set flags for that
  545. ddsd.ddsCaps.dwCaps = 
  546.   DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  547.  
  548. // set the backbuffer count to 1
  549. ddsd.dwBackBufferCount = 1;
  550.  
  551. // create the primary surface
  552. lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);
  553.  
  554. // query for the backbuffer i.e the secondary surface
  555. ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  556. lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback);
  557.  
  558. // now load the 8 bit color bitmap
  559. Load_Bitmap_File(&bitmap16bit, "ANDRE16.BMP");
  560.  
  561. // copy bitmap into secondary buffer
  562. // set up the surface description to lock the surface
  563. memset(&ddsd,0,sizeof(ddsd)); 
  564. ddsd.dwSize = sizeof(ddsd);
  565.  
  566. // lock the primary surface, note in a real game you would
  567. lpddsback->Lock(NULL,&ddsd, 
  568.                    DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
  569.  
  570. // get video pointer
  571. back_buffer = (USHORT *)ddsd.lpSurface;
  572.  
  573. // copy each bitmap line into primary buffer 
  574. // taking into consideration non-linear video 
  575. // cards and the memory pitch lPitch
  576. for (int y=0; y < SCREEN_HEIGHT; y++)
  577.     {
  578.     // copy the line
  579.     memcpy(&back_buffer[y*(ddsd.lPitch/2)],       // dest address
  580.            &bitmap16bit.buffer[y*SCREEN_WIDTH*2], // src address
  581.            SCREEN_WIDTH*2);                       // bytes to copy
  582.     } // end for y
  583.  
  584. // unlock the surface
  585. lpddsback->Unlock(NULL);
  586.  
  587. // set up the clipper
  588. // create clip list (4) rectangles
  589. RECT cliplist[4] = { {0,0,100,100}, {200,200,300,300},          
  590.                      {400,100,500,200}, {500,400,550,450}}; 
  591.  
  592. // attach clipper and save in lpddclipper
  593. lpddclipper = DD_Attach_Clipper(lpddsprimary,4,cliplist);
  594.  
  595. // return success
  596. return(1);
  597.  
  598. } // end Game_Init
  599.  
  600. ///////////////////////////////////////////////////////////
  601.  
  602. int Game_Shutdown(void *parms)
  603. {
  604. // this function is where you shutdown your game and
  605. // release all resources that you allocated
  606.  
  607. // first release the secondary surface
  608. if (lpddsback!=NULL)
  609.    lpddsback->Release();
  610.  
  611. // now release the primary surface
  612. if (lpddsprimary!=NULL)
  613.    lpddsprimary->Release();
  614.        
  615. // release the directdraw object
  616. if (lpdd!=NULL)
  617.    lpdd->Release();
  618.  
  619. // delete the bitmap 
  620. Unload_Bitmap_File(&bitmap8bit);
  621.  
  622. // return success
  623. return(1);
  624. } // end Game_Shutdown
  625.  
  626. ///////////////////////////////////////////////////////////
  627.  
  628. int Game_Main(void *parms)
  629. {
  630. // this is the workhorse of your game it will be called
  631. // continuously in real-time this is like main() in C
  632. // all the calls for you game go here!
  633.  
  634. // check of user is trying to exit
  635. if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
  636.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  637.  
  638. // select source position to grab bitmap from
  639. int source_x = rand()%SCREEN_WIDTH;
  640. int source_y = rand()%SCREEN_HEIGHT;
  641.  
  642. // select destination position to put to
  643. int dest_x = rand()%SCREEN_WIDTH;
  644. int dest_y = rand()%SCREEN_HEIGHT;
  645.  
  646. // select width and height of rectangle 
  647. int width = rand()%SCREEN_WIDTH;
  648. int height = rand()%SCREEN_HEIGHT;
  649.  
  650. // set up rectangles
  651. RECT source_rect, dest_rect;
  652.  
  653. source_rect.left   = source_x;
  654. source_rect.top    = source_y;
  655. source_rect.right  = source_x + width;
  656. source_rect.bottom = source_y + height;
  657.  
  658. dest_rect.left   = dest_x;
  659. dest_rect.top    = dest_y;
  660. dest_rect.right  = dest_x + width;
  661. dest_rect.bottom = dest_y + height;
  662.  
  663. // set up the color key so that RGB 0,0,0 is transparent
  664. DDCOLORKEY col_key;
  665. col_key.dwColorSpaceLowValue  = _RGB16BIT565(0,0,0);
  666. col_key.dwColorSpaceHighValue = _RGB16BIT565(0,0,0);
  667.  
  668. // set the key
  669. lpddsback->SetColorKey(DDCKEY_SRCBLT, &col_key);
  670.  
  671. // perform the blit from back to primary, but the output will only
  672. // be seen in the clipping windows defined in Game_Init()
  673. lpddsprimary->Blt(&dest_rect, lpddsback, &source_rect, DDBLT_KEYSRC | DDBLT_WAIT, NULL);
  674.  
  675. // return success
  676. return(1);
  677.  
  678. } // end Game_Main
  679.  
  680.  
  681.