home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / Source / GPCHAP10 / PROG10_7.CPP < prev    next >
C/C++ Source or Header  |  2002-04-27  |  18KB  |  609 lines

  1. // PROG10_7.CPP - a demo of bit blitting from secondary
  2. // surface to primary surface
  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    8           // 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. int Game_Init(void *parms=NULL);
  70. int Game_Shutdown(void *parms=NULL);
  71. int Game_Main(void *parms=NULL);
  72.  
  73. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);
  74. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap);
  75. int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height);
  76.  
  77. // GLOBALS ////////////////////////////////////////////////
  78.  
  79. HWND main_window_handle = NULL; // save the window handle
  80. HINSTANCE main_instance = NULL; // save the instance
  81. char buffer[80];                // used to print text
  82.  
  83. LPDIRECTDRAW7        lpdd         = NULL;  // dd object
  84. LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;  // dd primary surface
  85. LPDIRECTDRAWSURFACE7 lpddsback    = NULL;  // dd back surface
  86. LPDIRECTDRAWPALETTE  lpddpal      = NULL;  // a pointer to the created dd palette
  87. PALETTEENTRY         palette[256];         // color palette
  88. DDSURFACEDESC2       ddsd;                 // a direct draw surface description struct
  89. DDSCAPS2             ddscaps;              // a direct draw surface capabilities struct
  90. HRESULT              ddrval;               // result back from dd calls
  91. UCHAR                *primary_buffer = NULL; // primary video buffer
  92. UCHAR                *back_buffer    = NULL; // secondary back buffer
  93. BITMAP_FILE          bitmap16bit,            // a 16 bit bitmap file
  94.                      bitmap8bit;             // a 8 bit bitmap file
  95.  
  96. // FUNCTIONS //////////////////////////////////////////////
  97.  
  98. LRESULT CALLBACK WindowProc(HWND hwnd, 
  99.                             UINT msg, 
  100.                             WPARAM wparam, 
  101.                             LPARAM lparam)
  102. {
  103. // this is the main message handler of the system
  104. PAINTSTRUCT    ps;           // used in WM_PAINT
  105. HDC            hdc;       // handle to a device context
  106.  
  107. // what is the message 
  108. switch(msg)
  109.     {    
  110.     case WM_CREATE: 
  111.         {
  112.         // do initialization stuff here
  113.         return(0);
  114.         } break;
  115.  
  116.     case WM_PAINT:
  117.          {
  118.          // start painting
  119.          hdc = BeginPaint(hwnd,&ps);
  120.  
  121.          // end painting
  122.          EndPaint(hwnd,&ps);
  123.          return(0);
  124.         } break;
  125.  
  126.     case WM_DESTROY: 
  127.         {
  128.         // kill the application            
  129.         PostQuitMessage(0);
  130.         return(0);
  131.         } break;
  132.  
  133.     default:break;
  134.  
  135.     } // end switch
  136.  
  137. // process any messages that we didn't take care of 
  138. return (DefWindowProc(hwnd, msg, wparam, lparam));
  139.  
  140. } // end WinProc
  141.  
  142. // WINMAIN ////////////////////////////////////////////////
  143.  
  144. int WINAPI WinMain(    HINSTANCE hinstance,
  145.                     HINSTANCE hprevinstance,
  146.                     LPSTR lpcmdline,
  147.                     int ncmdshow)
  148. {
  149.  
  150. WNDCLASS winclass;    // this will hold the class we create
  151. HWND     hwnd;        // generic window handle
  152. MSG         msg;        // generic message
  153. HDC      hdc;       // generic dc
  154. PAINTSTRUCT ps;     // generic paintstruct
  155.  
  156. // first fill in the window class stucture
  157. winclass.style            = CS_DBLCLKS | CS_OWNDC | 
  158.                           CS_HREDRAW | CS_VREDRAW;
  159. winclass.lpfnWndProc    = WindowProc;
  160. winclass.cbClsExtra        = 0;
  161. winclass.cbWndExtra        = 0;
  162. winclass.hInstance        = hinstance;
  163. winclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
  164. winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  165. winclass.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
  166. winclass.lpszMenuName    = NULL; 
  167. winclass.lpszClassName    = WINDOW_CLASS_NAME;
  168.  
  169. // register the window class
  170. if (!RegisterClass(&winclass))
  171.     return(0);
  172.  
  173. // create the window, note the use of WS_POPUP
  174. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  175.                           "WinX Game Console",     // title
  176.                           WS_POPUP | WS_VISIBLE,
  177.                            0,0,       // x,y
  178.                           WINDOW_WIDTH,  // width
  179.                           WINDOW_HEIGHT, // height
  180.                           NULL,       // handle to parent 
  181.                           NULL,       // handle to menu
  182.                           hinstance,// instance
  183.                           NULL)))    // creation parms
  184. return(0);
  185.  
  186. // hide the mouse
  187. ShowCursor(FALSE);
  188.  
  189. // save the window handle and instance in a global
  190. main_window_handle = hwnd;
  191. main_instance      = hinstance;
  192.  
  193. // perform all game console specific initialization
  194. Game_Init();
  195.  
  196. // enter main event loop
  197. while(1)
  198.     {
  199.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  200.         { 
  201.         // test if this is a quit
  202.         if (msg.message == WM_QUIT)
  203.            break;
  204.     
  205.         // translate any accelerator keys
  206.         TranslateMessage(&msg);
  207.  
  208.         // send the message to the window proc
  209.         DispatchMessage(&msg);
  210.         } // end if
  211.     
  212.     // main game processing goes here
  213.     Game_Main();
  214.  
  215.     } // end while
  216.  
  217. // shutdown game and release all resources
  218. Game_Shutdown();
  219.  
  220. // return to Windows like this
  221. return(msg.wParam);
  222.  
  223. } // end WinMain
  224.  
  225. // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  226.  
  227. int Game_Init(void *parms)
  228. {
  229. // this function is where you do all the initialization 
  230. // for your game
  231.  
  232. // create object and test for error
  233. if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)!=DD_OK)
  234.    return(0);
  235.  
  236. // set cooperation level to windowed mode normal
  237. if (lpdd->SetCooperativeLevel(main_window_handle,
  238.            DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 
  239.            DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)!=DD_OK)
  240.     return(0);
  241.  
  242. // set the display mode
  243. if (lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,0,0)!=DD_OK)
  244.    return(0);
  245.  
  246. // Create the primary surface
  247. memset(&ddsd,0,sizeof(ddsd));
  248. ddsd.dwSize = sizeof(ddsd);
  249. ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  250.  
  251. // we need to let dd know that we want a complex 
  252. // flippable surface structure, set flags for that
  253. ddsd.ddsCaps.dwCaps = 
  254.   DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  255.  
  256. // set the backbuffer count to 1
  257. ddsd.dwBackBufferCount = 1;
  258.  
  259. // create the primary surface
  260. lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);
  261.  
  262. // query for the backbuffer i.e the secondary surface
  263. ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  264. lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback);
  265.  
  266. // create and attach palette
  267.  
  268. // create palette data
  269. // first clear out all the entries, defensive programming
  270. memset(palette,0,256*sizeof(PALETTEENTRY));
  271.  
  272. // create a R,G,B,GR gradient palette
  273. for (int index=0; index<256; index++)
  274.     {
  275.     // set flags
  276.     palette[index].peFlags = PC_NOCOLLAPSE;
  277.     } // end for index
  278.  
  279. // now create the palette object
  280. if (lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE | DDPCAPS_ALLOW256,
  281.                          palette,&lpddpal,NULL)!=DD_OK)
  282.    return(0);
  283.  
  284. // attach the palette to the primary
  285. if (lpddsprimary->SetPalette(lpddpal)!=DD_OK)
  286.    return(0);
  287.  
  288. // now load the 8 bit color bitmap
  289. Load_Bitmap_File(&bitmap8bit, "ANDRE8.BMP");
  290.  
  291. // now load the palette into the directdraw
  292. lpddpal->SetEntries(0,0,256,bitmap8bit.palette);
  293.  
  294. // copy bitmap into secondary buffer
  295. // set up the surface description to lock the surface
  296. memset(&ddsd,0,sizeof(ddsd)); 
  297. ddsd.dwSize = sizeof(ddsd);
  298.  
  299. // lock the primary surface, note in a real game you would
  300. lpddsback->Lock(NULL,&ddsd, 
  301.                    DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
  302.  
  303. // get video pointer
  304. back_buffer = (UCHAR *)ddsd.lpSurface;
  305.  
  306. // copy each bitmap line into primary buffer 
  307. // taking into consideration non-linear video 
  308. // cards and the memory pitch lPitch
  309. for (int y=0; y < SCREEN_HEIGHT; y++)
  310.     {
  311.     // copy the line
  312.     memcpy(&back_buffer[y*ddsd.lPitch], // dest address
  313.            &bitmap8bit.buffer[y*SCREEN_WIDTH],   // src address
  314.            SCREEN_WIDTH);                        // bytes to copy
  315.     } // end for y
  316.  
  317. // unlock the surface
  318. lpddsback->Unlock(NULL);
  319.  
  320. // return success
  321. return(1);
  322.  
  323. } // end Game_Init
  324.  
  325. ///////////////////////////////////////////////////////////
  326.  
  327. int Game_Shutdown(void *parms)
  328. {
  329. // this function is where you shutdown your game and
  330. // release all resources that you allocated
  331.  
  332. // first release the secondary surface
  333. if (lpddsback!=NULL)
  334.    lpddsback->Release();
  335.  
  336. // now release the primary surface
  337. if (lpddsprimary!=NULL)
  338.    lpddsprimary->Release();
  339.        
  340. // release the directdraw object
  341. if (lpdd!=NULL)
  342.    lpdd->Release();
  343.  
  344. // delete the bitmap 
  345. Unload_Bitmap_File(&bitmap8bit);
  346.  
  347. // return success
  348. return(1);
  349. } // end Game_Shutdown
  350.  
  351. ///////////////////////////////////////////////////////////
  352.  
  353. int Game_Main(void *parms)
  354. {
  355. // this is the workhorse of your game it will be called
  356. // continuously in real-time this is like main() in C
  357. // all the calls for you game go here!
  358.  
  359. // check of user is trying to exit
  360. if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
  361.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  362.  
  363. // select source position to grab bitmap from
  364. int source_x = rand()%SCREEN_WIDTH;
  365. int source_y = rand()%SCREEN_HEIGHT;
  366.  
  367. // select destination position to put to
  368. int dest_x = rand()%SCREEN_WIDTH;
  369. int dest_y = rand()%SCREEN_HEIGHT;
  370.  
  371. // select width and height of rectangle 
  372. int width = rand()%SCREEN_WIDTH;
  373. int height = rand()%SCREEN_HEIGHT;
  374.  
  375. // set up rectangles
  376. RECT source_rect, dest_rect;
  377.  
  378. source_rect.left   = source_x;
  379. source_rect.top    = source_y;
  380. source_rect.right  = source_x + width;
  381. source_rect.bottom = source_y + height;
  382.  
  383. dest_rect.left   = dest_x;
  384. dest_rect.top    = dest_y;
  385. dest_rect.right  = dest_x + width;
  386. dest_rect.bottom = dest_y + height;
  387.  
  388. // set up the color key so that color 0 is transparent
  389. DDCOLORKEY col_key;
  390. col_key.dwColorSpaceLowValue  = 0; 
  391. col_key.dwColorSpaceHighValue = 0;
  392.  
  393. // set the key
  394. lpddsback->SetColorKey(DDCKEY_SRCBLT, &col_key);
  395.  
  396. // perform the blit from back to primary
  397. lpddsprimary->Blt(&dest_rect, lpddsback, &source_rect, DDBLT_KEYSRC | DDBLT_WAIT, NULL);
  398.  
  399. // return success
  400. return(1);
  401.  
  402. } // end Game_Main
  403.  
  404. ///////////////////////////////////////////////////////////
  405.  
  406. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
  407. {
  408. // this function opens a bitmap file and loads the data into bitmap
  409.  
  410. int file_handle,  // the file handle
  411.     index;        // looping index
  412.  
  413. UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
  414. OFSTRUCT file_data;        // the file data information
  415.  
  416. // open the file if it exists
  417. if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
  418.    return(0);
  419.  
  420. // now load the bitmap file header
  421. _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
  422.  
  423. // test if this is a bitmap file
  424. if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
  425.    {
  426.    // close the file
  427.    _lclose(file_handle);
  428.  
  429.    // return error
  430.    return(0);
  431.    } // end if
  432.  
  433. // now we know this is a bitmap, so read in all the sections
  434.  
  435. // first the bitmap infoheader
  436.  
  437. // now load the bitmap file header
  438. _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
  439.  
  440. // now load the color palette if there is one
  441. if (bitmap->bitmapinfoheader.biBitCount == 8)
  442.    {
  443.    _lread(file_handle, &bitmap->palette,256*sizeof(PALETTEENTRY));
  444.  
  445.    // now set all the flags in the palette correctly and fix the reversed 
  446.    // BGR RGBQUAD data format
  447.    for (index=0; index < 256; index++)
  448.        {
  449.        // reverse the red and green fields
  450.        int temp_color = bitmap->palette[index].peRed;
  451.        bitmap->palette[index].peRed  = bitmap->palette[index].peBlue;
  452.        bitmap->palette[index].peBlue = temp_color;
  453.        
  454.        // always set the flags word to this
  455.        bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
  456.        } // end for index
  457.  
  458.     } // end if
  459.  
  460. // finally the image data itself
  461. _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
  462.  
  463. // now read in the image, if the image is 8 or 16 bit then simply read it
  464. // but if its 24 bit then read it into a temporary area and then convert
  465. // it to a 16 bit image
  466.  
  467. if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16)
  468.    {
  469.    // allocate the memory for the image
  470.    if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  471.       {
  472.       // close the file
  473.       _lclose(file_handle);
  474.  
  475.       // return error
  476.       return(0);
  477.       } // end if
  478.  
  479.    // now read it in
  480.    _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
  481.  
  482.    } // end if
  483. else
  484.    {
  485.    // this must be a 24 bit image, load it in and convert it to 16 bit
  486. //   printf("\nconverting 24 bit image...");
  487.  
  488.    // allocate temporary buffer
  489.    if (!(temp_buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  490.       {
  491.       // close the file
  492.       _lclose(file_handle);
  493.  
  494.       // return error
  495.       return(0);
  496.       } // end if
  497.    
  498.    // allocate final 16 bit storage buffer
  499.    if (!(bitmap->buffer=(UCHAR *)malloc(2*bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight)))
  500.       {
  501.       // close the file
  502.       _lclose(file_handle);
  503.  
  504.       // release working buffer
  505.       free(temp_buffer);
  506.  
  507.       // return error
  508.       return(0);
  509.       } // end if
  510.  
  511.    // now read it in
  512.    _lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);
  513.  
  514.    // now convert each 24 bit RGB value into a 16 bit value
  515.    for (index=0; index<bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight; index++)
  516.        {
  517.        // extract RGB components (note they are in memory BGR)
  518.        // also, assume 5.6.5 format, so scale appropriately
  519.        UCHAR red    = (temp_buffer[index*3 + 2] >> 3), // 5 bits
  520.              green  = (temp_buffer[index*3 + 1] >> 2), // 6 bits, change to 3 for 5 bits
  521.              blue   = (temp_buffer[index*3 + 0] >> 3); // 5 bits
  522.  
  523.        // build up 16 bit color word assume 5.6.5 format
  524.        USHORT color = _RGB16BIT565(red,green,blue);
  525.  
  526.        // write color to buffer
  527.        ((USHORT *)bitmap->buffer)[index] = color;
  528.  
  529.        } // end for index
  530.  
  531.    // finally write out the correct number of bits
  532.    bitmap->bitmapinfoheader.biBitCount=16;
  533.  
  534.    } // end if
  535.  
  536. #if 0
  537. // write the file info out 
  538. printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
  539.         filename,
  540.         bitmap->bitmapinfoheader.biSizeImage,
  541.         bitmap->bitmapinfoheader.biWidth,
  542.         bitmap->bitmapinfoheader.biHeight,
  543.         bitmap->bitmapinfoheader.biBitCount,
  544.         bitmap->bitmapinfoheader.biClrUsed,
  545.         bitmap->bitmapinfoheader.biClrImportant);
  546. #endif
  547.  
  548. // close the file
  549. _lclose(file_handle);
  550.  
  551. // flip the bitmap
  552. Flip_Bitmap(bitmap->buffer, 
  553.             bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8), 
  554.             bitmap->bitmapinfoheader.biHeight);
  555.  
  556. // return success
  557. return(1);
  558.  
  559. } // end Load_Bitmap_File
  560.  
  561. ///////////////////////////////////////////////////////////
  562.  
  563. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
  564. {
  565. // this function releases all memory associated with "bitmap"
  566. if (bitmap->buffer)
  567.    {
  568.    // release memory
  569.    free(bitmap->buffer);
  570.  
  571.    // reset pointer
  572.    bitmap->buffer = NULL;
  573.  
  574.    } // end if
  575.  
  576. // return success
  577. return(1);
  578.  
  579. } // end Unload_Bitmap_File
  580.  
  581. ///////////////////////////////////////////////////////////
  582.  
  583. int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
  584. {
  585. // this function is used to flip upside down .BMP images
  586.  
  587. UCHAR *buffer; // used to perform the image processing
  588. int index;     // looping index
  589.  
  590. // allocate the temporary buffer
  591. if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
  592.    return(0);
  593.  
  594. // copy image to work area
  595. memcpy(buffer,image,bytes_per_line*height);
  596.  
  597. // flip vertically
  598. for (index=0; index < height; index++)
  599.     memcpy(&image[((height-1) - index)*bytes_per_line],
  600.            &buffer[index*bytes_per_line], bytes_per_line);
  601.  
  602. // release the memory
  603. free(buffer);
  604.  
  605. // return success
  606. return(1);
  607.  
  608. } // end Flip_Bitmap
  609.