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

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