관리 메뉴

Kim's Programming

[다이렉트SDK 예제]DirectX Tutorial1 - CreateDevice 본문

Programming/DirectX

[다이렉트SDK 예제]DirectX Tutorial1 - CreateDevice

Programmer. 2016. 4. 14. 23:01
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//-----------------------------------------------------------------------------
// File: CreateDevice.cpp
//
// Desc: This is the first tutorial for using Direct3D. In this tutorial, all
//       we are doing is creating a Direct3D device and using it to clear the
//       window.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include <d3d9.h>
#pragma warning( disable : 4996 // disable deprecated warning 
#include <strsafe.h>
#pragma warning( default : 4996 )
 
 
 
 
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9         g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9   g_pd3dDevice = NULL; // Our rendering device
 
 
 
 
//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
    // Create the D3D object, which is needed to create the D3DDevice.
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;
 
    // Set up the structure used to create the D3DDevice. Most parameters are
    // zeroed out. We set Windowed to TRUE, since we want to do D3D in a
    // window, and then set the SwapEffect to "discard", which is the most
    // efficient method of presenting the back buffer to the display.  And 
    // we request a back buffer format that matches the current desktop display 
    // format.
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof( d3dpp ) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
 
    // Create the Direct3D device. Here we are using the default adapter (most
    // systems only have one, unless they have multiple graphics hardware cards
    // installed) and requesting the HAL (which is saying we want the hardware
    // device rather than a software one). Software vertex processing is 
    // specified since we know it will work on all cards. On cards that support 
    // hardware vertex processing, though, we would see a big performance gain 
    // by specifying hardware vertex processing.
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }
 
    // Device state would normally be set here
 
    return S_OK;
}
 
 
 
 
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
    if( g_pd3dDevice != NULL )
        g_pd3dDevice->Release();
 
    if( g_pD3D != NULL )
        g_pD3D->Release();
}
 
 
 
 
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
    if( NULL == g_pd3dDevice )
        return;
 
    // Clear the backbuffer to a blue color
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 00255 ), 1.0f, );
 
    // Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        // Rendering of scene objects can happen here
 
        // End the scene
        g_pd3dDevice->EndScene();
    }
 
    // Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
 
 
 
 
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            Cleanup();
            PostQuitMessage( );
            return 0;
 
        case WM_PAINT:
            Render();
            ValidateRect( hWnd, NULL );
            return 0;
    }
 
    return DefWindowProc( hWnd, msg, wParam, lParam );
}
 
 
 
 
//-----------------------------------------------------------------------------
// Name: wWinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
    UNREFERENCED_PARAMETER( hInst );
 
    // Register the window class
    WNDCLASSEX wc =
    {
        sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
        GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
        L"D3D Tutorial", NULL
    };
    RegisterClassEx( &wc );
 
    // Create the application's window
    HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice",
                              WS_OVERLAPPEDWINDOW, 100100300300,
                              NULL, NULL, wc.hInstance, NULL );
 
    // Initialize Direct3D
    if( SUCCEEDED( InitD3D( hWnd ) ) )
    {
        // Show the window
        ShowWindow( hWnd, SW_SHOWDEFAULT );
        UpdateWindow( hWnd );
 
        // Enter the message loop
        MSG msg;
        while( GetMessage( &msg, NULL, 0) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }
 
    UnregisterClass( L"D3D Tutorial", wc.hInstance );
    return 0;
}
cs



 - 전역변수


1
2
3
4
5
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9         g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9   g_pd3dDevice = NULL; // Our rendering device
cs


다이렉트X는 그래픽 카드를 이용합니다. 그렇기 때문에 그래픽 카드에 접근할 무언가가 필요하게 되는데요. 바로 그때 이용하는 것이 LPDIRECT3DEVICE9 구조체입니다. LPDIRECT3DEVICE9의 정의를 직접 따라 들어가다 보면 앞에 LP가 붙은거 처럼 포인터를 이용한다는 것을 알 수 있게 되는데 이 이유는 그래픽카드는 컴퓨터에 하나만 존재하지 않을 수도 있기 떄문입니다. 여전히 지금도 그래픽카드는 컴퓨터 1대당 1대가 달려있는게 일반적인데(내장1개 외장 1개 라서 2개인 개념이 아닙니다. Nvidia의 SLI 나 Radeon사의 CrossFire 같은 걸 의미합니다) 꼭 1대만 들어있지는 않기 때문에 포인터를 이용하여 접근하게됩니다. 그 위에 있는 LPDIRECT3D9는 다이렉트X용 구조체를 생성하며 역시나 포인터를 이용합니다.


- InitD3D(HWND hWnd)


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
//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
    // Create the D3D object, which is needed to create the D3DDevice.
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;
 
    // Set up the structure used to create the D3DDevice. Most parameters are
    // zeroed out. We set Windowed to TRUE, since we want to do D3D in a
    // window, and then set the SwapEffect to "discard", which is the most
    // efficient method of presenting the back buffer to the display.  And 
    // we request a back buffer format that matches the current desktop display 
    // format.
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof( d3dpp ) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
 
    // Create the Direct3D device. Here we are using the default adapter (most
    // systems only have one, unless they have multiple graphics hardware cards
    // installed) and requesting the HAL (which is saying we want the hardware
    // device rather than a software one). Software vertex processing is 
    // specified since we know it will work on all cards. On cards that support 
    // hardware vertex processing, though, we would see a big performance gain 
    // by specifying hardware vertex processing.
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }
 
    // Device state would normally be set here
 
    return S_OK;
}
cs


다이렉트 X를 초기화 해주는 부분입니다. 다이렉트 X는 사용하기 전에 DirectX SDK중에서 몇 버전을 쓰는지 명시되어야 합니다. 첫 조건문은 다이렉트 구조체가 몇 버전인지 명시해주는 역할을 합니다. 다음의 D3DPRESENT_PARAMETERS 구조체는 위에 있었던 LPDIRECT3DEVICE9로 만든 객체에 들어갈 파라메터들이 있는 구조체입니다. 그냥 직접 대입하지 않고 이를 이용하여 대입해주기 위해 만들어져있는 존재합니다.  ZeroMemoey를 통하여 초기화를 해주며 Windowed, SwapEffect, BackBufferFormat 에 대하여 조건을 주었습니다. D3DPRESENT_PARAMETERS구조체는 다음과 같이 이루어져 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _D3DPRESENT_PARAMETERS_
{
    UINT                BackBufferWidth;
    UINT                BackBufferHeight;
    D3DFORMAT           BackBufferFormat;
    UINT                BackBufferCount;
 
    D3DMULTISAMPLE_TYPE MultiSampleType;
    DWORD               MultiSampleQuality;
 
    D3DSWAPEFFECT       SwapEffect;
    HWND                hDeviceWindow;
    BOOL                Windowed;
    BOOL                EnableAutoDepthStencil;
    D3DFORMAT           AutoDepthStencilFormat;
    DWORD               Flags;
 
    /* FullScreen_RefreshRateInHz must be zero for Windowed mode */
    UINT                FullScreen_RefreshRateInHz;
    UINT                PresentationInterval;
} D3DPRESENT_PARAMETERS;
cs

원하는 부분에 대해서 지정해주면 됩니다. 현재 이 예제에서는 Windowed에 TRUE를 주어 윈도우 창이 뜰 수 있도록 하고 SwapEffect를 discard(즉 포기)하겠다고 하였으며 BackBufferFormat 백 버퍼의 포멧은 현재 데스크톱에 맞추기 위해여 D3DFMT_UNKNOWN(지정 되지 않았으니 알아서 찾아라 라는 뜻)을 주었습니다.


다음은 DirectX 구조체를 생성했으니 DirectX장치(즉 그래픽 카드)를 생성할 차례입니다. CreateDevice를 이용하여 그래픽 카드를 생성해주게 됩니다. 다중 그래픽 카드가 설치 되어 있지 않는 한은 대부분 그래픽 카드를 하나를 가지고 있기 떄무넹 기본 어댑터를 이용합니다. 그리고 그런 상황을 HAL(Hardware Abstraction Layer)에 요청합니다. 이러한 것들을 하는 과정이 마지막에 있는 조건문의 내용입니다.


Init3D함수에서는 E_FAIL, S_OK, FAILED 등이 보이는데 이는 FAILED함수를 이용할 떄 E_FAILED를 리턴받으면 오류가 생겼다 이런식으로 오류를 판별하기 위해서 작성해둔 함수와 변수입니다. 직접 정의로 이동하면

1
2
3
4
5
6
7
8
//
// MessageId: E_FAIL
//
// MessageText:
//
// Unspecified error
//
#define E_FAIL                           _HRESULT_TYPEDEF_(0x80004005L)
cs

다음과 같이 정의되어 있음을 확인 할 수 있습니다.



- Cleanup()

1
2
3
4
5
6
7
8
9
10
11
12
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
    if( g_pd3dDevice != NULL )
        g_pd3dDevice->Release();
 
    if( g_pD3D != NULL )
        g_pD3D->Release();
}
cs


Cleanup()함수는 만들었던 포인터들을 정리해주는 함수입니다. C언어에서 동적할당으로 만든변수를 끝에가서 동적해제를 해주듯이 DirectX에서도 할당한 변수들을 해제하게됩니다.


- Render()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
VOID Render()
{
    if( NULL == g_pd3dDevice )
        return;
 
    // Clear the backbuffer to a blue color
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 00255 ), 1.0f, );
 
    // Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        // Rendering of scene objects can happen here
 
        // End the scene
        g_pd3dDevice->EndScene();
    }
 
    // Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
cs



Render()함수는 화면을 매 프레임마다 그려주는 함수입니다. 첫 초건문에 g_pd3dDevice가 NULL인지 확인하여 그래픽카드가 생성되었는지(여기서는 InitD3D에서 생성함) 확인을 하는 과정입니다. 그 다음중에서는 g_pd3dDevice의 Clear함수를 통해서 BackBuffer를 파란색으로 초기화 합니다. 다음 조건문부터 그 조건문 안에 있는 EndScene()까지에는 렌더링 할 내용을 넣어주면 됩니다. 마지막 중에 있는 Present를 이용하여 백 버퍼의 내용을 출력하게됩니다.


 

- MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            Cleanup();
            PostQuitMessage( );
            return 0;
 
        case WM_PAINT:
            Render();
            ValidateRect( hWnd, NULL );
            return 0;
    }
 
    return DefWindowProc( hWnd, msg, wParam, lParam );
}
cs


윈도우즈는 메세지 시스템으로 돌아 갑니다. 그 부분을 처리해주는 함수입니다.



- wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )


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
//-----------------------------------------------------------------------------
// Name: wWinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
    UNREFERENCED_PARAMETER( hInst );
 
    // Register the window class
    WNDCLASSEX wc =
    {
        sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
        GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
        L"D3D Tutorial", NULL
    };
    RegisterClassEx( &wc );
 
    // Create the application's window
    HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice",
                              WS_OVERLAPPEDWINDOW, 100100300300,
                              NULL, NULL, wc.hInstance, NULL );
 
    // Initialize Direct3D
    if( SUCCEEDED( InitD3D( hWnd ) ) )
    {
        // Show the window
        ShowWindow( hWnd, SW_SHOWDEFAULT );
        UpdateWindow( hWnd );
 
        // Enter the message loop
        MSG msg;
        while( GetMessage( &msg, NULL, 0) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }
 
    UnregisterClass( L"D3D Tutorial", wc.hInstance );
    return 0;
}
cs


wWinMain함수는 윈도우 프로그래밍에서 C언어의 main함수와 같은 역할을 하며 기본적인 윈도우를 생성하고 제목 등등을 설정합니다.

위의 긴 녀석들 전체의 결과는 황당하게도 다음과 같습니다.




지금까지의 과정은 단순히 DirectX 창 하나를 만들기 위해서 이렇게 길게 만들었지만. 다음 예제부터 본격적으로 활용하게됩니다.