// PhilVaz Animation Bitmap Demo // Displays and animates Megaman // Full Screen DirectDraw demo // Feb 14, 2004 // INCLUDES /////////////////////////////////////////////// #define WIN32_LEAN_AND_MEAN #include // include all the windows headers #include // include useful macros #include // for DirectDraw #include // for rand functions #include #include #include // include DirectDraw #include "ddutil.h" // for DDLoadBitmap #include "Megaman2.h" // DEFINES //////////////////////////////////////////////// // defines for windows #define WINDOW_CLASS_NAME "WINCLASS1" #define WINDOW_WIDTH 800 // size of game window #define WINDOW_HEIGHT 600 #define WINDOW_BPP 16 // bits per pixel #define GAME_SPEED 30 // speed of game (increase to go slower) #define MEG_SPEED 8 // x speed of Megaman animation #define MEG_DELAY 3 // delay between frames // MACROS ///////////////////////////////////////////////// #define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) #define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1) // GLOBALS //////////////////////////////////////////////// HWND game_window = NULL; // global game window handle HINSTANCE game_instance = NULL; // global game instance handle // DirectDraw variables LPDIRECTDRAW game_draw_main = NULL; // dd main object LPDIRECTDRAWSURFACE game_draw_surface = NULL; // dd primary surface LPDIRECTDRAWSURFACE game_draw_back = NULL; // dd back surface DDSURFACEDESC game_draw_desc; // dd surface description DDSCAPS game_draw_caps; // dd surface capabilities DDBLTFX back_fill; // to clear back buffer to black bool draw_ok; // for whether DirectDraw initialized ok int xbmp, ybmp; // BMP x and y position int xlimit, ylimit; // BMP limits for x and y int meg_pos; // animation position (0 to 9) int meg_countdown; // countdown between frames // for bitmap animations, bmp dd surfaces LPDIRECTDRAWSURFACE hbmp0 = NULL; LPDIRECTDRAWSURFACE hbmp1 = NULL; LPDIRECTDRAWSURFACE hbmp2 = NULL; LPDIRECTDRAWSURFACE hbmp3 = NULL; LPDIRECTDRAWSURFACE hbmp4 = NULL; LPDIRECTDRAWSURFACE hbmp5 = NULL; LPDIRECTDRAWSURFACE hbmp6 = NULL; LPDIRECTDRAWSURFACE hbmp7 = NULL; LPDIRECTDRAWSURFACE hbmp8 = NULL; LPDIRECTDRAWSURFACE hbmp9 = NULL; RECT bmp_rect = {0, 0, 53, 48}; // each bmp anim surface which is 53 x 48 // FUNCTIONS //////////////////////////////////////////////////////////// bool GameInit(); void GameMain(); void GameQuit(); // WINPROC ///////////////////////////////////////////////////////////// LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // this is the main message handler of the system HDC hdc; // handle to a device context PAINTSTRUCT ps; // used in WM_PAINT switch(msg) // what is the message { case WM_CREATE: { // do initialization stuff here return(0); // return success } break; case WM_PAINT: { hdc = BeginPaint(hwnd, &ps); // validate the window EndPaint(hwnd, &ps); return(0); // return success } break; case WM_DESTROY: { PostQuitMessage(0); // kill the application, sends a WM_QUIT message return(0); // return success } break; default:break; } // end switch // process default messages return (DefWindowProc(hwnd, msg, wparam, lparam)); } // end WinProc // WINMAIN //////////////////////////////////////////////// int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { WNDCLASSEX winclass; // this will hold the class we create HWND hwnd; // generic window handle MSG msg; // generic message // first fill in the window class structure winclass.cbSize = sizeof(WNDCLASSEX); winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; winclass.lpfnWndProc = WinProc; winclass.cbClsExtra = 0; winclass.cbWndExtra = 0; winclass.hInstance = hinstance; winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); winclass.hCursor = LoadCursor(NULL, IDC_ARROW); winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = WINDOW_CLASS_NAME; // save the game instance handle game_instance = hinstance; // register the window class if (!RegisterClassEx(&winclass)) return(0); // create the window if (!(hwnd = CreateWindowEx(NULL, // extended style WINDOW_CLASS_NAME, // class "Megaman2 Animation DD", // title WS_POPUP | WS_VISIBLE, // use POPUP for full screen 0,0, // initial game window x,y WINDOW_WIDTH, // initial game width WINDOW_HEIGHT, // initial game height NULL, // handle to parent NULL, // handle to menu hinstance, // instance of this application NULL))) // extra creation parms return(0); // save the game window handle game_window = hwnd; draw_ok = GameInit(); // game initialization function called here // enter main event loop using PeekMessage() to retrieve messages while(TRUE) { // get initial tick count to keep game speed constant DWORD start_tick = GetTickCount(); // is there a message in queue, if so get it if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { // test if this is a quit if (msg.message == WM_QUIT) break; // translate any accelerator keys TranslateMessage(&msg); // send the message to WinProc DispatchMessage(&msg); } // end if GameMain(); // game main processing function called here // check for key and send quit game if (KEYDOWN(VK_ESCAPE)) SendMessage (hwnd, WM_CLOSE, 0, 0); // wait until we hit correct game speed frame rate while ((GetTickCount() - start_tick) < GAME_SPEED); } // end while GameQuit(); // game quit function and clean up before exit called here return(msg.wParam); // return to Windows } // end WinMain // BEGIN GAME CODE //////////////////////////////////////// /////////////////////////////////////////////////////////// // // GAME INITIALIZATION // /////////////////////////////////////////////////////////// bool GameInit() { // set initial position of megaman Bitmap xbmp = 1; ybmp = 1; meg_pos = 0; // start at first animation position meg_countdown = MEG_DELAY; // set countdown between frames xlimit = WINDOW_WIDTH - 60; ylimit = WINDOW_HEIGHT - 60; // temporary change to full screen mode -- initialize DirectDraw // first create base IDirectDraw interface if (FAILED(DirectDrawCreate(NULL, &game_draw_main, NULL))) { MessageBox(game_window, "DirectDraw could not be initialized -- Create Error","DirectDraw Error",MB_OK); return FALSE; // error returned } // set cooperation to full screen if (FAILED(IDirectDraw_SetCooperativeLevel(game_draw_main, game_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN))) { MessageBox(game_window, "DirectDraw could not be initialized -- Cooperative Level Error","DirectDraw Error",MB_OK); return FALSE; // error returned } // set display mode to specific resolution if (FAILED(IDirectDraw_SetDisplayMode(game_draw_main, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP))) { MessageBox(game_window, "DirectDraw could not be initialized -- Screen Resolution Not Available","DirectDraw Error",MB_OK); return FALSE; // error returned } // create the primary surface with a back buffer ZeroMemory(&game_draw_desc, sizeof(game_draw_desc)); // clear out surface description game_draw_desc.dwSize = sizeof(game_draw_desc); game_draw_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; game_draw_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; game_draw_desc.dwBackBufferCount = 1; if (FAILED(IDirectDraw_CreateSurface(game_draw_main, &game_draw_desc, &game_draw_surface, NULL))) { MessageBox(game_window, "DirectDraw could not be initialized -- Primary Surface Error","DirectDraw Error",MB_OK); return FALSE; // error returned } // get the pointer to the back buffer game_draw_caps.dwCaps = DDSCAPS_BACKBUFFER; if (FAILED(IDirectDrawSurface_GetAttachedSurface(game_draw_surface, &game_draw_caps, &game_draw_back))) { MessageBox(game_window, "DirectDraw could not be initialized -- Back Surface Error","DirectDraw Error",MB_OK); return FALSE; // error returned } // load the BMP Megaman surface animations, checking for error if (((hbmp0 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG0), 0, 0)) == NULL) || ((hbmp1 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG1), 0, 0)) == NULL) || ((hbmp2 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG2), 0, 0)) == NULL) || ((hbmp3 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG3), 0, 0)) == NULL) || ((hbmp4 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG4), 0, 0)) == NULL) || ((hbmp5 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG5), 0, 0)) == NULL) || ((hbmp6 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG6), 0, 0)) == NULL) || ((hbmp7 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG7), 0, 0)) == NULL) || ((hbmp8 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG8), 0, 0)) == NULL) || ((hbmp9 = DDLoadBitmap(game_draw_main, MAKEINTRESOURCE(BMP_MEG9), 0, 0)) == NULL)) { // we had a problem loading one of the bitmaps from resource MessageBox(game_window, "A bitmap could not be initialized -- DDLoadBitmap Error","DirectDraw Error",MB_OK); return FALSE; // error returned } ZeroMemory(&back_fill,sizeof(back_fill)); // set up back fill for clear background back_fill.dwSize = sizeof(back_fill); back_fill.dwFillColor = RGB(0,0,0); MessageBox(game_window, "DirectDraw Initialized Okay -- Entering GameMain Loop","DirectDraw OK",MB_OK); return TRUE; // success } // END OF GameInit /////////////////////////////////////////////////////////// // // GAME MAIN LOOP AND PROCESSING // /////////////////////////////////////////////////////////// void GameMain() { // clear the back buffer to black if (draw_ok) IDirectDrawSurface_Blt(game_draw_back,NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT, &back_fill); // choose position of animation and display Megaman to back buffer if (meg_pos == 0 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp0,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 1 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp1,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 2 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp2,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 3 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp3,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 4 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp4,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 5 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp5,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 6 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp6,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 7 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp7,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 8 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp8,&bmp_rect,DDBLTFAST_WAIT); if (meg_pos == 9 && draw_ok) IDirectDrawSurface_BltFast(game_draw_back,xbmp,ybmp,hbmp9,&bmp_rect,DDBLTFAST_WAIT); meg_countdown--; if (meg_countdown == 0) { meg_pos++; if (meg_pos > 9) meg_pos = 0; xbmp = xbmp + MEG_SPEED; if (xbmp > xlimit) { xbmp = 1; ybmp = ybmp + 20; if (ybmp > ylimit) ybmp = 1; } meg_countdown = MEG_DELAY; } // copy/flip back buffer to front buffer if (draw_ok) IDirectDrawSurface_Flip(game_draw_surface,NULL,DDFLIP_WAIT); } // END OF GameMain /////////////////////////////////////////////////////////// // // GAME QUIT AND CLEAN UP // /////////////////////////////////////////////////////////// void GameQuit() { // release/delete the bmp dd surfaces if (hbmp0) IDirectDrawSurface_Release(hbmp0); if (hbmp1) IDirectDrawSurface_Release(hbmp1); if (hbmp2) IDirectDrawSurface_Release(hbmp2); if (hbmp3) IDirectDrawSurface_Release(hbmp3); if (hbmp4) IDirectDrawSurface_Release(hbmp4); if (hbmp5) IDirectDrawSurface_Release(hbmp5); if (hbmp6) IDirectDrawSurface_Release(hbmp6); if (hbmp7) IDirectDrawSurface_Release(hbmp7); if (hbmp8) IDirectDrawSurface_Release(hbmp8); if (hbmp9) IDirectDrawSurface_Release(hbmp9); // release/delete the primary and back dd surfaces if (game_draw_back) IDirectDrawSurface_Release(game_draw_back); if (game_draw_surface) IDirectDrawSurface_Release(game_draw_surface); // release/delete the IDirectDraw interface if (game_draw_main) { IDirectDraw_Release(game_draw_main); game_draw_main = NULL; } } // END OF GameQuit // END GAME CODE //////////////////////////////////////////