| 일 | 월 | 화 | 수 | 목 | 금 | 토 | 
|---|---|---|---|---|---|---|
| 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 | 
													Tags
													
											
												
												- DP
 - Stored Procedure
 - SQL
 - Brute Force
 - Dijkstra
 - binary search
 - Trie
 - two pointer
 - 다익스트라
 - Two Points
 - 스토어드 프로시저
 - String
 - union find
 - 이진탐색
 - MYSQL
 - Hash
 - 그래프
 
													Archives
													
											
												
												- Today
 
- Total
 
codingfarm
6. 그래픽 - 그리기 모드 본문
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, NULL, 0, 0)) { 
        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를 처리하지도 않는다. 그리기 정보를 저장하는 방법은 추후 학습할것이다.
'Windows > 윈도우즈 API' 카테고리의 다른 글
| 6. 그래픽 - 폰트 (0) | 2021.12.25 | 
|---|---|
| 6. 그래픽 - 비트맵 (0) | 2021.05.05 | 
| 6. 그래픽 - DC의 정보 수정 (0) | 2021.05.04 | 
| 5. 리소스 - 문자열 테이블(string table) (0) | 2021.05.01 | 
| 5. 리소스 - 액셀러레이터(Accelerator) (0) | 2021.05.01 | 
			  Comments