42
< .NET 플랫폼에서의 2D 그래픽 프로그래밍 > 이 논문에서는 MS가 최신 기술이자 2006년쯤에 나올 새로운 OS인 롷혼(Windows XP 의 차세대 버전 )의 API인 WinFX의 기초가 될 .NET 라이브러리를 사용하여 Manage(관리) 환경에서의 2D 그래픽 프로그래밍에 대해서 소개 히고자 한다. 본 논문은 크게 두 가지의 주제로 나누어 설명을 하고자 한다. 첫째. GDI+를 이용한 2D 그래픽 프로그래밍의 소개 둘째. Managed DirectX를 이용한 그래픽 프로그래밍 의 소개. 참고로 이 글에 포함이 되어 있는 소스는 C# 으로 구성 되어져 있다. 특별히 C# 에 대해서 소개를 한다는 것은 워낙 방대한 내용이고 주제에 대해서 넘어서는 내용 이기에 별도로 언급하지 않는다. 이 글의 소스는 굳이 C#을 몰라도 이해가 가능한 부분이 많다고 생각되나 혹 모르는 분들은 양해를 부탁한다. 1. GDI+ 에 대해 GDI+는 Win32 API의 GDI 프로그래밍 방식을 개선/발전 시킨 것으로 .NET 뿐만 아닌 Windows 2000 이상의 플랫폼 이라면 Win32 API에서도 사용이 가능하다. GDI+는 .NET 에서 그래픽 작업을 위하여 제작 된 API로 특히 웹, Windows 컨트 롤을 염두에 두고 설게 되었다. GDI+ 는 API 라기 보다는 GDI를 감싼 레퍼이다. GDI+는 이해하기 쉽고 상속에 기반한 개체 모델을 제공한다. 특히 C++/MFC에 경험이 있는 프로그래머라면 GDI+의 개념을 쉽게 받아 들일 수 있을 것이다. GDI+의 특징 1. 창, 비트맵, 프린터라는 세 종류의 그리기 표면을 제공한다. 2. 2차원적인 선을 그릴 수 있는 도구를 제공한다. 무한히 다양한 브러시와 펜 을 사용해서 선, 도형, 다각형, 곡선을 그릴 수 있다. 3. 다양한 텍스트 그리기를 지원한다(앤티 엘리어싱도 제공한다). 4. 이미지를 읽었어 그리기도 가능하며 이미지를 생성하여 그 안에 그림을 그

< .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

< .NET 플랫폼에서의 2D 그래픽 프로그래밍 >

이 논문에서는 MS가 최신 기술이자 2006년쯤에 나올 새로운 OS인 롷혼(Windows

XP 의 차세대 버전 )의 API인 WinFX의 기초가 될 .NET 라이브러리를 사용하여

Manage(관리) 환경에서의 2D 그래픽 프로그래밍에 대해서 소개 히고자 한다.

본 논문은 크게 두 가지의 주제로 나누어 설명을 하고자 한다.

첫째. GDI+를 이용한 2D 그래픽 프로그래밍의 소개

둘째. Managed DirectX를 이용한 그래픽 프로그래밍 의 소개.

참고로 이 글에 포함이 되어 있는 소스는 C# 으로 구성 되어져 있다. 특별히 C#

에 대해서 소개를 한다는 것은 워낙 방대한 내용이고 주제에 대해서 넘어서는 내용

이기에 별도로 언급하지 않는다. 이 글의 소스는 굳이 C#을 몰라도 이해가 가능한

부분이 많다고 생각되나 혹 모르는 분들은 양해를 부탁한다.

1. GDI+ 에 대해

GDI+는 Win32 API의 GDI 프로그래밍 방식을 개선/발전 시킨 것으로 .NET 뿐만

아닌 Windows 2000 이상의 플랫폼 이라면 Win32 API에서도 사용이 가능하다.

GDI+는 .NET 에서 그래픽 작업을 위하여 제작 된 API로 특히 웹, Windows 컨트

롤을 염두에 두고 설게 되었다.

GDI+ 는 API 라기 보다는 GDI를 감싼 레퍼이다.

GDI+는 이해하기 쉽고 상속에 기반한 개체 모델을 제공한다.

특히 C++/MFC에 경험이 있는 프로그래머라면 GDI+의 개념을 쉽게 받아 들일 수

있을 것이다.

GDI+의 특징

1. 창, 비트맵, 프린터라는 세 종류의 그리기 표면을 제공한다.

2. 2차원적인 선을 그릴 수 있는 도구를 제공한다. 무한히 다양한 브러시와 펜

을 사용해서 선, 도형, 다각형, 곡선을 그릴 수 있다.

3. 다양한 텍스트 그리기를 지원한다(앤티 엘리어싱도 제공한다).

4. 이미지를 읽었어 그리기도 가능하며 이미지를 생성하여 그 안에 그림을 그

Page 2: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

리는 것도 가능하고 또한 다양한 포맷으로 저장도 가능하다.

5. 인쇄 지원으로 미리 보기 기능도 쉽게 구현 가능하다.

GDI+의 장점

1. GDI 이상의 능력을 제공한다. GDI 에서는 구현하기가 힘들었던 기능들인

반투명 효과, 그라데이션 브러시, 강력한 그래픽 패스 등을 제공한다.

2. GDI는 복잡 하여 사용이 까다로우나 GDI+는 간결 하면 한결 사용이 편리

하다.

3. GDI+는 개체 지향적 클래스 구조로 되어 있어 GDI+ 프로그래밍은 개체의

생성, 개체의 속성 설정, 개체의 메소드 호출로 이루어 진다.

4. 메소드 오버로딩을 사용한다. 따라서 어떤한 GDI+ 개체의 메소드를 호출

할 때 주어진 상황에 가장 적합한 인수들을 받는 버전의 메소드를 선택할

수 있다.

5. GDI+는 외곽선 그리기와 내부 채우기 사이의 차이를 인식하여 각각 서로

구별되는 처리수단을 제공하는 좀 더 유연한 그리기 인터페이스를 제공한

다.

6. GDI+는 상태 관리의 일부 측면들을 개발자로부터 은폐한다.

GDI+ 새로운 기능

1). 그라데이션 브러시

- GDI+는 도형, 패스 및 영역을 채우는 데 사용하는 선형 그라데이션 브러시와 패

스 그라데이션 브러시를 제공함으로서 GDI를 확장한다. 그라데이션 브러시는 또한

선, 곡선 및 패스를 그리는 데 사용할 수 있다. 선형 그라데이션 브러시를 사용하여

도형 내의 위치에 따라 색상이 변하도록 도형을 채울 수 있다.

도형을 패스 그라데이션 브러시로 채울 때에는 도형의 한 영역에서 다른 영역으로

이동할 때의 색상 변화를 다양하게 지정할 수 있다.

Page 3: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

2). 카디널 스프라인

GDI+는 GDI에서 지원되지 않던 카디널 스플라인을 지원한다. 카디널 스플라인은

대형 곡선을 형성하는 개별 곡선 순서 집합이다. 스플라인은 점의 배열과 그 배열

의 각 점을 통과하는 패스에 의해 지정된다. 카디널 스플라인은 배열의 각 점을 날

카로운 모서리 없이 매끄럽게 통과하므로, 직선을 연결하여 생성한 패스보다 더 정

교하다.

3). 독립적인 패스 개체

GDI+에서 그리기는 Graphics 개체별로 수행되며 Graphics 개체와 분리된 여러

GraphicsPath 개체를 생성하고 유지할 수 있다. GraphicsPath 개체는 그리기가

끝나도 소멸되지 않기 때문에 같은 GraphicsPath 개체를 사용하여 패스를 여러 번

그릴 수 있다.

4). 변환 및 매트릭스 개체

GDI+는 회전이나 변형 등과 같은 변환 작업을 쉽고 유연하게 만들어 주는 강력한

도구인 Matrix 개체를 제공한다. 매트릭스 개체는 변형된 개체와 함께 동작한다.

예를 들어, GraphicsPath 개체는 Matrix 개체를 인수로 받는 Transform 메서드가

있다.

Page 4: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

5). 확장 가능한 영역

GDI+에서는 GDI 보다 영역 지원 기능이 대폭 강화되었다. GDI 에서는 영역이

디바이스 좌표로 저장되며 영역에 적용할 수 있는 유일한 변환은 변형이다.

GDI+에서는 영역을 전역 좌표로 저장하며 영역에 크기 조절 등과 같은 모든 변환

매트릭스를 적용할 수 있다. 다음 예제에서는 크기 조절, 회전 후 변환 변형을

거친 영역을 보여 준다.

6). 알파 혼합

알파 혼합을 사용하면 채워진 색상의 투명성을 지정할 수 있다. 투명한 색상은

배경 색상과 혼합된다. 채워지는 색상의 투명성을 높일 수록 배경색이 잘 보인다.

Page 5: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

7). 다양한 이미지 형식 지원

GDI+에서 제공되는 Image, Bitmap 및 Metafile 클래스를 사용하여 다양한 형식으로

이미지를 로드 및 저장하고 조작할 수 있습니다. 다음 형식이 지원됩니다. BITMAP.

GIF, JPEG, EXIF, PNG, TIFF, ICON, WMF, EMF

GDI+는 개발자에게 필요한 대부분의 그래픽 기능성을 제공하여 일관적이고 강력한

고성능 클래스들의 집합이다. 그러나 GDI+는 새로운 라이브러리로써 기능성에 제

한도 있어 때에 따라서는 GDI를 함께 사용 할 경우도 있다.

GDI+ 네임스페이스

GDI+ 관련 네임스페이스는 총 6개로 역할은 다음과 같다.

네임 스페이스 설명

System.Drawing 그리기 표면, 이미지, 색, 브러시, 펜, 글꼴 같은 기

본적인 그래픽 기능 제공

System.Drawing.Drawing2D 고급 레스터 및 벡터 그래픽 기능성을 제공

System.Drawing.Imaging System.Drawing 네임스페이스가 제공하는 것 이사

의 이미징 기능성을 제공

System.Drawing.Printing 인쇄 및 인쇄 미리 보기 기능성을 제공

System.Drawing.Text System.Drawing 네임스페이스가 제공하는 것 이상

의 글꼴 기능성을 제공

System.Drawing.Design 사용자 지정 컨트롤의 디자인 시점 지원을 개선하기

위한 기능성 제공

Page 6: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

이 글에서는 GDI+의 모든 것을 다룰 수는 없으므로 게임프로그래밍과 밀접한

System.Drawing, System.Drawing.Drawing2D,

System.Drawing.Imaging 네임 스페이스에 있는 클래스들 위주로 설명 하려고 한

다.

2. GDI+ 프로그래밍

(1)간단한 C#을 사용한 GDI+ 프로그램

처음으로 간단하게 구성한 GDI+ 와 C# 으로 구성된 프로그램을 소개 하고자 한다.

여기에서 예제로 소개할 프로그램들은 모두 간단하므로 소스 설명과 함께 간단하게

설명하는 정도로 하고자 한다.

예) 1

using System;

using System.Windows.Forms;

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Drawing.Imaging;

using System.Drawing.Text;

public class LineTextForm : Form

{

// Win32 기반에서는 OnPaint 와 같이 그리기 이벤트시 호출되는 함수 이다.

// OnPaint 는 오버라이드 할 수도 있고 아니면 delegate 로 위임 시킬 수도

있다.

protected override void OnPaint(PaintEventArgs e)

{

// 그래픽스 객체를 얻어온다.

Graphics g = e.Graphics;

Page 7: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

// 검은색의 크기 3 의 펜을 하나 생성한다.

Pen blackPen = new Pen(Color.Black, 3);

// 0,0 에서 100,100 점을 생성한다.

Point startPoint = new Point(0, 0);

Point endPoint = new Point(100, 100);

// 위에서 생성한 펜으로 점 사이를 선으로 긋는다.

g.DrawLine(blackPen, startPoint, endPoint);

// 검은색 글자를 그리기 위해 검은색 브러시를 생성한다.

Brush blackBrush = new SolidBrush(Color.Black);

// ‘Times New Roman’글꼴 패밀리를 생성한다.

FontFamily familyName = new FontFamily("Times New Roman");

// 글꼴 패밀리를 이용하여 24 픽셀의 글꼴을 생성.

Font myFont = new Font(familyName, 24, FontStyle.Regular,

GraphicsUnit.Pixel);

// 글자를 그릴 위치의 포인트를 만든다.

PointF startPoint = new PointF(10, 20);

// “Hello World!’라는 글자를 10,20 위치에 검은색의 ‘Times New

Roman’폰트로 그린다.

g.DrawString("Hello World!", myFont, blackBrush, startPoint);

}

// 프로그램 진입점. 기존 C 및 C++ 프로그램의 main 과 비슷하다.

public static void Main()

{

// 메인 폼을 생성 후 실행한다.

Application.Run(new LineTextForm());

}

}

Page 8: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

위 프로그램은 아주 간단한 형식의 C# 언어를 이용한 GDI+ 프로그램이다. 메인

폼(윈도우)에 OnPaintg 메소드를 오버라이드 하여 GDI+ 객체를 이용하여 선을 긋

고 글자를 그리고 있다. 위 예제를 보면 알겠지만 예전 GDI에 비해서 간단하며 상

당히 직관적으로 되어 있다는 것을 알고 있다. .NET에서는 동적으로 객체를 생성

하며 객체의 해제는 .NET에서 해주므로 신경 쓸 필요가 없다.

폼에 그림을 그리기

Win32 API에서 프로그래밍시 윈도우에서 다시 그리기를 시도 할 때 계속 그려질려

고 하면 WM_PAINT 메시지에서 그려질 내용을 기술 하였는데 .NET에서도 이와

같다.

위 예제 처럼 protected override void OnPaint(PaintEventArgs e) 을 오버라이드

하여 정의 하던가

LineTextForm.Paint += new System.Windows.Forms.PaintEventHandler(this.MapEditer_Paint); 처럼

delegate로 특정 함수로 위임하여도 된다.

.NET의 OnPaint의 동작은 기존의 Win32의 WM_PAINT와 같기 때문에 기존의 윈도우

프로그래머들은 아주 쉽게 이해될 것 이다.

Win32에서의 DC는 .NET에서는 Graphics

기존의 Win32 프로그래밍에서는 윈도우에 무엇인가를 그리기 위해서는 DC를 얻어서

여기에다 그렸었다. .NET 에서는 Graphics가 기존의 DC의 역할을 한다.

Graphics g = e.Graphics;

OnPaint 이벤트에서 PaintEventArgs 인수를 통해 Graphics 객체를 얻는다.

다른 이벤트에서 만약 뭔가를 그리고 싶다면 CreateGraphics 메소드로 직접 생성해

야된다.

Graphics g = LineTextForm.CreateGraphics();

위의 예제와 Win32 의 GDI를 사용하는 예제를 비교를 해보면

.NET의 GDI+ 프로그래밍의 간단함과 편리함을 어느 정도 알 수 있으리라 생각한

다.

그럼 계속해서 GDI+의 각 요소에 대해서 이야기 하겠다.

Page 9: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

(2) 펜으로 선과 도형 그리기

선과 도형을 그릴 때에는 Graphics 개체의 DrawLine 메소드와 DrawRectangle 메

소드를 사용한다.

그리고 선과 도형의 선의 색이나 굵기를 지정할려면 Pen 개체를 사용하여야 된다.

그럼 검은색 펜을 사용하여 100,100 좌표에서 250,300 으로 선을 긋는 다면 아래

와 같다.

Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0));

e.Graphics.DrawLine(pen, 100, 100, 250, 300);

Pen 클래스 생성자를 사용하여 검은색 Pen을 만드는데 생성자의 전달 인수를

Color.FromArgb(알파 값, R, G, B) 메소드로 색을 지정하여 넘겨준다.

3픽셀의 Pen으로 10,10 위치에 너비는 50, 높이는 50인 사각 도형은 그릴 때는

다음과 같다.

Pen blackPen = new Pen(Color.FromArgb(255, 0, 0, 0), 3);

e.Graphics.DrawRectangle(blackPen, 10, 10, 50, 50);

펜의 굵기가 3이므로 1픽셀은 경계에 1픽셀은 안쪽, 1픽셀은 바깥쪽에 그려진다.

선의 앞과 끝의 모양을 지정할려면

선의 앞과 끝에 화살표나 사각형, 라운드 등 다양한 스타일을 지정할 수 있다.

pen.StartCap = LineCap.ArrowAnchor;

pen.EndCap = LineCap.RoundAnchor;

위와 같이 펜의 앞과 뒤에 LineCap으로 스타일을 지정하면 된다. 밑의 그림은

LineCap을 지정한 선의 모습이다.

Page 10: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

점선 밒 파선 그리기

Pen 개체의 DashStyle 속성에 DashStyle 열거형 중 하나를 선택함으로써 점선이

나 파선을 그릴 수 있다.

Pen.DashStyle = DashStyle.Dash;

사용자 지정 선 그리기

단색의 일반적인 선 대신 이미지 파일을 사용하여 선을 그릴 수 있다. 이런 선을

그릴려면 TextureBrush 개체를 만들어 Pen 생성자에 전달하면 된다.

아래의 예제는 .NET Frmaework SDK에 있는 예제이다.

Bitmap bitmap = new Bitmap("Texture1.jpg");

TextureBrush tBrush = new TextureBrush(bitmap);

Pen texturedPen = new Pen(tBrush, 30);

e.Graphics.DrawImage(bitmap, 0, 0, bitmap.Width, bitmap.Height);

e.Graphics.DrawEllipse(texturedPen, 100, 20, 200, 100);

(3) 브러시 사용

도형을 색으로 채우려면 SolidBrush 개체를 만들어 Grpahics 클래스의 채우기 메

소드 중 하나에 인수로 전달한다. 아래 코드는 녹색으로 채워진 타원을 그린다.

SolidBrush solidBrush = new SolidBrush( Color.FromArgb(255, 0,

255, 0) );

Page 11: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

e.Graphics.FillEllipse(solidBrush, 0, 0, 100, 60);

도형의 이미지로 채우기

도형을 특정의 이미지로 채우려고 하면 Image 클래스와 TextyreBrush 클래스를

사용하면 된다.

// 채울 이미지를 생성한다.

Image image = new Bitmap("particle.bmp");

// 이미지를 사용 할 브러시를 생성한다.

TextureBrush tBrush = new TextureBrush(image);

// 50,150 위치에 타원을 그린다.

e.Graphics.FillEllipse(tBrush, new Rectangle(50, 150, 200, 300));

도형에 이미지를 바둑판으로 그리기

위의 TextureBrush를 사용하면 도형에 바둑판 식으로 이미지를 채울 수 있다.

아래의 예제는 SDK에 있는 것을 인용하였다.

이미지를 채울려고 한다.

Image image = new Bitmap("HouseAndTree.gif");

TextureBrush tBrush = new TextureBrush(image);

Pen blackPen = new Pen(Color.Black);

e.Graphics.FillRectangle(tBrush, new Rectangle(0, 0, 200, 200));

Page 12: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

e.Graphics.DrawRectangle(blackPen, new Rectangle(0, 0, 200, 200));

위 코드는 다음과 같이 출력된다.

브러시 개체의 WrapMode 속성을 지정에 따라 이미지를 대칭형으로 그릴 수 있다.

가로 대칭 세로 대칭

가로세로 대칭

Page 13: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

WrapMode 속성 값 중 WrapMode.TileFlipX 는 가로 대칭, WrapMode.TileFlipY 는

세로 대칭, WrapMode.TileFlipXY 는 가로세로 대칭이 되도록 한다.

(4) 이미지

GDI+에는 레스터 이미지에 대해 작업하는 데 사용하는 Bitmap 클래스와 벡터 이

미지에 대해 작업하는데 사용하는 MetaFile 클래스가 있다. 이 두 클래스는 모두

Image 클래스에서 상속된다.

이미지의 읽기 및 그리기

파일에서 이미지 파일을 읽어 화면에 그리려면 Bitmap 개체와 Graphics 개체가 필

요하다. Bitmap 클래스는 이름만 보면 BMP 파일만 읽어 수 있는 것처럼 보이지만

BMP, GIF, JPEG, PNG, TIFF 파일도 읽을 수가 있다.

기본적인 이미지 출력은 Bitmap 생성자에 이미지 파일 이름을 전달하여 개체를 만

들고 이 개체를 Graphics 개체의 DrawImage 메소드에 전달 하면 된다.

Bitmap bitmap = new Bitmap("Grapes.jpg");

e.Graphics.DrawImage(bitmap, 60, 10);

위 코드는 ‘Graphics.jpg’ 파일을 화면의 60,10에 출력 한다.

또 다양한 Bitmap 생성자를 이용하여 다양한 방법으로 Bitmap 클래스를 생성하여

사용 할 수 있다.

이미지 자르기 및 크기 조정

Graphics 클래스에는 다양하게 하게 오버로드 된 DrawImage 메소드가 있다. 그

중 일부는 이미지를 자르고 배율을 조정하는 데 사용할 수 있는 원본 및 대상 사각

형 매개 변수가 있다.

아래의 예제는 SDK에 있는 예제로 원본의 사과 이미지를 그린 후 DrawImage 메

소드를 사용하여 원래 사과 이미지보다 큰 대상 사각형에 사과의 일부를 그린다.

Image image = new Bitmap("Apple.gif");

// 사과 이미지를 0,0 좌표에 그린다.

Page 14: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

e.Graphics.DrawImage(image, 0, 0);

// 사과 이미지의 넓이 및 높이를 얻는다.

int width = image.Width;

int height = image.Height;

// 150,20 위치에 사과 이미지의 1.3배의 실수를 사용하는 사각형 개체를 만든다.

RectangleF destinationRect =new RectangleF(

150,

20,

1.3f * width,

1.3f * height);

// 사과 이미지의 넓이와 높이의 0.75 배 크기의 사각형 개체를 만든다.

RectangleF sourceRect = new RectangleF(0, 0, .75f * width, .75f * height);

// 사과 이미지의 원래 이미지의 0.75까지(만약 넓이가 100 이라면 75)만의 크기를

// 원본 이미지의 1.3배의 크기로 그린다.

e.Graphics.DrawImage(image, destinationRect, sourceRect, GraphicsUnit.Pixel);

DrawImage 메소드의 첫번째 인수는 이미지 개체, 두번째는 출력되는 위치 및 크

기를 가르키는 사각 개체, 세번째는 그리기 원하는 이미지의 위치 및 크기를 가르

키는 사각 개체, 네번째는 측정단위를 가르킨다.

배율 조정 시 이미지의의 보간 모드에 따라 성능 및 이미지의 질에 영향을 준다.

Page 15: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

보간 모드의 선택은 Graphics 개체의 InterpolationMode 속성 값을 변경하면 된다.

InterpolationMode 는 총 5개의 열거가 있다.

• NearestNeighbor

• Bilinear

• HighQualityBilinear

• Bicubic

• HighQualityBicubic

이미지의 퀄리티는 NearestNeighbor < Bilinear < HighQualityBilinear

< Bicubic < HighQualityBicubic 순이고 성능은 당연히 그 반대이다.

사용 방법은 DrawImage 메소드를 사용하기 전에

e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;

로 설정해 주면 된다.

이미지의 회전 및 반사

원래 이미지의 왼쪽 위, 오른쪽 위, 왼쪽 아래 모서리에 대한 대상 지점을

지정하여 이미지를 회전 및 반사하고 기울 일 수 있다. 세개의 대상 지정에 따라

원래의 사각형 이미지를 평행 사변형으로 매핑하는 관계 변환이 결정된다.

넓이가 100, 높이가 50 인 이미지를 기울이고 회전 하고 반사 하려고 한다.

Point[] destinationPoints = {

new Point(200, 20), // 원본의 왼쪽 상단을 가르킨다.

new Point(110, 100), // 원본의 오른쪽 상단을 가르킨다.

Page 16: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

new Point(250, 30)}; // 원본의 왼쪽 하단을 가르킨다.

Image image = new Bitmap("Stripes.bmp");

// 원본 이미지를 0,0 에 그린다.

e.Graphics.DrawImage(image, 0, 0);

// 원본 이미지를 변형 하여 그린다.

e.Graphics.DrawImage(image, destinationPoints);

자동 배율 조정을 주의 하자

일반적으로 DrawImage 메소드는 DrawImage( Image, x, y) 메소드를 많이 사용한

다. 그러나 위의 메소드는 때에 따라서 성능에 영향을 미친다. 만약 Image의 해상

도와 GDI+의 해상도가 서로 다르면 자동으로 보간을 한다. 그래서 자동으로 이미

지 배율을 조정한다. 이것을 막기 위해서 DrawImage( Image, x, y, width, height )

를 사용하여 자동으로 행하는 이지미의 조정을 막을 수 있다.

코딩의 양이 조금 늘더라도 가급적 위치와 크기를 지정하는 DrawImage 메소드 사

용을 권한다.

새로운 이미지를 생성하고 이미지에 그리기

새로운 이미지를 생성할려고 하면 Bitmap 클래스의 생성자 중 하나를 선택 하여

사용한다. 다양한 생성자가 있으나 일반적으로 다음의 3가지를 많이 사용한다.

Page 17: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

Bitmap bmp = new Bitmap( int width, int height );

Bitmap bmp = new Bitmap( int width, int height, PixelFormat pixelformat );

Bitmap bmp = new Bitmap( int width, int height, Graphics g );

첫번째 생성자는 넓이와 높이를 지정하고 픽셀 형식은 Foramt32bppARGB 이다.

두번째 생성자는 넓이와 높이, PixelFormat 열거형을 지정한다.

세번째 생성자는 넓이와 높이, 그리기를 원하는 Graphics 개체의 그리기 표면과 동

일한 해상도 및 색 깊이를 가지게 한다.

다음의 새로운 이미지를 만들고 이 이미지에 속인 찬 사각형을 그려보겠다.

// 200, 200 크기의 이미지를 생성한다.

Bitmap bmp = new Bitmap( 200, 200 );

// 비트맵 이미지의 그리기 표면을 얻는다.

Graphics gImage = Grpahics.FromImage( bmp );

// 이미지의 0,0 에서 비트맵 이미지 크기만큼의 녹색으로 채워진

// 사각형을 그린다.

gImage.Fill Rectangle( Brushes.Green, 0, 0, bmp.Width, bmp.Height );

// 폼의 그리기 표면을 얻는다.

Graphics gScreen = g.Graphics;

// 폼에 이미지를 그린다.

gScreen.DrawImage( bmp,

new Rectangle( 10, 10, bmp.Width, bmp.Height );

Bitmap 개체에 그릴 때의 장점

1. 미리 이미지에 그리고 필요할 때 Paint 이벤트에서 그린다. Paint 이벤트를

받을 때마다 그릴 필요가 없이 한번만 그리면 되므로 성능을 크게 향상 시

킬 수 있다.

2. 복잡한 그림을 그릴 때 메모리 안의 이미지에서 그리고 다 그린 후 Paint에

서 그리므로 깜빡임을 피 할 수 있다.

3. 블러링이나 샤프닝 같은 이미지 처리들은 이미지를 메모리 상에서 조작하는

방식에서만 구현 가능하다.

Page 18: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

합성 모드에 따른 알파 혼합

이미지 전체를 반투명하게 만들던가 기존 이미지에 새 요소를 반 투명하게 그려서

이미지의 기존 내용과 혼합되도록 만들 수 있다.

GDI+는 합성 모드는 두 가지가 있다.

1. 그려지는 색과 알파를 기존 색과 알파에 혼합한다.

2. 그려지는 색과 알파를 기존 색과 알파에 덮어쓴다.

다음의 예제는 SDK에 있는 예제로 Bitmap 개체를 기반으로 Graphics 개체를 만든

후 두 개의 반투명 브러시가 있는 Graphics 개체를 사용하여 비트맵에서 빨강 타

원과 녹색 타원을 그린다. 녹색 타원은 빨강 타원과 겹치지만 합성 모드를

CompositingMode.SourceCopy로 설정하여 혼합되지 않도록 한다.

그리고 다음 코드에서는 폼의 그리기 표면에 속이 채워진 사각형을 그린다.

비트맵 이미지와 폼의 표면에 그린 것이 서로 혼합되어 그려진다.

// 빈 비트맵을 생성한다.

Bitmap myBitmap = new Bitmap(180, 100);

// 비트맵의 그리기 표면을 얻는다.

Graphics bitmapGraphics = Graphics.FromImage(myBitmap);

// 알파 값을 가지는 붉은 색과 녹색의 브러시를 생성한다.

SolidBrush redBrush = new SolidBrush(Color.FromArgb(210, 255, 0, 0));

SolidBrush greenBrush = new SolidBrush(Color.FromArgb(210, 0, 255,

0));

// 합성모드를 덮어쓰기로 설정한다.

bitmapGraphics.CompositingMode = CompositingMode.SourceCopy;

// 알파 값을 가진 붉은 브러시로 타원을 그린다.

bitmapGraphics.FillEllipse(redBrush, 0, 0, 150, 70);

// 위의 타원과 일부가 겹쳐지는 녹색의 브러시로 타원을 그린다.

bitmapGraphics.FillEllipse(greenBrush, 30, 30, 150, 70);

Page 19: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

// 합성의 퀄리티를 지정한다.

e.Graphics.CompositingQuality = CompositingQuality.GammaCorrected;

// 세 가지의 색으로 폼의 그리기 표면에 사가형을 그린다.

SolidBrush colorBrush = new SolidBrush(Color.Aqua);

e.Graphics.FillRectangle(colorBrush, 200, 0, 60, 100);

colorBrush.Color = Color.Yellow;

e.Graphics.FillRectangle(colorBrush, 260, 0, 60, 100);

colorBrush.Color = Color.Fuchsia;

e.Graphics.FillRectangle(colorBrush, 320, 0, 60, 100);

// 비트맵을 그리기 표면에 그린다.

e.Graphics.DrawImage(myBitmap, 0, 0);

// 세 가지 색으로 사각형을 그린 곳에 비트맵을 그린다.

e.Graphics.DrawImage(myBitmap, 200, 0);

아래의 결과를 보면 알겠지만 비트맵 파일에 그린 타원은 서로 덮어쓰기를

하고 있지만 폼의 배경에 그린 사각형과는 합성을 하고 있다.

만약 타원도 서로 혼합되게 할려면 CompositingMode 를

bitmapGraphics.CompositingMode = CompositingMode.SourceOver;

로 변경 하면 된다. 결과는 다음과 같다.

Page 20: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

이것으로 .NET에서의 GDI+ 프로그래밍에 대해서 마칠까 한다.

지금까지 필자가 적은 것은 GDI+의 아주 일부분으로써 아주 기본만을 간추린 것이

다. 사실 적을 게 더 많지만 적으려면 그 내용이 너무 방대하기 때문에 너무 기본

만은 소개한 것에 대해 많은 양해를 바란다. 여기 나온 것 말고 더 많은 정보는 서

점에 출간된 .NET용 책이나 .NET Framework SDK를 통해 얻을 수 있다.

아직도 온라인 보드형 게임에서는 Win32 기반의 GDI를 사용하여 그리는데 .NET

에서는 GDI+를 사용하여 GDI에 비해서 더욱 쉽고 빠르게 개발을 할 수 있으리라

생각된다.

그러면 이후는 .NET에서 사용하는 DirectX인 Managed DirectX에 대해서 이야기

하겠다.

3. Managed DirectX

Managed DirextX에 대해서 아주 간단하게 설명하면 Microsoft(이하 MS)의 .NET

플랫폼에서 사용하는 DirectX라고 말 할 수 있다. DirectX 8.0까지는 .NET에서

DirectX를 사용할려면 InteOP라는 방식을 이용하여 간접적으로 사용하던 것을 9.0

에서 .NET에서도 편하게 사용 할 수 있도록 하였다. .NET이 객체의 관리

를 .NET 자체가 해주므로 .NET의 언어들을 Managed(관리) 언어라고 하는데 그래

서 기존의 DirectX에 Managed라는 수식어가 붙었다. 그래서 Managed DirectX는

기존의 DirectX와 구조가 거의 같으면서 사용이 더 쉬워졌다고 생각해도 될 것이다.

Managed DirectX는 다음의 컴포넌트로 구성되어 있다.

• Direct3D Graphics : 3D 그래픽 프로그래밍에 사용 하는 API 를 제공한다.

• DirectDraw : 비디오 메모리로의 하위 레벨 접근을 제공하여 빠른 렌더링을

실현시켜준다.

Page 21: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

• DirectInput : 포스 피드백 기술의 완전 지원 등 다양한 입력 디바이스를

지원해 준다.

• DirectPlay : 멀티플레이어랑 네트워크 게임을 지원 한다.

• DirectSound : 디지털 샘플의 재생과 캡쳐를 지원한다.

• 오디오와 비디오 재생은 오디오 미디어와 비디오 미디어 재생 및 제어를

지원한다.

Managed DirectX의 장점

기존의 DirectX는 COM으로 되어 있어 이것을 사용하기 위해 InterOP 레

이어를 사용했으나 Managed DirectX는 바로 사용하므로 성능이 향상 된다.

Managed 코드는 코드의 양을 감소 시켜 생산성을 향상 시킨다. 인터페이

스가 고성능으로 쉽게 사용하는 Microsoft .NET Framework에 공통된 타

입의 인터페이스를 사용하여 아주 직관적이다.

Managed 코드를 사용하면 오브젝트의 해방 등 메모리 관리에 관한 대부분

의 작업에서 해방된다.

4. Managed DirectX를 사용하기 위한 환경

Managed DirectX를 사용하기 위해서는 MS의 .NET Framework 1.1 SDK와

DirectX 9 SDK, Visual Studio.NET 2002(및 상위 버전)가 필요하다.

.NET Framework1.1 SDK와 DirectX 9 SDK는 MS 웹 사이트에서 다운로드 받을

수 있다.

( 참고로 개발 PC가 아닌 PC에서 .NET용 프로그램을 실행하기 위해서는 .NET

Framework 1.1과 DirectX 9만 설치 되어 있으면 실행 가능하다.)

참고로 DirectX 9 SDK는 Managed DirectX 부분이 2004 Summer Update에서 약

간 변경된 사항이 있으므로 꼭 최신의 SDK를 설치 하기를 바란다.

Managed DirectX는 .NET용 언어인 C#, Visual Basic .NET 및 Managed C++ 언

Page 22: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

어로 프로그래밍 하므로 위의 3 언어 중 하나를 선택해서 프로그래밍 해야 된다.

사실 위의 3개의 언어는 공통의 라이브러리를 사용하므로 언어 문법적인 부분이 다

를 뿐이지 사용하는 라이브러리는 같기 때문에 크게 차이는 나지 않는다고 볼 수

있다.

새롭게 프로그래밍 언어를 배우기 힘든 사람 중 기존에 Visual basic을 사용해본

사람은 Visual Basic .NET을 사용하고 C++을 사용할 줄 아는 사람은 Managed

C++를 사용하기를 추천하나 가능하면 MS에서 요즘 가장 밀고 있으며 .NET의 대

표 언어인 C#으로 사용하기를 바란다. 추천하는 이유는 최신의 언어라서 상당히 잘

만들어져 있으며 MS에서 .NET 샘플 프로그램을 주로 이 언어로 사용해서 만들기

때문에 MS의 강의나 샘플 프로그램을 볼 때 많은 도움이 되기 때문이다.

5. Managed DircetDraw 소개

Managed DirectDraw(이하 줄여서 MDD라고 하겠다)는 기존의 DirectX의 DirectDraw와

같다고 보면 된다. 이름을 봐도 비슷하지 하니 굿이 따로 설명하지 않아도 쉽게 알 수 있었

을 것이라고 생각한다.

MDD는 디스플레이 메모리, 하드웨어 블리트, 하드웨어 오버레이 지원, 플립, 서페이스 지

원을 직접 조작 할 수 있다. DirectDraw가 지원하는 기능을 모두 지원하면 각 인터페이스

의 구조와 이름도 흡사하다. 그래서 기존의 DirectDraw를 아는 사람은 아주 쉽게 적응 할

수가 있다.

요즘의 게임은 거의 3D로 제작하는 분위기라서 사실 2D를 한다는 것은 시대에 뒤떨어진다

는 느낌을 받을 수가 있는데 필자는 짧은 게임 개발 경험이 있지만 아무리 3D가 대세라고

하지만 2D로 만들 수 있는 게임이 있고(특히 온라인 웹 용 보드 게임은 굿이 3D를 사용할

의미가 없다라고 볼 수도 있다), 2D가 3D 보다는 게임 제작 방법이 훨씬 쉽고 다양한 기법

이 많이 공개되어 있었어 아직 .NET에 익숙하지 않던가 3D 개념이 약한 게임 프로그래머

들은 먼저 MDD를 습득하고 Direct3D로 넘어 가는 것이 아주 좋은 순서이지 않을까 생각

된다.

다음은 MDD의 구조에 대한 이해를 위해 기존의 DirectX 7.0의 DirectDraw와 각 중요

인터페이스를 서로 비교하면 다음과 같다.

Page 23: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

참고로 아래의 MDD의 클래스는 모두 Microsoft.DirectX.DirectDraw 네임스페이스 안에

있다.

Managed DirectDraw DirectDraw 7.0

Cliper IDirectDrawClipper

ColorControl IDirectDrawColorControl

Device IDirectDraw7

DeviceCollection DirectDrawEnumerateEx 함수

DisplayModeCollection IDirectDraw7::EnumDisplayModes 함수

Palette IDirectDrawPalette

Surface IDirectDrawSurface7

SurfaceCaps IDirectDrawSurface7

SurfaceDescription IDirectDrawSurface7::SetSurfaceDesc 함수

이 이외에 Microsoft.DirectX.DirectDraw 네임스페이스 안에는 아주 많은 예외처리 인터

페이스가 있으며 프로그래밍 시 이것을 이용하면 안전하고 편리하게 예외에 대응 할 수가

있다( 참고로 .NET의 예외는 C++의 예외와 달리 오버헤드가 거의 없다).

그리고 MDD는 기존의 DirectDraw 7.0을 단순히 컨버전 한 것이 아니라 7.0에 없는 기능

이 추가되어 있어 상당히 편리하게 사용 할 수 있다( DX 7.0에는 없는 선 긋기 등이 있다).

MDD를 공부 할 때 기존의 DirectDraw와 비교하는 것은 필수 이다. 왜냐하면 MS가

DirectX 8.0부터 기존의 2D를 더 이상 지원하지 않는데, Managed DirectX에서도 3D는

아주 자세히 설명 하고 있지만 2D인 DirectDraw에 대해서는 거의 한 줄 정도의 설명 밖에

없었어 처음 DirectDraw를 접하는 사람은 거의 알 수가 없기 때문에 DirectDraw 7.0과

인터페이스 이름을 서로 비교하면서 DirectX 7.0 SDK의 DirectDraw 부분을 같이 봐야

이해를 할 수 있을 것이다(참고로 SummerUpdate 2004에서는 예제도 없어져 버렸다 -_-).

MDD가 기존의 DirectDraw와 거의 흡사하기 때문에 설명은 이것으로 간단하게 하고 이제

부터 프로그래밍 예를 들면서 설명하겠다 – 필자의 어설픈 설명보다는 실제 예를 보는 것이

이해에 더욱 도움이 될 것이라 생각된다.

그리고 예제를 설명하면서 코드에 나오는 C# 프로그래밍 부분은 간단하게만 설명하겠다.

6. Managed DirectDraw 프로그래밍

Page 24: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

1) 윈도우 모드(창 모드) 애플리케이션

using System; using System.Drawing; using System.ComponentModel; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.DirectDraw; namespace DXTest1 { public class Windowed : System.Windows.Forms.Form { private System.ComponentModel.Container components = null; // DirectDraw 관련 객체를 초기화 한다. private Device draw = null; private Surface primary = null; private Surface offscreen = null; private Clipper clip = null; private Rectangle destination = new Rectangle(); //! 이 프로그램의 생성자 public Windowed() { // 생성 할 윈도우를 초기화 한다. InitializeComponent(); // 디바이스를 만든 후 창모드로 지정 후 Surface를 만든다.

① // 윈도우의 가로 길이는 295로 설정. draw = new Device();

draw.SetCooperativeLevel( this, CooperativeLevelFlags.Normal );

② // 표면을 생성한다.

CreateSurfaces(); Width = 295; } // 윈도우 파괴자 protected override void Dispose(bool disposing) { if( disposing ) { if( components != null ) { components.Dispose(); } } base.Dispose(disposing); } private void InitializeComponent() { // 가로:세로 비율울 설정 this.AutoScaleBaseSize = new

Page 25: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

System.Drawing.Size( 5, 13 ); // 윈도우의 클라이언트 영역의 크기를 설정한다. this.ClientSize = new System.Drawing.Size( 292, 266 ); // 타이틀 바에 표시된 텍스트와 윈도우의 이름을 설정하고

이벤트를 등록 한다. this.Name = "Windowed DX";

this.Text = "Windowed DX"; // 윈도우의 사이즈가 변경 될 때의 이벤트 등록

this.Resize += new System.EventHandler( this.Windowed_SizeChanged );

// 윈도우의 사이즈가 변경 완료 되었을 때의 이벤트 등록 this.SizeChanged += new

System.EventHandler( this.Windowed_SizeChanged );

// 윈도우의 그리기 이벤트 등록 this.Paint += new

System.Windows.Forms.PaintEventHandler ( this.Windowed_Paint );

} // 실행한다. static void Main() { Application.Run( new Windowed() ); } ⑥ // 윈도우 내부를 그린다. private void Windowed_Paint( object sender,

System.Windows.Forms.PaintEventArgs e ) { Draw(); }

// 윈도우의 사이즈가 변경 될 때 발생하는 이벤트 함수 private void Windowed_SizeChanged( object sender,

System.EventArgs e ) { Draw(); } // 윈도우 내부에 그리는 함수.

⑦ private void Draw() { if( null == primary ) return; // 윈도우의 크기가 최소화 되었다면 그리지 않는다. if( FormWindowState.Minimized == WindowState ) return; Height = Height < 50 ? 50 : Height; // 사각형의 크기를 윈도우의 클라이언트 영역의 크기로 만든다. destination = new Rectangle( PointToScreen( new

Point(0,0) ), ClientSize );

Page 26: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

try { // 오프 스크린의 그림을 표면 스크린에 그린다. primary.Draw( destination, offscreen,

DrawFlags.Wait ); } // 메모리를 잃어버렸다면 다시 표면을 생성한다. catch( SurfaceLostException )

{ CreateSurfaces(); } } // 표면과 후면 서페이스를 만들고 표면 서페이스에는 클리퍼를 설정 한다. private void CreateSurfaces() { SurfaceDescription description = new

SurfaceDescription(); ③ description.SurfaceCaps.PrimarySurface = true; primary = new Surface( description, draw ); ④ clip = new Clipper(draw); clip.Window = this; primary.Clipper = clip;

description.Clear(); // 후면서페이스에 그림을 로드 한다.

⑤ offscreen = new Surface(DXUtil.SdkMediaPath + "\\earthenvmap.bmp", description, draw );

} } }

Page 27: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

이 소스는 SDK에 있는 예제로 보면 알겠지만 상당히 간단한 프로그램이다.

그러나 MDD의 기본적인 부분은 다 있으므로 이것만 봐도 대충 어떤 식으로 프로

그래밍 하는지 그리고 기존의 DirectDraw7과 얼마나 비슷한지도 알수 있을 것이다.

디바이스 및 그리기 표면 설정

위 예제의 ① 에서 디바이스를 생성한다. 이것을 통해 DirectDraw 개체를 만들고 시스템

레벨의 변수와 같이 작용한다. 직접 하드웨어 접근을 가능하도록 해준다.

그 후 애플리케이션의 최상위 동작을 지정한다. draw = new Device(); draw.SetCooperativeLevel( this, CooperativeLevelFlags.Normal );

public void SetCooperativeLevel( Control parent, CooperativeLevelFlags flags );

첫번째 인자는 지정할 컨트롤(즉 폼(윈도우)를 말한다)이고, 두번째 인자는 최상위

동작 래벨을 뜻한다. 예제에서는 현 폼(윈도우)를 지정하고 윈도우 모드(창 모드)로

지정 하였다. 참고로 Managed DirectX를 이야기 할 때 언급 했지만 현재 SDK에는

이것에 대한 설명은 한 줄 밖에 없다. 그래서 각 인자나 인자에서 사용하는 열거

값은 기존의 DirectDraw7의 SDK를 참고해야만 된다. 다행이 이름이 서로 비슷해

서 찾는데 어렵움은 거의 없다.

②의 Createsurfaces()에서 서페이스와 클리핑 영역을 설정한다.

Page 28: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

SurfaceDescription description = new SurfaceDescription();

SurfaceDescription로 어떤 서페이스를 만들 건지 설정한다. 서페이스의 크기, 메

모리 할당 방법, 전면/후면 설정 등을 한다.

③에서 전면 Surface를 생성한다. 이 Surface가 폼의 화면에 출력된다. description.SurfaceCaps.PrimarySurface = true;

primary = new ( description, draw );

Surface의 생성자는 다음과 같다.

public Surface (Stream, SurfaceDescription, Device)

public Surface (Bitmap, SurfaceDescription, Device)

public Surface (String, SurfaceDescription, Device)

public Surface (SurfaceDescription, Device)

생성자를 통해 메모리, 비트맵 이미지, 파일의 이름 및 Surface 기술자로 생성이

가능하다. 예제에서는 전면 Surface이므로 따로 그려질 내용을 설정하지 않았다.

Surface

④에서 애플리케이션에서 그려질 영역을 설정한다. clip = new Clipper(draw); clip.Window = this; primary.Clipper = clip;

public Clipper (Device)

Clipper 개체를 생성하는 생성자로 Device 개체를 인자로 받는다.

Clipper 개체를 만든 후 Clipper와 관련될 윈도우를 지정한다. 그 후 전면 Surface

의 Clipper에 등록 한다.

⑤후면 Surface를 만들고 후면 Surface에 그림을 그린다. offscreen = new Surface(DXUtil.SdkMediaPath +

"\\earthenvmap.bmp", description, draw );

Surface의 오버로드 된 4개의 함수로 되어 있다.

IOStream을 통해 Surface를 생성할 때 사용

public Surface (Stream, SurfaceDescription, Device)

비트맵 파일을 통해 Surface를 생성할 때 사용. 이미지를 Surface에 그린다.

Page 29: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

public Surface (Bitmap, SurfaceDescription, Device)

파일이름을 통해 Surface를 생성

public Surface (String, SurfaceDescription, Device)

Surface 기술자를 통해 Surface를 생성

public Surface (SurfaceDescription, Device)

이로써 DirectDraw를 사용하도록 하고 그리기 표면의 설정이 끝났다.

이제 후면 Surface를 전면 Surface로 복사하고 전면 Surface를 화면에 출력하

면 된다.

화면에 출력

⑥의 Paint 이벤트의 Draw() 함수에서 후면 Surface에 그려진 이미지를 화면에 출

력 하도록 한다.

⑦에서 폼이 숨겨진 상태 일 때에는 그리기를 중단 시키고 숨겨진 상태가 아니면

현재 폼의 크기에 맞게 후면 Surface에 그려진 이미지를 화면에 출력 하도록 한다. primary.Draw( destination, offscreen, DrawFlags.Wait );

public void Draw( Surface sourceSurface, DrawFlags flags ); DirectDraw7의 IDirectDrawSurface7::Blt 와 같은 기능을 한다. DrawFlags는 관련된

DrawEffects 구조체의 유효한 멤버를 지정하던가 칼라 키 정보를 지정 등 특별한 동작을

요구 할 때 사용하는 열거의 조합이다. DirectDraw7의 4번째 파라메터와 같은 역할을 한다.

그리고 만약 Surface 메모리가 분실 되었다면(Ctrl+Alt+Del 키를 누르면 발생한

다) 다시 Surface를 다시 생성하도록 예외 처리를 한다. catch( SurfaceLostException ) {

CreateSurfaces(); }

예전의 방식에서는 언제나 Surface 표면을 조사하여 분실이 일어나지 않나를 확인

을 해야되는데 MDD에서는 C#의 예외처리로 간단하게 처리한다. 참고로 C#은

C++과 다르게 예외처리를 .NET 자체에서 지원해주므로 예외처리에 의한 성능 감

소는 거의 없다.

필자가 처음 이 예제를 봤을 때 느낀 것은 정말 간단하다는 것이다. 기존의

Page 30: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

DirectDraw은 초기화를 하는데 복잡한 감이 없지 않는데 Managed로 포팅 되면서

.NET의 라이브러리 처럼 간단하게 사용하기 쉽도록 변한 것을 알 수 있었다.

그리고 기존의 유저들의 배려하여 이름이나 전체적인 구조는 기존의 것과 같다는

것이다. 그러나 기존의 것과 비슷해서인지 아니면 MS에서 3D 위주의 정책 때문인

지 레퍼런스가 너무 부실하다. 그래서 Managed DirectDraw를 공부 할려면

DirectDraw7 SDK가 절대 필요 하다는 것이 좀 아이러니 하게 만든다.

2) 전체 모드 및 Surface를 이요한 페이지 플리핑

사실 일반적인 게임에서는 위의 예제와 같은 윈도우 모드 보다는 전체 모드에서 여

러 개의 Surface를 만들어 놓고 이것을 서로 교체하는 식으로 만든다.

이런 방식을 사용한 예제를 토대로 설명 하겠다.

using System;

using System.Windows.Forms;

using System.Drawing;

using Microsoft.DirectX;

using Microsoft.DirectX.DirectDraw;

namespace DXTest2

{

public class MainClass : System.Windows.Forms.Form

{

private System.ComponentModel.Container components = null;

// 스크린의 크기

const int screenWidth = 640;

const int screenHeight = 480;

① Device displayDevice = null; // 디바이스

Surface front = null; // 앞면 서페이스

Page 31: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

Surface back = null; // 뒷면 서페이스

Surface BackGround = null; // 배경 서페이스

Surface SpriteImage = null; // 스프라이트 이미지 서페이스

// 스프라이트가 총 5개이므로 5개의 영역을 잡아 놓는다.

private System.Drawing.Rectangle[] SpriteRect = new

System.Drawing.Rectangle[5];

private int iAniCount = 0; // 스프라이트 번호

private int iFrame = 0; // 프레임

private int iMouseX = 0; // 스프라이트가 그려질 위치 X

private int iMouseY = 100; // 스프라이트가 그려질 위치 Y

static void Main()

{

MainClass mainclass = new MainClass();

Application.Exit();

}

public MainClass()

{

InitializeComponent();

② InitializeDirectDraw();

③ while( Created )

{

GameProc();

Application.DoEvents();

}

}

protected override void Dispose( bool disposing )

Page 32: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

{

if( disposing )

{

if( components != null )

{

components.Dispose();

}

}

base.Dispose( disposing );

}

④ private void GameProc()

{

// 배경의 영역 크기

Rectangle BackRect = new Rectangle( 0, 0, screenWidth,

screenHeight );

// 배경을 뒷면 서페이스에 그린다.

back.DrawFast( 0, 0, BackGround, BackRect, DrawFastFlags.Wait

| DrawFastFlags.NoColorKey );

// 프레임을 설정하고 스프라이트 이미지 번호를 로테이션 시킨다.

++iFrame;

if( iFrame >= 5 )

{

++iAniCount;

if( ++iAniCount >= 5 )

iAniCount = 0;

iFrame = 0;

}

// 뒷면 서페이스에 스프라이트를 그린다.

back.DrawFast( iMouseX, iMouseY, SpriteImage,

SpriteRect[iAniCount], DrawFastFlags.Wait | DrawFastFlags.SourceColorKey );

Page 33: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

// 앞면 서페이스로 뒷면 서페이스를 플립 시킨다.

front.Flip( back, FlipFlags.Wait );

}

private void InitializeComponent()

{

// 키 이벤트와 마우스 이벤트를 등록 한다.

this.KeyUp += new

System.Windows.Forms.KeyEventHandler( this.DxTest2_KeyUp );

this.MouseDown += new

System.Windows.Forms.MouseEventHandler( this.DXTest2_MouseDown );

}

private void DxTest2_KeyUp( object sender,

System.Windows.Forms.KeyEventArgs e )

{

// 'ESC'를 누르면 종료 시킨다.

if( Keys.Escape == e.KeyCode )

Close();

}

private void DXTest2_MouseDown( object sender,

System.Windows.Forms.MouseEventArgs e )

{

// 마우스 왼쪽을 클릭하면 이미지가 그려질 위치를 마우스

위치로 변경한다.

iMouseX = e.X - 50;

iMouseY = e.Y - 35;

}

private void InitializeDirectDraw()

{

// 서페이스 스크립션과 디바이스를 생성

SurfaceDescription description = new SurfaceDescription();

Page 34: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

displayDevice = new Device();

// 전체모드로 설정한다.

displayDevice.SetCooperativeLevel( this,

CooperativeLevelFlags.FullscreenExclusive );

try

{

// 디스플레이 모드를 설정한다.

displayDevice.SetDisplayMode( screenWidth,

screenHeight, 16, 0, false );

}

catch( UnsupportedException )

{

MessageBox.Show( "DirectX 초기화에 실패 하였습니다.",

"최흥배의 Managed DirectX 프로그래밍" );

Close();

return;

}

// 앞면 서페이스를 설정 후 할당 한다.

description.SurfaceCaps.PrimarySurface =

description.SurfaceCaps.Flip = description.SurfaceCaps.Complex = true;

description.BackBufferCount = 1;

front = new Surface( description, displayDevice );

// 뒷면 서페이스를 설정 후 할당 한다.

SurfaceCaps caps = new SurfaceCaps();

caps.BackBuffer = true;

back = front.GetAttachedSurface( caps );

// 스프라이트 서페이스와 배경 서페이스를 그림과 같이 생성

시킨다.

description.Clear();

SpriteImage = new Surface( "Exam3_1.bmp", description,

displayDevice );

Page 35: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

BackGround = new Surface( "Exam3_2.bmp", description,

displayDevice );

// 특별한 칼라키를 지정하지 않았으므로 칼라키는

검은색(0,0,0)이 된다.

ColorKey ck = new ColorKey();

SpriteImage.SetColorKey( ColorKeyFlags.SourceDraw, ck );

// 스프라이트 이미지의 영역을 설정한다.

SpriteRect[0] = new System.Drawing.Rectangle( new

System.Drawing.Point( 0, 0) , new System.Drawing.Size( 100, 70 ) );

SpriteRect[1] = new System.Drawing.Rectangle( new

System.Drawing.Point( 100, 0) , new System.Drawing.Size( 100, 70 ) );

SpriteRect[2] = new System.Drawing.Rectangle( new

System.Drawing.Point( 200, 0) , new System.Drawing.Size( 100, 70 ) );

SpriteRect[3] = new System.Drawing.Rectangle( new

System.Drawing.Point( 300, 0) , new System.Drawing.Size( 100, 70 ) );

SpriteRect[4] = new System.Drawing.Rectangle( new

System.Drawing.Point( 400, 0) , new System.Drawing.Size( 100, 70 ) );

}

void RestoreSurfaces()

{

SurfaceDescription description = new SurfaceDescription();

displayDevice.RestoreAllSurfaces();

SpriteImage.Dispose();

SpriteImage = null;

SpriteImage = new Surface( "Exam3_1.bmp", description,

displayDevice );

ColorKey ck = new ColorKey();

SpriteImage.SetColorKey( ColorKeyFlags.SourceDraw, ck );

BackGround.Dispose();

BackGround = null;

Page 36: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

BackGround = new Surface( "Exam3_2.bmp", description,

displayDevice );

return;

}

}

}

이 예제는 5개의 그림을 애니메이션 시키는 프로그램이다.

① 에서 프로그램에서 사용할 변수를 선언한다. 전면, 후면, 배경, 스프라이트 이

미지 Surface를 선언한다.

②의 InitializeDirectDraw() 함수에서 DirectDraw 초기화 및 설정을 한다.

첫 예제와 다르게 전체 모드로 설정한다.

displayDevice.SetDisplayMode( screenWidth, screenHeight, 16, 0, false );

해상도 크기를 640,480 크기에 16비트 모드로 설정한다.

public void SetDisplayMode(

int width, // 넓이

int height, // 높이

int bitPerPixel, // 픽셀 단위

int refreshRate, // 갱신 률

bool standardVgaMode // VgaMode 여부

);

전면과 후면 Surface를 설정 후 배경과 스프라이트 이미지 Surface를 만든다.

SpriteImage = new Surface( "Exam3_1.bmp", description, displayDevice );

BackGround = new Surface( "Exam3_2.bmp", description, displayDevice );

그런 후 스프라이트 그림에서 그려지질 않을 색상을 지정한다.

ColorKey ck = new ColorKey();

SpriteImage.SetColorKey( ColorKeyFlags.SourceDraw, ck );

하드웨어가 Surface에 칼라 키를 지정할 수 있는 경우 사용한다.

public void SetColorKey(

Page 37: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

ColorKeyFlags flags, // 요구 되는 칼라 키

ColorKey value // 칼라 값

);

이후 각 스프라이트 이미지의 영역을 설정 한다.

③에서 프로그램이 종료(ESC 키를 누른다) 할 때까지 무한으로 스프라이트 이미지

를 애니메이션 될 순서대로 그린다.

while( Created )

{

GameProc();

Application.DoEvents();

}

Application.DoEvents() 이 함수는 비주얼 베이직을 해본 사람은 알겠지만 이 프로

그램이 혼자 시스템을 독점 하지 못하도록 시스템에 권한을 잠시 넘겨주는 것이다.

④ GameProc()에서 각 Surface를 플리핑 시키면서 애니메이션된 이미지를 출력 하

게 한다.

private void GameProc()

{

// 배경의 영역 크기

Rectangle BackRect = new Rectangle( 0, 0, screenWidth, screenHeight );

// 배경을 뒷면 서페이스에 그린다.

back.DrawFast( 0, 0, BackGround, BackRect, DrawFastFlags.Wait |

DrawFastFlags.NoColorKey );

// 프레임을 설정하고 스프라이트 이미지 번호를 로테이션 시킨다.

++iFrame;

if( iFrame >= 5 )

{

++iAniCount;

if( ++iAniCount >= 5 )

iAniCount = 0;

iFrame = 0;

}

Page 38: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

// 뒷면 서페이스에 스프라이트를 그린다.

back.DrawFast( iMouseX, iMouseY, SpriteImage, SpriteRect[iAniCount],

DrawFastFlags.Wait | DrawFastFlags.SourceColorKey );

// 앞면 서페이스로 뒷면 서페이스를 플립 시킨다.

front.Flip( back, FlipFlags.Wait );

}

먼저 배경 이미지의 크기를 정한 후 배경을 그린다.

back.DrawFast( 0, 0, BackGround,BackRect,DrawFastFlags.Wait |

DrawFastFlags.NoColorKey );

DrawFastr는 DirectDraw7의 DirectDrawSurface7.BltFast와 같은 기능을 한다.

public void DrawFast(

int xcoord, // 목적지의 x 좌표

int ycoord, // 목적지의 좌표

Surface sourceSurface, // 소스 Surface

Rectangle srcRectangle, // 소스 Surface에서 목적지 Surface에 그려질 영역

DrawFastFlags flags // 전송 타입

);

예제에서는 배경으로 사용되는 Surface 전체를 칼라 키 지정 없이 그리고 있다.

후면 Surface에 스프라이트로 사용되는 Surface의 일부 영역을 각 프레임마다 다

르게 지정하여 그린다. 스프라이트를 그릴 때는 배경은 그려지면 안되기 때문에 투

명 칼라 키를 지정한다.

다 그려졌다면 플리핑으로 후면 Surface를 전면 Surface에 그린다.

front.Flip( back, FlipFlags.Wait );

BackBuffer Surface 와 관련된 Surface 메모리를 전면 Surface 에 붙인다.

public void Flip(

Surface surface, // Flip 할 Surface

FlipFlags flags // Flip 옵션

);

이로써 매 프레임마다 스프라이트 이미지를 그리는 프로그램이 완성 되었다.

Page 39: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

이 예제도 위의 예제처럼 복잡하던가 어려운 부분이 없어 이해가 되리라 생각된다.

다만 필자는 사실 이 예제를 기존의 DirectDraw를 조금이라도 알고 있다는 가정하

게 적었기 때문에 처음 접하는 사람에게는 어려움이 있으리라도 생각되기도 한다.

그러나 기존의 DirectDraw를 조금만 참고만 하면 금방 이해 할 것이다.

3) Surface에 직접 접근

Managed DirectDraw도 기존의 DirectDraw와 같이 Surface 메모리에 직접 접근

하여 그릴 수 있다. 그러나 .NET이 C++에 비해 포인터 접근이 좀 까다로워서 사

용하는 방법을 약간 다르게 해야 된다.

Array lpbuffer[][];

Surface back;

…………..

// 메모리를 잠근다. lpbuffer = back.Lock( LockFlags.Wait | LockFlags.SurfaceMemoryPointer ); for( int k = 200; k < 480; ++k ) {

// 두 개의 선을 긋는다. lpbuffer.SetValue( 0xff22, 100, k ); lpbuffer.SetValue( 0xff22, 200, k ); }

// 메모리를 푼다. back.Unlock( lpbuffer );

Surface의 메모리를 조작 할 수 있다.

public Byte Lock (LockFlags)

public Byte Lock (Rectangle, LockFlags)

Managed 방식에서는 Lock을 걸어 2차원 Array 형으로 영역을 얻어서 x,y 좌표

를 가르키는 배열에 그리면 된다. 그러나 내부적으로 2의 제곱수의 크기의

Page 40: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

Surface에만 x,y 좌표를 1:1 접근이 가능하지 Surface의 넓이와 크기가 2의

제곱수가 아니면 선이 삐뚤 하게 출력 되었다. 이건 아마 MS에서 성능을 좋게

하기 위해서 3D의 텍스쳐 크기 지정방식과 같게 한 것 같다. 필자가 해보지는 않았

지만 Array를 Byte에 다시 담아서 비디오 카드의 실제 lPitch 값을 사용하여

접근하면 되지 않을까 싶지만 이렇게 하는 게(.NET에서는 포인터 접근이 꽤

까다롭다) 너무 까다로워 지기 때문에 편하게 2의 제곱수의 크기의 Surface를

사용 하는 게 훨씬 좋다( 필자는 처음에 x,y 좌표에 1:1로 맵핑 되는 걸로 알아서

그렇게 했는데 선이 이상하게 나와서 조금 헤매기도 했다. 혹시나 하는 마음에

2의 제곱수의 크기를 사용하니 제대로 나왔다..-_- ).

이것으로 Managed DirectDraw의 중요 부분은 간단하게 설명이 된 것 같다. 보통

위에서 설명한 부분이 프로그래밍에서 주로 쓰이기 때문에 Managed DirectDraw가

어떤 식으로 프로그래밍 되는지 알 수 있으리라 생각된다.

참고로 이번에 나온 DirectX SDK SummerUdate 2004에서 Managed DirectDraw

가 예제도 삭제되어 버려서 좀 난감했다. 대세가 3D 인지라 MS에서는 2D도 3D에

서 구현하기를 원하는 것 같다. 그러나 아직 3D에 익숙하지 않은 사람은

DirectDraw가 훨씬 접근 하기가 편할 것이다. 그리고 3D를 잘 알던가 관심이 있는

사람은 Managed Direct3D에서의 2D 프로그래밍을 공부 하는 것도 좋으리라 생각

된다.

필자는 개인적으로 아는 사람과 액션 게임을 하나 만들려고 하고 있는데 처음에는

DirectDraw로 만들려고 했다가 이번 SDK 때문에 Managed Direct3D를 사용 하여

3D에서 2D 프로그래밍으로 만들지 고민 중 이다.

7. 끝으로….

이것으로 .NET 플랫폼에서의 그래픽 프로그래밍에 대한 글을 마치려고 한다.

이 글은 정말 부족한 부분이 너무 많다. 필자의 글을 못 적는 실력과, 프로그래밍

기술 부족, 시간 부족이 겹치다 보니 이렇게 질이 떨어지는 논문이 나와버렸다.

제일 처음 소개한 GDI+ 프로그래밍만 하더라도 그 양이 만만치 않아 간추리기가

힘들었고 Managed DirectX의 경우에는 필자는 지금의 회사에서는 서버/클라이언트

를 다 하지만 원래 서버 담당이었고 회사에서도 DirectX 부분은 거의 사용을 하지

않아 경험이나 기술적인 이해가 부족한 편이었어 꼭 필요한 부분은 매끄럽게 적지

못했다. 그리고 원래대로 라면 Managed Direct3D도 할려고 했으나 이 부분은 시

Page 41: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

간이 너무 부족하여 도저히 쓸 수가 없었다. 사실 어찌 보면 지금의 게임 프로그래

머에게는 3D 부분이 가장 필요할 듯 한데 이 부분을 다루지 못해서 너무 아쉽다.

아직 .NET이 데스크탑 환경에서는 제대로 활성화 되지 않았어 사실 지금은 필요하

지 않을지도 모른다. 그러나 앞을 생각하면 꼭 하면 공부하기를 바란다. 바로 MS에

서 그리도 주장하는 롱혼 이라는 OS 때문이다. 이놈의 API는 기존의 Win32 API가

아닌 .NET의 라이브러리를 확장한 WinFX를 사용한다. 지금부터 .NET을 공부하여

잘 이해한 사람은 롱혼에서 무리 없이 적응하겠지만 그렇지 못한 프로그래머는 예

전의 도스에서 Window95 플랫폼에서 넘어 올 때 적응 하지 못해 낙오된 프로그래

머가 될 확률이 높다.

또 Managed DirectX는 기존의 DirectX에 사용하기도 편해서 생산성이 훨씬 좋아

진다. 현재의 방식은 개발에 너무 많은 시간을 소요하기 때문에 생산성을 무시 하

지 못한다. 외국의 게임 회사들도 이 점을 상당히 중요하게 인식하고 있다.

그리고 성능도 기존의 것과 큰 차이는 없다. 물론 아직은 기존의 방식보다는 좀 느

리지만 차기 버전에서는 그 차이도 거의 없어지리라 생각된다( 참고로 예전에 퀘이

크2가 포팅된 적이 있는데 이건 정말 .NET에 대한 성능을 고려하지 않고 포팅된

것이라서 성능이 많이 떨어진다. 잘못된 방식으로 포팅을 했기 때문에 .NET의 대

한 이해를 가지고 포팅을 해야 제대로된 성능을 낸다).

Managed DirectX에 대한 MS의 생각을 알고 싶다면 다음의 글을 읽어보기를 바란

다.

.NET Show : Managed DirectX 인터뷰

그리고 .NET용 프로그램의 성능 튜닝에 대한 글은 아래에 잘 나와 있다.

.NET 애플리케이션의 성능 관련 힌트와 트릭

필자는 개인적으로 게임을 만들려고 하고 있는데 그 게임을 Managed DirectX를

사용하여 만들려고 한다. 게임에서 사용하는 툴은 GDI+를 사용하여 만들고 간단한

보드 게임은 Managed DirectDraw를 사용하고, 효과를 많이 사용하는 게임은

Managed Direct3D를 사용하여 만들려고 한다. 게임을 만들면 꼭 필자의 홈페이지

에 올릴 테니 참고하기를 바라며 그리고 이번 글에서 적지 못한 3D에 관한 글도

꼭 시간을 내어 필자의 홈페이지에 올리겠다.

일본의 MS 사이트에서는 별도의 Managed DirectX 포럼이 있어 다양한 의견을 나

누고 있으면 관련된 컬럼도 꾸준히 올라 오고 있다. 우리나라는 내가 알기로 아직

은 이런 사이트가 없는 것으로 아는데 Managed DirectX에 관심이 있는 사람들 끼

Page 42: < .NET 플랫폼에서의 2D 그래픽 프로그래밍 >cfs7.tistory.com/upload_control/download.blog?fhandle=YmxvZzE4MDA0... · < .NET 플랫폼에서의 2D 그래픽 프로그래밍

리 서로 정보를 교환하여 빠르게 관련된 기술을 쌓았으면 좋겠다고 생각한다.

본문에서 참고한 출처

1. .NET Framework SDK 도움말

2. GDI+ Programming:C#을 이용한 사용자 지정 컨트롤 작성하기 – 정보문화사

3. DirectX SDK

4. Windows 게임프로그래머를 위한 X파일 – 사이버출판사

5. 필자의 홈페이지 http://jacking75.cafe24.com

6. 일본 마이크로소프트 DirectX 홈 페이지 :

http://www.microsoft.com/japan/msdn/directx/default.asp