2011-01-14 13 views
2

Wie würdest du in regelmäßigen Abständen etwas auf ein Fenster malen?Wie würde ich ein Fenster mit dem Win32 Api animieren?

Ich habe mit dem diesem (gestrippt ziemlich viel für Klarheit)

#include <windows.h> 

void DrawOntoDC (HDC dc) { 

    pen = CreatePen(...) 
    penOld = SelectObject(dc, pen) 

    ..... Here is the actual drawing, that 
    ..... should be regurarly called, since 
    ..... the drawn picture changes as time 
    ..... progresses 

    SelectObject(dc, pen_old); 

    DeleteObject(pen); 
} 



LRESULT CALLBACK WindowProc(....) { 
    switch(Msg) { 

    case WM_PAINT: { 
     PAINTSTRUCT ps; 
      dc = BeginPaint(hWnd, &ps); 

     ..... A Memory DC is created 
     ..... In order to prevent flickering. 

     HBITMAP PersistenceBitmap; 
     PersistenceBitmap = CreateCompatibleBitmap(dc, windowHeight, windowHeight); 

     HDC  dcMemory = CreateCompatibleDC(dc); 
     HBITMAP oldBmp = (HBITMAP) SelectObject(dcMemory, PersistenceBitmap); 

     DrawOntoDC(dcMemory); 

     ..... "copying" the memory dc in one go unto dhe window dc: 

     BitBlt (dc, 
        0, 0, windowWidth, windowHeight, 
        dcMemory, 
        0, 0, 
        SRCCOPY 
       ); 

     ..... destroy the allocated bitmap and memory DC 
     ..... I have the feeling that this could be implemented 
     ..... better, i.e. without allocating and destroying the memroy dc 
     ..... and bitmap with each WM_PAINT. 

     SelectObject(dcMemory, oldBmp); 
     DeleteDC(dcMemory); 
     DeleteObject(PersistenceBitmap); 

    EndPaint (hWnd, &ps); 
     return 0; 
    } 
    default: 
     return DefWindowProc(hWnd, Msg, wParam, lParam); 
    } 
} 


DWORD WINAPI Timer(LPVOID p) { 

    ..... The 'thread' that makes sure that the window 
    ..... is regularly painted. 

    HWND hWnd = (HWND) *((HWND*) p); 

    while (1) { 
    Sleep(1000/framesPerSecond); 
    InvalidateRect(hWnd, 0, TRUE); 
    } 
} 


int APIENTRY WinMain(...) { 

    WNDCLASSEX windowClass; 
     windowClass.lpfnWndProc   = WindowProc; 
     windowClass.lpszClassName  = className; 
     .... 

    RegisterClassEx(&windowClass); 

    HWND hwnd = CreateWindowEx(
       .... 
       className, 
       ....); 


    ShowWindow(hwnd, SW_SHOW); 
    UpdateWindow(hwnd); 

    DWORD threadId; 
    HANDLE hTimer = CreateThread(
     0, 0, 
     Timer, 
    (LPVOID) &hwnd, 
    0, &threadId); 

    while(GetMessage(&Msg, NULL, 0, 0)) { 
     .... 
    } 

    return Msg.wParam; 
} 

Ich denke, es gibt eine Menge, die verbessert werden könnten und ich würde schätzt jeden Zeiger auf Dinge, die ich übersehen haben kommen.

Antwort

4

tun diese Art der Sache mit einem Arbeitsthread ist nicht optimal. Da der optimale Codepfad für die Malerei ist immer über eine WM_PAINT, die zwei Möglichkeiten, läßt dies zu tun:

  1. einfach einen Timer auf dem GUI-Thread erstellen, WM_TIMER-Nachrichten an eine TimerProc posten, oder das Fenster direkt, und rufen Sie den OnTick() Teil Ihrer Engine auf. Wenn sich Sprites bewegen, machen sie ihren Bereich ungültig, indem sie InvalidateRect() verwenden und Windows folgt, indem sie automatisch einen WM_PAINT posten. Dies hat den Vorteil einer sehr geringen CPU-Auslastung, wenn das Spiel relativ leer ist.

  2. Die meisten Spiele wollen strengeres Timing, die mit einem niedrigen Priorität WM_TIMER basierend Timer erreicht werden können. In diesem Fall implementieren Sie eine Spielschleife etwas wie folgt aus:

Nachricht Loop:

while(stillRunning) 
{ 
    DWORD ret = MsgWaitForMultipleObjects(0,NULL,FALSE,frameIntervalMs,QS_ALLEVENTS); 
    if(ret == WAIT_OBJECT_0){ 
    while(PeekMessage(&msg,0,0,0,PM_REMOVE)){ 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
    if(TickGame()) // if TickGame indicates that enough time passed for stuff to change 
    RedrawWindow(hwndGame,...); // Dispatch a WM_PAINT immediately. 
} 

Die Gefahr bei dieser Art von Nachrichtenschleife ist, wenn die ... Anwendung in jeder Art geht des modalen Status: - Der Benutzer beginnt das Fenster zu ziehen/ein modales Dialogfeld erscheint, dann werden Nachrichten von der modalen Schleife gepumpt, so dass die Animation stoppt. Als Ergebnis benötigen Sie einen Fallback-Timer, wenn Sie eine Hochleistungs-Nachrichtenschleife mit modalen Operationen kombinieren müssen.


WRT Ihre WM_PAINT Implementierung - seine in der Regel besser zu (re) erstellen Sie Ihre Backbuffer in Antwortnachrichten an WM_SIZE. Auf diese Weise hat es immer die richtige Größe, und Sie erleiden nicht die ziemlich großen Kosten, einen großen Speicherpuffer viele Male pro Sekunde neu zu erstellen.

Verwandte Themen