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

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