300 likes | 624 Views
4. 기본적인 그리기. 1. GDI 철학. 비디오 출력과 프린터에 그래픽을 책임지고 있는 Windows 의 하위 시스템은 그래픽 디바이스 인터페이스 (GDI) 이다 . Windows 98 과 Microsoft NT 에서의 그래픽은 주로 동적 링크 라이브러리 GDI32.DLL 로부터 얻어진 함수들에 의해 처리된다 . GDI 의 목적 중의 하나는 장치에 구애 받지 않고 그래픽을 지원하는 것이다 . Windows 는 디폴트로 픽셀을 기반으로 하는 좌표계를 사용
E N D
4. 기본적인 그리기
1. GDI 철학 • 비디오 출력과 프린터에 그래픽을 책임지고 있는 Windows의 하위 시스템은 그래픽 디바이스 인터페이스(GDI)이다. • Windows 98과 Microsoft NT에서의 그래픽은 주로 동적 링크 라이브러리 GDI32.DLL로부터 얻어진 함수들에 의해 처리된다. • GDI의 목적 중의 하나는 장치에 구애 받지 않고 그래픽을 지원하는 것이다. • Windows는 디폴트로 픽셀을 기반으로 하는 좌표계를 사용 • 가로축과 세로축이 0에서 32,767까지 가능한 가상 좌표계를 사용
2. GDI함수 호출 • 장치 컨텍스트를 얻고 해제하는 함수들 • BeginPaint • EndPaint • GetDC • ReleaseDC • 장치 컨텍스트에 대한 정보를 획득하는 함수들 • GetTextMetrics • 그리는 함수들 • TextOut • 장치 컨텍스트의 속성을 설정하고 얻어내는 함수들 • SetTextColor • SetTextAlign • GDI개체를 다루는 함수들 • CreatePen • CreatePenIndirect
3. 장치 컨텍스트 핸들 얻기 hdc = Beginpaint(hwnd,&ps) EndPaint(hwnd,&ps); • WM_PAINT • WM_PAINT가 아닌 다른 메시지에서 hdc = GetDC(hwnd) ReleaseDC(hwnd,hdc); • 전체 윈도우에 대한 hDC얻기 hdc = GetWindowDC(hwnd) ReleaseDC(hwnd,hdc); • 화면전체에 출력을 하려면 hdc = CreateDC (pszDriver,pszDevice,pszOutput,pData); [다른 명령들] DeleteDC(hdc);
3. 장치 컨텍스트 핸들 얻기 hdc=CreateDC(“DISPLAY”,NULL,NULL,NULL); Ex) hdc=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL); TextOut(hdc,0,0,TEXT("여기는 처음"),12); DeleteDC(hdc); hdcMem=CreateCompatibleDC(hdc); [다른 명령들] DeleteDC(hdc);
4. 점과 선 그리기 • 픽셀 정하기 • SetPixcel(hdc,x,y,crColor); • crColor는 COLORREF형식으로 색상을 지정 • crColor = GetPixcel(hdc,x,y) • 지정된 좌표의 픽셀 색상을 반환한다. • 직선 • LineTo : 직선을 그린다. • Polyline와 PolylineTo : 연결된 직선을 그린다. • PolyPolyline : 여러 개의 Polyline을 그린다. • Arc : 호를 그린다. • PolyBezier와 PolyBezierTo : 베지어 스플라인을 그린다. • Rectangle : 사각형을 그린다. • Ellipse : 타원을 그린다. • RoundRect : 모서리가 둥근 사각형을 그린다. • Pie : 파이모양을 그린다. • Chord : 현 형태의 다원 부분을 그린다.
5. 직선 그리기 • 직선을 그리려면 • MoveToEx(hdc,xBeg,yBeg,NULL); • MoveToEx는 펜의 위치는 옮긴다. • MoveToEx의 마지막 인자는 POINT 구조체에 대한 포인터이다. • 함수로부터 반환 시에 POINT구조체의 x,y 필드는 이전의 위치를 체운다. • Windows 98에서의 좌표값이 32bit이지만 오직 하위 16비트만 사용한다. • Windows NT는 32비트를 모두 사용한다. • LineTo(hdc,xEnd,yEnd); • LineTo함수는 현재의 위치로 부터 xEnd,yEnd까지 선을 그린다. • GetCurrentPositionEx(hdc,&pt); • 현재의 위치를 알아 내려면 • pt는 POINT구조체이다.
5. 직선 그리기 GetClientRect(hwnd,&rect); for (x = 0; x < rect.right; x+=100) { MoveToEx (hdc,x,0,NULL); LineTo(hdc,x,rect.bottom); } for (y = 0; y < rect.bottom; y+=100) { MoveToEx (hdc,0,y,NULL); LineTo(hdc,rect.right,y); } POINT apt[5] = {100,100,200,100,200,200,100,200,100,100}; MoveToEx(hdc,apt[0].x,apt[0].y); for (I = 1; I < 5;I++) { LineTo(hdc,apt[I].x,apt[I].y); } • Polyline(hdc,apt,5); • MoveToEx(hdc,apt[0].x,apt[0].y,NULL); • PolylineTo(hdc,apt+1,4);
5. 경계 상자 함수 • Rectangle(hdc,xLeft,yTop,xRight,yBottom); • 채워진 사각형을 그린다. • Ellipse(hdc,xLeft,yTop,xRight,yBottom); • 채워진 타원을 그린다. • RoundRect(hdc,xLeft,yTop,xRight,yBottom,xCornerEllipse,yCornerEllipse); • 모서리가 둥근 채워진 사각형을 그린다. • Arc(hdc,xLeft,yTop,xRight,yBottom,xStart,yStart,xEnd,yEnd); • 호를 그린다. • Chord(hdc,xLeft,yTop,xRight,yBottom,xStart,yStart,xEnd,yEnd); • 현을 그린다. • Pie(hdc,xLeft,yTop,xRight,yBottom,xStart,yStart,xEnd,yEnd); • 파이 모양의 도형을 그린다.
5. 경계 상자 함수 case WM_LBUTTONDOWN: hdc=GetDC(hwnd); LineTo(hdc,LOWORD(lParam),HIWORD(lParam)); m_OldPT.x = LOWORD(lParam); m_OldPT.y = HIWORD(lParam); ReleaseDC(hwnd,hdc); return 0; case WM_MOUSEMOVE: if (wParam & MK_LBUTTON) { hdc=GetDC(hwnd); SelectObject(hdc,GetStockObject(WHITE_PEN)); LineTo(hdc,m_OldPT.x,m_OldPT.y); MoveToEx(hdc,0,0,NULL); SelectObject(hdc,GetStockObject(BLACK_PEN)); LineTo(hdc,LOWORD(lParam),HIWORD(lParam)); m_OldPT.x = LOWORD(lParam); m_OldPT.y = HIWORD(lParam); ReleaseDC(hwnd,hdc); } return 0;
6. 스톡 펜 사용하기 • Windows가 기본적으로 제공하는 스톡 펜 • BLACK_PEN,WHITE_PEN,NULL_PEN • 디폴트 장치 컨텍스트 펜 • BLACK_PEN • PEN 정의 • HPEN hPen; • 윈도우 스톡에 있는 Pen가져오기 • hPen = GetStockObject(WHITE_PEN); • 장치 컨텍스트에 지정하려면 • SelectObject(hdc,hPen) • SelectObject(hdc,GetStockObject(WHITE_PEN));
7. 펜의 생성과 선택, 그리고 삭제 • 펜의 사용 • 펜은 CreatePen과 CreatePenIndirect를 이용하여 펜을 생성한다. • SelectObject을 이용하여 만들어진 이 펜을 사용할 수 있다. • 새로운 펜으로 그린다. • 오직 하나의 펜만이 장치 컨텍스트에서 선택될 수 있다. • SelectObject를 이용하여 이전의 펜으로 되돌린다. • DeleteObject를 이용하여 만들어진 펜을 삭제한다 • GDI객체 사용 규칙 • 마지막에 항상 생성한 GDI객체를 삭제해야 한다. • 유효한 장치 컨텍스트에서 선택되어 있는 GDI객체를 삭제하지 않는다. • 스톡 객체는 삭제하지 않는다. • hPen = CreatePen(iPenStyle,iWidth,crColor); • iPenStyle :PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT,PS_DASHDOTDOT,PS_NULL,PS_INSIDEFRAMER • iWidth : 펜의 두께 , crColor : COLORREF의 펜의 Color • CreatePenIndirect • 먼저 LOGPEN형식의 구조체를 정의한다. • LOGPEN logpen; • ( lopnStyle => pen의 스타일, lopnWidht => pen의 두께, • lopnColor => pen의 칼라 ) • hPen = CreatePenIndirect(&logpen);
7. 펜의 생성과 선택, 그리고 삭제 HPEN hPen1,hPen2,hPen3; hPen1 = CreatePen(PS_SOLID,1,0); hPen2 = CreatePen(PS_SOLID,1,RGB(255,0,0)); hPen3 = CreatePen (PS_DOT,0,0); SelectObject(hdc,hPen1); • [선그리기] SelectObject(hdc,hPen2); • [선그리기] SelectObject(hdc,hPen3); • [선그리기] DeleteObject (hPen1); DeleteObject (hPen2); DeleteObject (hPen3); -프로그램에서 3개의 Pen을 사용하면
8. 틈새 채우기 • 도트 펜과 대쉬 펜 사이의 틈새는 어떻게 처리할까? • 틈새의 색은 Windows디폴트 배경색인 흰색으로 틈을 칠한다. (OPAQUE) • 틈새의 색을 바꾸려면 • SetBkColor(hdc,crColor); • 틈새를 칠하지 않게 할 수도 있다 • 배경모드를 TRANSPARENT로 지정한다. • SetBkMode(hdc,TRANSPARENT);
9. 그리기모드 • 디스플레이에 그려진 선의 외형은 장치 컨텍스트에서 정의된 그리기 모드에 영향을 받는다. • 펜을 사용하여 선을 그릴 때 실제로는 펜의 픽셀과 목표가 되는 디스플레이 픽셀의 bitwise 2진 연산을 수행한다. • 픽셀을 가지고 2진 연산을 수행하는 것을 “래스터 연산” 또는 “ROP”라고 한다. • R2_COPYPEN • 디폴트 그리기 모드 • 단순히 펜의 픽셀을 목표에 복사하는 것을 나타낸다. • R2_BLACK • 항상 검은 선을 그린다. • R2_NOTMERGEPEN • 펜과 배경이 검정색일 때 선은 흰색으로 그린다. • R2_NOT • 펜의 색상과는 상관없이 항상 목표 색상을 반전하여 선의 색을 결정한다. • 그리기 모드 지정 • SetROP2(hdc,iDrawMode); • 그리기 모드를 읽어 온다. • iDrawMode = GetROP2(hdc)
9. 그리기모드 AND XOR COPY OR 원본 그림
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; static int xPos, yPos, xOldPos, yOldPos; static bool bNowDraw = FALSE; switch (message) { case WM_LBUTTONDOWN: xPos = LOWORD(lParam); yPos = HIWORD(lParam); xOldPos = xPos; yOldPos = yPos; bNowDraw = true; return 0; case WM_LBUTTONUP: bNowDraw = false; hdc = GetDC(hwnd); MoveToEx(hdc,xPos,yPos,NULL); LineTo(hdc,xOldPos,yOldPos); ReleaseDC(hwnd,hdc); return 0; case WM_MOUSEMOVE: if (bNowDraw) { hdc = GetDC(hwnd); SetROP2(hdc,R2_NOT); MoveToEx(hdc,xPos,yPos,NULL); LineTo(hdc,xOldPos,yOldPos); int xNewPos = LOWORD(lParam); int yNewPos = HIWORD(lParam); MoveToEx(hdc,xPos,yPos,NULL); LineTo(hdc,xNewPos,yNewPos); xOldPos = xNewPos; yOldPos = yNewPos; ReleaseDC(hwnd,hdc); } return 0; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }
10. 채워진 영역 그리기 • Rectangle : 직각 모서리를 가지는 사각형 • Ellipse : 타원 • RoundRect :둥근 모서리를 가지는 사각형 • Chord : 종료점은 현에 의해 연결되는 타원 외곽의 호 • Pie : 타원 외곽선으로 정의되는 Pie • Polygon : 다변체 그림 • PolyPolygon : 다중 다변체 그림 • 현재 장치 컨텍스트에서 선택된 브러쉬로 채워진다. • 디폴트 : WHITE_BURSH • 6개의 스톡 브러쉬 : • WHITE_BRUSH , LTGRAY_BRUSH,GRAY_BRUSH, DKGRAY_BRUSH,BLACK_BRUSH,NULL_BRUSH
10. 채워진 영역 그리기 • HBRUSH hBrush,hOldBrush; • hBrush = GetStockObject(GRAY_BRUSH); • hOldBrush = SelectObject(hdc,hBrush); • [도형 그리기] • SelectObject(hdc, hOldBrush); • 경계가 없는 그림을 그리려면 • SelectObject(hdc,GetStockObject(NULL_PEN)); • 내부를 채우지 않고 그림의 외곽선 그리려면 • SelectObject(hdc,GetStockObject(NULL_BRUSH));
11. 내부를 브러쉬로 채우기 • 단색의 브러쉬를 만든다. • hBrush = CreateSolidBrush(crColor); • 수평,수직,혹은 대각선으로 구성되는 hatch표시를 이용하여 브러쉬를 생성 • hBrush = CreateHatchBrush(iHatchStyle,crColor); • PS_HORIZONTAL,PS_BDIAGONAL,PS_VERTICAL,PS_CROSS, • PS_FDIAGONAL,PS_DIAGCROSS
11. 내부를 브러쉬로 채우기 • Bitmap으로 도형을 채우려면 • hBitMap = LoadBitmap(hinst,MAKEINTRESOURCE(IDB_BITMAP1)); • hNewBrush = CreatePatternBrush(hBitMap); • FillRect(hdc, &rect, hBrush) • 지정된 브러쉬로 사각형을 채운다. • FrameRect(hdc, &rect, hBrush); • 사각형의 Frame을 그리지만 채우지는 않는다. • InvertRect(hdc,&rect); • 사각형 내의 모든 픽셀들을 반전하여 1은 0으로 0은 1로 만든다. • Rect구조체를 채운다. • SetRect (&rect,xLeft,yTop,xRight,yBottom); • 사각형 내에 포인트가 있는지를 결정한다. • bInRect = PtInRect(&rect,point);
12. 랜덤 사각형 • PeekMessage(&msg,NULL,0,0,PM_REMOVE); • 처음 4개의 매개변수는 GetMessage와 동일하다. • PM_REMOVE는 메시지를 읽은 후 제거한다. • PM_NOREMOVE는 메시지를 읽은 후 제거하지 않는다. • PeekMessage()의 Return 값 • 메시지를 읽었는지 읽지 못 했는지를 Return한다. /*------------------------------------------ RANDRECT.C -- Displays Random Rectangles (c) Charles Petzold, 1998 ------------------------------------------*/ #include <windows.h> #include <stdlib.h> // for the rand function LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; void DrawRectangle (HWND) ; int cxClient, cyClient ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("RandRect") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"),szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("Random Rectangles"),WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (TRUE) { if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break ; TranslateMessage (&msg) ; DispatchMessage (&msg) ; } else DrawRectangle (hwnd) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; }
12. 랜덤 사각형 • WM_SIZE 메시지 • 윈도우의 크기가 변경될 때 보내진다. • lParam에는 하위 워드에 윈도우의 폭, 상위 워드에 윈도우의 높이 • wParam에는 메시지가 발생한 이유를 나타내는 플래그 전달
13. 영역을 생성하고 색칠하기 • 영역은 사각형,다각형,타원의 조합으로 이루어진다. • 영역을 사용하여 그리거나 잘라내기를 할 수 있다. • 영역도 GDI객체이다. • 생성된 모든 영역은 DeleteObject을 통하여 삭제한다. • 영역에 대한 Handle은 HRGN을 반환한다. • 영역 생성 • hRgn = CreateRectRgn(xLeft,yTop,xRight,yBottom); • hRgn = CreateRectRgnIndirect(&rect); • hRgn = CreateEllipticRgn(xLeft, yTop,xRight,yBottom); • hRgn = CreateEllipticRgnIndirect(&rect); • CreateRoundRectRgn은 둥근 모양의 사각형 영역을 생성 • 다각형영역을 생성 • hRgn=CreatePolygonRgn(&point,iCount,iPolyFillMode); • point : POINT형 구조체 • iCount : 포인트의 개수 • iPolyFillMode : ALTERNATE또는 WINDING
13. 영역을 생성하고 색칠하기 • iRgnType = CombineRgn(hDestRgn,hSrcRgn1,hSrcRgn2,iCombine); • 2개의 원본 영역을 조합하여 목표 핸들이 조합된 영역을 나타내도록 한다. • iCombine 매개변수는 hSrcRgn1과 hSrcRgn2의 영역이 조합되는 방식이다. • RGN_AND 두개의 소스 영역의 교차영역 • RGN_OR 두개의 소스 영역의 전영역 • RGN_XOR 두개의 소스 영역에서 교차 부분을 뺀 영역 • RGN_DIFF hSrcRgn2에 속하지 않는 hSrcRgn1영역 • RGN_COPY hSrcRgn1전부 (hSrcRgn2무시) • Return값 • 빈 영역이면 NULLREGION; • 간단한 사각형,원,다각형이면 SIMPLEREGION • 사각형,타원,혹은 다각형들의 조합이면COMPLEXREGION • ERROR면 ERROR
14. 맵핑모드 • 맵핑모드란 주어진 좌표가 화면상의 실제 어디에 해당하는지를 결정하는 방법을 말한다. • 윈도우에서 사용하는 좌표는 논리 좌표와 물리 좌표 두 가지가 있다. • 논리 좌표 : 윈도우 내부에서 사용되는 좌표를 말한다. • TextOut,DrawText등에서 사용하는 좌표를 말한다. • DC핸들을 인수로 받아들이는 모든 함수는 논리 좌표이다. • 물리 좌표 : 실제 화면에 출력되는 좌표이며 픽셀 단위를 사용한다. • 물리좌표 100,100은 그 위치가 정해져 있다. • 논리 좌표의 (20,20)은 물리 좌표의 (20,20)일 수도 있고 다른 곳 일 수도 있다. • 윈도우가 사용하는 디폴트 맵핑모드는 물리좌표와 논리좌표가 일치한다. • int SetMapMode(HDC hdc, int iMapMode); • int GetMapMode(HDC hdc);
15. 윈도우와 뷰 포트 • 윈도우는 논리 좌표가 사용되는 표면을 말한다. • 그래픽 출력 함수는 윈도우에 그래픽을 출력한다. • 뷰 포트는 물리 좌표가 사용되는 영역을 말한다. • 실제로 사용자의 눈에 보이는 좌표 영역이다. • SetViewportOrgEx(HDC hdc, int X, int Y, LPPOINT lpPoint); • 윈도우의 원점을 이동시킨다. • SetWindowOrgEx(HDC hdc, int X, int Y, LPPOINT lpPoint); • 뷰 포트의 원점을 이동시킨다.
16. 가변 비율 • 윈도우 확장을 조정할 수 있는 맵핑모드에는 MM_ISOTROPIC과 MM_ANISOTROPIC 두 가지가 있다. • BOOL SetWindowExtEx(HDC hdc, int nXExtent, int nYExtent, LPSIZE lpSize); • 논리적인 좌표 범위를 지정한다. • BOOL SetViewportExtEx(HDC hdc, int nXExtent, int nYExtent, LPSIZE lpSize); • 물리적인 좌표 범위를 지정한다.