< PAINTSTRUCT >

 

WM_PAINT의 선두에서는 항상 BeginPaint 함수를 호출한다. 이 함수는 윈도우 핸들과 PAINTSTRUCT 구조체의 포인터를

인수로 취하는데 PAINTSTRUCT 구조체를 잘 활용하면 그리기 속도를 높일 수 있다.

 

1
2
3
4
5
6
7
8
typedef struct tagPAINTSTRUCT {
    HDC         hdc;
    BOOL        fErase;
    RECT        rcPaint;
    BOOL        fRestore;
    BOOL        fIncUpdate;
    BYTE        rgbReserved[32];
} PAINTSTRUCT;
cs

 

이 구조체는 BeginPaint 함수에 의해 채워지며 사용자는 필요에 따라 이 구조체의 정보를 사용하면 된다.

 

HDC hdc : 그리기에 사용될 DC의 핸들값이며 BeginPaint가 리턴하는 값과 동일하다.

BOOL fErase : 배경을 지울 것인가 아닌가를 지정하는 멤버이지만 통산 FALSE로 사용한다.

RECT rcPaint : 그리기를 해야 할 사각영역을 가진다. 이 영역은 클리핑 영역을 포함하는 최소한의 사각영역이다.

 

하기에서 rcPaint를 이용하여 그리기 속도를 줄여볼 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void Swap(int &a, int &b)
{
    int t;
    t=a;
    a=b;
    b=t;
}
 
COLORREF CalcColor()
{
    int r,g,b,i;
    r = rand()%255;
    g = rand()%255;
    b = rand()%255;
    for (i=0; i<10++i) {
        Swap(r,g);
    }
 
    return RGB(r,g,b);
}
 
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rt;
    int x,y;
 
    switch(iMessage) {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &rt);
        for (y=0; y<rt.bottom; ++y) {
            for (x=0; x<rt.right; ++x) {
                SetPixel(hdc, x, y, CalcColor());
            }
        }
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
 
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

 

상기 코드는 화면에 여러 색상으로 점을 차례로 찍는 프로그램이다. 어느정도 Delay를 위해 무의미한 Swap 기능이 들어가 있다.

이러한 프로그램의 문제점은 화면의 일부분이 무효화되어 WM_PAINT가 재 호출될 때 전체 화면을 처음부터 다시 그린다는 것이다.

운영체제에 의해 무효화되지 않은 부분은 SetPixel이 바로 리턴되므로 다시 그려지는 것은 아니지만 어찌되었든 전체 루프를 돌면서

색상을 계산하는 함수가 호출되기 때문에 시간이 오래 소요된다.

운영체제는 다시 그릴 필요가 없다는 것은 알지만 연산 자체가 불필요하다는 것은 판단할 수 없기 때문이다.

 

이런 경우 하기와 같이 PAINTSTRUCT의 rtPaint를 이용하면 루프 자체를 무효화 영역만 반복하기 때문에 속도 차이가 기존에 비해

상당히 빠르다.

 

1
2
3
4
5
6
7
8
9
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        for (y=ps.rcPaint.top; y<ps.rcPaint.bottom; ++y) {
            for (x=ps.rcPaint.left; x<ps.rcPaint.right; ++x) {
                SetPixel(hdc,x,y,CalcColor());
            }
        }
        EndPaint(hWnd, &ps);
        return 0;
cs

 

 

< WM_PAINT 호출 >

 

하기 코드는 WM_PAINT가 얼마나 자주 호출되는지 눈으로 확인하는 용도의 프로그램 코드이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    HBRUSH hBrush;
    static int count = 0;
    TCHAR str[128];
 
    switch(iMessage) {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        hBrush = CreateSolidBrush(RGB(rand()%256, rand()%256, rand()%256));
        FillRect(hdc, &ps.rcPaint, hBrush);
        DeleteObject(hBrush);
        wsprintf(str,TEXT("무효화 회수 = %d"), count++);
        SetWindowText(hWnd, str);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
 
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

+ Recent posts