tags:

views:

45

answers:

1
#include "stdafx.h"

// Mario Headers
#include "GameMain.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Mario global variables =================
CGameMain* gGameMain;
HWND hWnd;
PAINTSTRUCT ps;
// ========================================



// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

// My unprocess function =====================================
void OnCreate(HWND hWnd)
{
}
void OnKeyUp(WPARAM wParam)
{
    switch (wParam) {
                case VK_LEFT:
                    gGameMain->KeyReleased(LEFT);
                    break;
                case VK_UP:
                    gGameMain->KeyReleased(UP);
                    break;
                case VK_RIGHT:
                    gGameMain->KeyReleased(RIGHT);
                    break;
                case VK_DOWN:
                    gGameMain->KeyReleased(DOWN);
                    break;
    }
}
void OnKeyDown(HWND hWnd,WPARAM wParam)
{
    switch (wParam) {
                case VK_LEFT:
                    gGameMain->KeyPressed(LEFT);
                    break;
                case VK_UP:
                    gGameMain->KeyPressed(UP);
                    break;
                case VK_RIGHT:
                    gGameMain->KeyPressed(RIGHT);
                    break;
                case VK_DOWN:
                    gGameMain->KeyPressed(DOWN);
                    break;
            }
}
void OnPaint(HWND hWnd)
{
   HDC hdc = BeginPaint(hWnd,&ps);

   RECT rect;
   GetClientRect(hWnd,&rect);

   HDC hdcDouble        = CreateCompatibleDC(hdc);
   HBITMAP hdcBitmap    = CreateCompatibleBitmap(hdc,rect.right,rect.bottom);
   HBITMAP bmOld        = (HBITMAP)SelectObject(hdcDouble, hdcBitmap);

   gGameMain->SetHDC(&hdcDouble);
   gGameMain->SendMessage(MESSAGE_PAINT);

   BitBlt(hdc,0,0,rect.right,rect.bottom,hdcDouble,0,0,SRCCOPY);
   SelectObject(hdcDouble,bmOld);
   DeleteDC(hdcDouble);
   DeleteObject(hdcBitmap);
   DeleteDC(hdc);
}

void OnDestroy() 
{
    gGameMain->isPlaying = false;
    EndPaint(hWnd,&ps);
}
// My unprocess function =====================================

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDIMARIO));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_GDIMARIO);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, 0, NULL, hInstance, NULL);
   if (!hWnd)
   {
      return FALSE;
   }

   // ---------------- Start gdiplus ------------------
   GdiplusStartup(&gdiToken,&gdiStartInput,NULL);
   // -------------------------------------------------

   // Init GameMain
   gGameMain = new CGameMain();

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    switch (message)
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;

        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_KEYDOWN: 
        OnKeyDown(hWnd,wParam);
        break;
    case WM_KEYUP: 
        OnKeyUp(wParam);    
        break;
    case WM_CREATE:
        OnCreate(hWnd);
        break;
    case WM_PAINT:          
        OnPaint(hWnd);
        break;
    case WM_DESTROY:
        OnDestroy();
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_GDIMARIO, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDIMARIO));

    // Main message loop:
    // GameLoop

    PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);

    while (gGameMain->isPlaying)
    {
        while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
            if (msg.message == WM_QUIT) 
                break;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        if (gGameMain->enterNextState) {
            gGameMain->SendMessage(MESSAGE_ENTER);
            gGameMain->enterNextState = false;
        }

        gGameMain->SendMessage(MESSAGE_UPDATE);
        InvalidateRect(hWnd,NULL,FALSE);
        /*if (gGameMain->exitCurrentState) {
            gGameMain->SendMessage(MESSAGE_EXIT);
            gGameMain->enterNextState = true;
            gGameMain->exitCurrentState = false;
        }*/
        ::Sleep(gGameMain->timer);
            // Do your game stuff here
    }

    GdiplusShutdown(gdiToken); // Shut down gdiplus token

    return (int) msg.wParam;
}

I use InvalidateRect(hWnd,NULL,FALSE); for repaint window, but the problem I met is when I repaint without any changes in Game struct .

First it paints my logo well, the second time ( just call InvalidateRect(hWnd,NULL,FALSE); without gGameMain->SendMessage(MESSAGE_ENTER); which is init some variables for painting . Thanks for reading this :)

+2  A: 

You're calling BeginPaint() in each wm_paint message, but there's no corresponding call to EndPaint() in the wm_paint message handler. Each BeginPaint() must be matched with a corresponding EndPaint(). Your EndPaint() call in OnDestroy is useless.

Also, don't delete the DC returned by BeginPaint(). It is borrowed, not owned.

Other notes: Try to avoid allocating a new bitmap on every wm_paint message. Allocate the bitmap when the window changes size, and hold onto it to be reused by multiple wm_paint passes.

Also note that you're not optimizing the draw to draw only what has been invalidated in the clip rect. You're drawing everything, blitting everything, and relying on GDI to only take the small portion of the bitmap that is actually in the clip rect. This will become a performance issue as the size of your window/bitmap increases and the number of objects/sprites you have running around on the screen increases. You should only draw things that are visible and within the cliprect.

dthorpe
how can I use one bitmap . I move hdc = BeginPaint(hWnd, in to OnPaint .every time program excute hdc = BeginPaint(hWnd, , hdc address change and I must readd hdcDouble, hdcBitmap . I'm new to this, thanks :)
nXqd
You can create your hdcDouble ahead of time as well - it doesn't have to be constructed off the hdc returned by BeginPaint. GetDC(0) will return a dc for the screen device which will be the same as CreateCompatibleDC. You will need to discard the DC if the user changes the screen settings, so you will need to listen to the appropriate messages informing you of that.Yes, you do need to use hdc=BeginPaint(...) in each OnPaint call, but the hdcDouble does not have to be constructed from that hdc. The BitBlt copies pixels from the bitmap hdc to the screen hdc.
dthorpe