WINAPI - 그리기 모드
→ 화면에 무엇인가가 그려져 있는 상황에서 그 위에 다른 무엇인가를 출력하면 원래 그려져 있던 그림은 새로 그려지는 그림에 의해 지워진다.
→ 디스플레이 표면은 2차원적인 평면이므로 새로운 그림이 그려지면 그 아래에 있던 그림은 지워질 수 밖에 없다.
→ 화면에 그려진 그림은 비디오 램에 저장되는데 램이 동시에 두 개의 값을 기억할 수는 없으므로 타원이 있던 자리에 사각형을 그리면 타원은 덮여져 사라지는 것이 당연하다. 그러나 이런 당연한 현상도 그리기 모드를 변경하면 달라진다.
→ 그리기 모드란 도형이 그려질 때 원래 그려져 있던 그림과 새로 그려지는 그림과의 관계를 정의하는 것이다.
→ 2개의 원본 그림이 있을 때(흑백의 경우)
→ COPY는 새로 그려지는 그림이 기존 그림을 덮어 버리는 것이며 원래 그려져 있던 그림은 뒤의 그림에 덮여 사라져 버린다.
→ OR은 두 그림의 대응되는 비트를 OR 연산하여 새로운 값을 만들어 써넣는다. 즉, 두 비트가 모두 1이거나 둘중 하나라도 1이면 1이 쓰여지며 둘다 0일 경우에만 0을 써 넣는다.
→ AND 연산은 두 그림의 교집합 영역만 그려진다.
→ XOR 연산은 두 그림 중 겹쳐지는 부분이 반전되는 효과를 가져온다.
→ 흑백에서의 비트 연산은 0(검정색) 또는 1(흰색)만 있기 때문에 이렇게 이해하기 쉽지만 여러가지 색상을 사용하는 컬러 그래픽 환경에서의 비트 연산은 이보다 훨씬 더 복잡하다. 하지만 개념적으로는 대응되는 비트끼리 흑백에서와 같은 형태의 이진 연산을 하기 때문에 정밀하게 계산해 본다면 결과를 예측할 수도 있다.
- 그리기 모드의 종류
→ 윈도우즈에서 사용하는 디폴트 그리기 모드는 R2_COPYPEN 모드이다. 그래서 그려지는 그림이 기존 그림을 덮어버린다.
→ 그리기 모드를 변경하는 함수와 현재 설정된 그리기 모드를 구하는 함수는 다음과 같다.
int SetROP2(HDC hdc, int fnDrawMode);
int GetROP2(HDC hdc);
첫 번째 인수 hdc는 그리기 모드를 변경(또는 조사) 하고자 하는 DC의 핸들이며 SetROP2 함수의 두번째 인수에 다음과 같은 그리기 모드값을 넘겨준다.
- 그리기 모드
예제
BOOL bNowDraw = FALSE;
LRESULT OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
return 0;
}
LRESULT OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
return 0;
}
LRESULT OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
sx = LOWORD(lParam); // 각 좌표가 저장되고 이것을 다시 oldx에 삽입
sy = HIWORD(lParam); // 처음 마우스를 누른 위치
oldx = sx;
oldy = sy;
bNowDraw = TRUE; // 그림을 그린다.
return 0;
}
LRESULT OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
if(bNowDraw)
{
HDC hdc;
hdc = GetDC(hWnd);
SetROP2(hdc, R2_BLACK); // 항상 검정색이다.
MoveToEx(hdc, sx, sy, NULL);
LineTo(hdc, oldx, oldy); // oldx = sx, oldy = sy
oldx = LOWORD(lParam); // 새로운 값을 읽는다.(MouseMove된 현재 좌표)
oldy = HIWORD(lParam); // 지워져야 할 선의 끝 좌표
MoveToEx(hdc, sx, sy, NULL); // 마우스 클릭시 현재 좌표
LineTo(hdc, oldx, oldy); // 최종 이동된 좌표
ReleaseDC(hWnd, hdc);
}
return 0;
}
LRESULT OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
// 기본모드(R2_COPYPEN)
HDC hdc;
bNowDraw = FALSE;
hdc = GetDC(hWnd);
MoveToEx(hdc, sx, sy, NULL);
LineTo(hdc, oldx, oldy);
ReleaseDC(hWnd, hdc);
return 0;
}
→ 출력 결과
- 더블클릭으로 화면 클리어를 위한 소스 수정
WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
→ 더블클릭 메시지를 받기 위해 윈도우 클래스 스타일에 CS_DBLCLKS 플래그를 추가한다.
→ 보편적으로 많이 사용되는 더블클릭 메시지를 디폴트로 지원하지 않고 꼭 CS_DBLCLKS 플래그를 지정하도록 되어 있는 이유는 더블 클릭을 검출하는데는 그만큼 실행시간의 감소가 요구되며 어떤 프로그램은 더블클릭보다 WM_LBUTTONDOWN을 두 벋 받기를 원할 수 도 있기 때문이다.
LRESULT OnLbuttonDblclk(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
InvalidateRect(hWnd, NULL, TRUE); // 화면 클리어
return 0;
}
→ InvalidateRect 하수를 호출하여 작업영역 전체를 무효화 해버린다.
→ 위의 예제 코드에서 WM_PAINT 메시지를 처리하지 않으므로 무효영역이 생기면 DefWindowProc이 WM_PAINT 메시지를 처리하며 이 함수는 배경색으로 윈도를 지운다. 따라서 단순히 InvalidateRect 함수만 호출하면 화면이 지워진다.
'내장형 하드웨어 > WINAPI' 카테고리의 다른 글
WINAPI - 비트맵 출력, 메모리 DC (0) | 2011.09.15 |
---|---|
WINAPI - RopMode2 실습 (0) | 2011.09.09 |
WINAPI - 그래픽(색상) (0) | 2011.09.08 |
WINAPI - 그래픽(GDI 오브젝트) (0) | 2011.09.07 |
WINAPI - WM_COMMAND (0) | 2011.09.06 |