첫 번째 Direct2D 프로그래밍~
지난 시간을 통해서 Direct2D의 필요성에 대해서, 제가 열심히(?) 언급해 드렸습니다.^^
이번 시간에는 Direct2D 프로그래밍의 세계에 대해서 들어가기 전에,
간단하게 프로그램을 작성해 볼 것입니다.
부끄럽지만, 저는 박식한 이론 내용 없이도 많은 프로그래밍 작업을 했었습니다.^^
그 만큼, 직접 프로그램을 작성하면 쉽게 이해할 수 있는 부분이 많이 있을 것입니다.
기본적으로 Direct2D는 2차원 그래픽을 만들기 위한 API입니다.
기존의 GDI를 이용한 프로그램의 일부분을 Direct2D로 대체를 하는 것만으로도 성능을 향상시킬 수 있습니다.
기본적으로 Direct2D로 작업하는 순서는 다음과 같습니다.
-
Direct2D 팩토리를 생성한다.
-
팩토리에서 렌더타겟을 생성한다.
-
렌더타겟에서 리소스들을 생성한다.
-
생성 되어진 리소스들을 이용해서 그리기 작업을 수행한다.
Direct2D의 모든 작업은 위의 순서를 따릅니다.
이제 이들 순서를 어떻게 API로 표현하는지 살펴보겠습니다.
화면 작업을 위해 준비하기
첫 번째로 작성해볼 프로그램은 특정 색상으로 화면을 채우는 작업을 하는 것입니다.
먼저 마법사로 프로젝트를 생성하고, "stdafx.h" 헤더파일에 Direct2D와 관련된 선언을 추가시켜주기 바랍니다.
위의 내용은 Direct2D와 관련된 라이브러리와 헤더파일을 선언해 준 것입니다.
그리고 작업을 수행할 .cpp 파일에 전역 변수를 두 개 선언합니다.
Direct2D 프로그래밍을 위해서 가장 먼저 해야 하는 일은 ID2D1Factory 를 생성하는 일입니다.
D2D1CreateFactory()의 첫 번째 인자는 멀티 스레드 지원 여부를 설정합니다.
이번 내용에서는 싱글 스레드만을 사용합니다.( 멀티스레드 어려워요~~)
두 번째 인자는 팩토리가 생성되어서 결과를 반환 받을 수 있는 팩토리 포인터를 넘겨줍니다.
이것이 성공하면, Direct2D 와 관련된 작업을 할 수 있게 됩니다.( 참~~ 쉽죠잉!! )
우리가 만들려고 하는 프로그램이 화면에 어떤 내용을 그리는 것입니다.
화면에 무엇인가를 그린다는 개념은 하드웨어 입장에서 봤을 때는 메모리에 값을 쓰는 것입니다.
여러분들이 보고 있는 모니터 화면은 거대한 메모리에 색상 값이 기록되어 있는 것입니다.
이번에 할 일은 바로 이 메모리 영역을 생성하는 일입니다.
Direct2D의 가장 큰 장점이 바로 이 메모리 영역에 값을 기록하는 작업( 이하 렌더링 )이
GDI를 이용하는 것보다 훨씬 빠르다는 것입니다.
왜냐하면, 바로 이 메모리 영역이 그래픽 카드에 있기 때문입니다.
그리기 명령을 수행할 메모리 영역을 생성하기 위해서 다음과 같이 코딩을 합니다.
바로 이 메모리 영역을 렌더타겟( RenderTarget ) 이라 합니다.
CreateHwndRenderTarget() 의 첫번째 인자는 화면에 대한 정보를 설정합니다.
픽셀 포맷이나 DPI 등의 많은 플래그와 옵션이 있지만, 현재는 디폴트 정보로 넘겨주었습니다.
두 번째 인자는 하드웨어 가속을 받는 렌더링에 대한 옵션을 설정합니다.
간단하게 크기 정보만 넘겨주는 것으로 마무리했습니다.
마지막으로는 이 API 호출이 성공했을 때 리턴되어지는 렌더타겟의 포인터를 저장할 변수를 넣어주었습니다.
이렇게 함으로써 간단하게 우리는 하드웨어 가속을 받을 수 있는 렌더타겟을 생성할 수 있습니다.
옵션이나 인자에 대한 설명을 충분히 드리면 좋겠지만, 너무 많습니다.^^
중요한 인자나 옵션에 대해서만 설명 드리는 점 양해 부탁 드립니다.
이제 우리는 렌더타겟을 가지고 있으니 이 메모리 영역에 값을 쓰면, 모니터로 결과를 확인할 수 있습니다.
윈도우가 화면에 그리기 위해서 발생하는 메시지가 WM_PAINT 입니다.
저는 이 메시지를 처리해서, 원하는 색상으로 렌더타겟의 색상을 채울 것입니다.
다음과 같이 코딩을 합니다.
이번 코드를 실행시키면, 파란색으로 칠해진 윈도우 프로그램을 만나게 될 것입니다.
더 정확하게 얘기하면, 메모리 영역( 렌더타겟 )이 파란색 색상데이터로 채워진 것입니다.
샘플을 올려둡니다.( SimpleDraw.zip )
도움이 되셨으면 좋겠습니다.^^
GDI vs Direct2D 비교해 보기.
제가 아무리 Direct2D가 GDI보다 좋다고 혼자 말하는 것 보다, 여러분들이 직접 결과를 확인하는 것이 좋습니다.
그래서 이번에는 GDI와 Direct2D를 이용해서 타원을 렌더링 할 것입니다.
그리고 결과로 나오는 것을 보고, 여러분들이 직접 확인해 보기 바랍니다.
GDI 로 작업하기.
GDI를 이용하는 것은 전통적인 윈도우 프로그래밍에서 사용되던 방식입니다.
주변에서 이와 관련한 많은 내용들을 접할 수 있어서, 내용에 대한 자세한 설명은 생략하겠습니다.
Windows 운영체제에서 모든 드로잉(Drawing) 작업은
디바이스 컨텍스트 오브젝트( device-context object )를 통해서 실행이 됩니다.
이를 줄여서 'DC' 라고 줄여서 얘기합니다.( 다 아시죠? ^^ )
DC란, 윈도우즈 운영체제에서 컴퓨터 모니터나 프린터에 그리기 명령을 수행하기 위한
여러 속성 정보들을 구조화한 데이터입니다.
우리는 Windows API를 이용해서 DC를 이용한 그리기 작업을 수행할 수 있습니다.
DC를 이용하면, 우리는 어떠한 하드웨어 장치와는 관련이 없이 공통된 형식으로 화면에 그릴 수 있습니다.
이것이 가능한 이유는 DC는 CPU가 그리기 작업을 처리해 주기 때문입니다.
<코드>
HDC hDC;
HBRUSH hBrush,
hOldBrush;
if (!(hDC = GetDC (hwnd)))
return;
hBrush = CreateSolidBrush (RGB(0, 255, 255));
hOldBrush = SelectObject (hDC, hBrush);
Rectangle (hDC, 0, 0, 100, 200);
SelectObject (hDC, hOldBrush);
DeleteObject (hBrush);
ReleaseDC (hwnd, hDC);
</코드>
위의 코드는 간단히 DC를 이용해서 사각형을 그리는 코드입니다.
위에서 보는 것과 같이,
GetDC() 라는 API 를 통해서 현재 윈도우 애플리케이션에 대한 DC를 얻어서 작업을 수행합니다.
DC와 관련된 코드를 살펴보면, SelectXXX() 형식을 자주 볼 수 있습니다.
이는 DC가 일종의 상태 정보를 유지하고 있기 때문입니다.
예를 들면, 빨간 펜과 파란 펜으로 두 개 동시에 작업을 할 수는 없습니다.
하나의 펜으로 먼저 작업을 한 후에, 작업한 펜을 제거하고 다음 펜을 선택한 후에 작업을 해야 한다는 얘기입니다.
이점을 잘 고려해서 작업을 해야 하는 것이죠.
이것은 DC를 이용하는 하나의 방법일 뿐입니다.
만약 WM_PAINT 메시지 내부에서 처리하고자 한다면, 아래와 같은 구조를 취할 수 있습니다.
<코드>
PAINTSTRUCT ps;
case WM_PAINT :
hdc = BeginPaint(hWnd, &ps);
{
DoSomething()
}
EndPaint(hWnd, &ps);
break;
</코드>
PAINTSTRUCT 는 내부에 DC 관련 멤버 변수를 가지고 있습니다.
BeginPaint()를 통해서 DC 정보가 채워지게 되는 것입니다.
이러한 DC를 활용하는 것이 GDI 를 이용하는 것의 핵심입니다.
이와 관련된 내용을 더 언급하고 싶지만, 이 정도에서 정리하겠습니다.
이미 많은 분들이 저 보다는 훨씬 많은 지식을 가지고 있을 것이며,
관련 자료들도 이미 훌륭히 찾아 볼 수 있기 때문입니다.^^
우리가 지금 하려는 것은 GDI와 Direct2D의 비교입니다.
프로젝트를 만들고, 시스템을 셋팅하시기 바랍니다.( Direct2D 오브젝트도 생성해 주어야 합니다. )
WM_PAINT 메시지에 이 두 가지 방법을 사용해서 렌더링 하는 함수를 호출했습니다.
( 제가 정의한 함수들입니다. )
먼저, Direct2D를 이용해서 타원을 렌더링 하는 코드를 살펴보겠습니다.
이 방법은 뒤에도 설명을 하겠지만, Direct2D에서 DC를 활용하는 렌더링 방법입니다.
몇몇 생소한 개념들이 보이지만, 이들에 대해서는 차후에 설명을 할 것입니다.
GDI를 활용해서 타원을 렌더링 하는 코드는 다음과 같습니다.
자, 이제 이 둘의 결과는 예제 코드를 실행시키면, 다음과 같이 확인할 수 있습니다.
이는 타원의 일부를 캡쳐한 화면입니다.
좌측은 Direct2D의 결과이고, 우측은 GDI를 이용한 결과입니다.
겉으로 보기에는 차이가 없어 보이지만,
자세히 보면 우측의 경우는 울퉁불퉁한 계단 현상이 심한 것을 알 수 있습니다.
( 잘 보이지 않는다면, 샘플을 실행시켜보시기 바랍니다.^^ )
분명히 같은 기능을 하는 두 함수이지만, 결과에서는 이렇게 차이가 납니다.
샘플 파일( BasicRender.zip )을 같이 첨부했으니, 도움이 되셨으면 좋겠습니다.^^