Tzu ng
Tzu ng

Reputation: 9234

Repaint window problems

#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 :)

Upvotes: 1

Views: 522

Answers (1)

dthorpe
dthorpe

Reputation: 36072

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.

Upvotes: 3

Related Questions