Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
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
Archives
Today
Total
관리 메뉴

codingfarm

6. 그래픽 - 그리기 모드 본문

Windows/윈도우즈 API

6. 그래픽 - 그리기 모드

scarecrow1992 2021. 5. 5. 18:35

1. 흑백에서의 그리기 모드

  • 그리기 모드 : 도형이 그려질 때 원래 그려져 있던 그림과 새로 그려지는 그림과의 관계를 정의하는것
    • ex : 예전 그림 위에 새그림 덮기, 적절히 혼합하기

가령 2개의 흑백 그림을 4가지 비트 연산으로 합처보면 아래와 같다.

 


2. 그리기 모드의 종류

  • 그리기 모드를 변경하는 함수와 현재 설정된 그리기 모드를 구하는 함수는 아래와 같다.
1
2
int SetROP2( HDC hdc,  int rop2 );
int GetROP2( HDC hdc);
cs

hdc : 그리기 모드를 변경(또는 조사) 하고자 하는 DC의 핸들

rop2 : 변경할 그리기 모드 값

그리기 모드 설명
R2_BLACK 항상 검정색이다.
R2_WHITE 항상 흰색이다.
R2_NOP 아무런 그리기도 하지 않는다.
R2_NOT 원래의 그림을 반전시킨다.
R2_COPYPEN 원래의 그림을 덮어버리고 새 그림을 그린다.
R2_NOTCOPYPEN 새 그림을 반전시켜 그린다.
R2_MERGEPEN OR연산으로 두 그림을 합친다.
R2_MASKPEN AND연산으로 겹치는 부분만 그린다.
R2_XORPEN XOR연산으로 겹치는 부분만 반전시킨다.

디폴트 : R2_COPYPEN (그려지는 그림이 기존 그림을 덮는다)

이외에 여러가지 그리기 모드가 있지만 주로 NOT연산자를 중간중간에 넣은 것들이며 거의 사용되지 않는다.

 

 


3. 그리기 모드

 

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <windows.h>
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("RopMode");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow) {
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
 
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
    while (GetMessage(&Message, NULL00)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
 
    }
    return Message.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
    static int sx, sy, oldx, oldy;
    static BOOL bNowDraw = FALSE;
    HDC hdc;
    switch (iMessage) {
    case WM_LBUTTONDOWN:
        sx = LOWORD(lParam);
        sy = HIWORD(lParam);
        oldx = sx;
        oldy = sy;
        bNowDraw = TRUE;
        return 0;
 
    case WM_MOUSEMOVE:
        if (bNowDraw) {
            hdc = GetDC(hWnd);
            SetROP2(hdc, R2_NOT);
            MoveToEx(hdc, sx, sy, NULL);
            LineTo(hdc, oldx, oldy);
            oldx = LOWORD(lParam);
            oldy = HIWORD(lParam);
            MoveToEx(hdc, sx, sy, NULL);
            LineTo(hdc, oldx, oldy);
            ReleaseDC(hWnd, hdc);
        }
        return 0;
 
    case WM_LBUTTONUP:
        bNowDraw = FALSE;
        hdc = GetDC(hWnd);
        MoveToEx(hdc, sx, sy, NULL);
        LineTo(hdc, oldx, oldy);
        ReleaseDC(hWnd, hdc);
        return 0;
 
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
 
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

마우스를 드래그하면 이전에 클릭했던 좌표와 놓았던 좌표사이에 선이 그려지며, 마우스를 움직이는동안 실시간으로 그려질 선이 미리 보인다.

여기서 주목할만한 부분은, 그려저야할 선을 미리 보여주는 부분인데 마우스를 움직일때마다 전송되는 메시지 WM_MOUSEMOVE내에서 이루어지는 작업이다.

SetROP2 함수를 호출하여 그리기 모드를 R2_NOT으로 변경하고, (sx, sy)-(oldx, oldy) 선에 대해 반전연산을 적용한다. 그러면 이전에 그렸던 선이 지워지게된다. 그리고 현 지점을 oldx, oldy에 대입하고 새로운 선을 그리면 된다.

만약 ROP모드의 R2_NOT을 통해 색반전이 아니라 흰색펜으로 지운 후 검정펜으로 다시 그리면 어떻게 될까?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
case WM_MOUSEMOVE:
    if (bNowDraw) {
        hdc = GetDC(hWnd);
        SelectObject(hdc, GetStockObject(WHITE_PEN));
        MoveToEx(hdc, sx, sy, NULL);
        LineTo(hdc, oldx, oldy);
        oldx = LOWORD(lParam);
        oldy = HIWORD(lParam);
        SelectObject(hdc, GetStockObject(BLACK_PEN));
        MoveToEx(hdc, sx, sy, NULL);
        LineTo(hdc, oldx, oldy);
        ReleaseDC(hWnd, hdc);
    }
    return 0;
cs

마우스를 따라 선을 이동시킬 때 이미 그려진 그림의 보존이 전혀 안되는것을 확인할 수 있다.

 

이 예제는 마우스의 이동에 의해 임시적인 선을 그려놓을뿐, 어디에 선을 그려놓았는지를 기억하지 않으므로, 덮어 씌워진 선을 복구할 수 없으며, WM_PAINT를 처리하지도 않는다. 그리기 정보를 저장하는 방법은 추후 학습할것이다.

 

 

 

 

Comments