DirectX11
2DLibrary 정리 1차
치킨CEO
2019. 10. 31. 18:18
4월 중순부터 시작해 현재까지 만든 2D 게임의 라이브러리다. DirectX를 사용하며, 이후 이미지 또한 DirectX를 통해 관련 기능을 추가할 것이다.
1. ClassDiagram





현재까지 만든 라이브러리의 클래스 다이어그램이다. 각 매니저들은 싱글턴 템플릿 클래스를 상속 받아서 싱글턴 패턴을 사용하고 있다. 매니저가 다른 곳에 객체가 생성되면 위험하기 때문에 싱글턴 패턴을 사용했다. 매니저들 밑에 클래스가 있는데 이 클래스들은 바로 위에 있는 매니저의 멤버 변수로 사용되고 있다.
이 매니저들은 SCore에서 사용하고 있다. SCore는 SDevice와 SWindow를 상속 받고 있다. SDevice는 DirectX의 초기화를 담당하는 클래스이며, SWindow는 창을 띄우는 역할을 담당하는 클래스이다. SCore는 이 둘의 기능을 가지고 게임 프레임 워크 기능을 담당하고 있다.
2. Core Class
2-1 SDevice
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
|
class SDevice
{
public:
//==============================================================================================
// DirectX Interface Pointer
//==============================================================================================
ID3D11Device* m_pD3DDevice; // DirectX Interface Device ver.11 ( Resource )
ID3D11DeviceContext* m_pImmediateContext; // DirectX Interface DeviceContext ver.11 ( Rendering )
ID3D11RenderTargetView* m_pRenderTargetView; // DirectX Interface RenderTargetView ver.11 ( Camera )
IDXGIFactory* m_pDxgiFactory; // DirectX Interface Factory ( Create Interface )
IDXGISwapChain* m_pDxgiSwapChain; // DirectX interface SwapChain ( Buffers )
//==============================================================================================
// DirectX Enum or Structure
//==============================================================================================
D3D_DRIVER_TYPE m_DriverType; // Device Type
D3D_FEATURE_LEVEL m_FeatureLevel; // Device Feature Level
D3D11_VIEWPORT m_ViewPort; // ViewPort
BOOL m_IsFullSceenMode; // FullScreen Flag
public:
//==============================================================================================
// Getter and Setter Functions
//==============================================================================================
BOOL GetFullScreenModeFlag() { assert(m_IsFullSceenMode); return m_IsFullSceenMode; }
void SetFullScreenModeFlag(BOOL bFlag){ m_IsFullSceenMode = bFlag; }
ID3D11Device* GetDevice() { assert(m_pD3DDevice); return m_pD3DDevice;}
ID3D11DeviceContext* GetContext(){ assert(m_pImmediateContext); return m_pImmediateContext; }
ID3D11RenderTargetView* GetRenderTargetView(){ assert(m_pRenderTargetView); return m_pRenderTargetView; }
IDXGIFactory* GetFactory() { assert(m_pDxgiFactory); return m_pDxgiFactory; }
IDXGISwapChain* GetSwapChain() { assert(m_pDxgiSwapChain); return m_pDxgiSwapChain ; }
public:
//==============================================================================================
// Initialize Function
//==============================================================================================
HRESULT InitDevice(HWND hWnd, UINT iWidth, UINT iHeight, BOOL isFullScreen = FALSE); // Initialize Enter Fuction
//==============================================================================================
// Create Device and SwapChain
//==============================================================================================
HRESULT CreateDevice(); // Create Device Instance
HRESULT CreateGIFactory(); // Create Factory Instance
HRESULT CreateSwapChain(HWND hWnd, UINT iWidth, UINT iHeight, BOOL IsFullScreen); // Create SwapChain Instance
//==============================================================================================
// Setting RenderTargetView and ViewPort
//==============================================================================================
HRESULT SetRenderTargetView(); // Create RanderTargetView
HRESULT SetViewPort(); // ViewPort Binding
public:
HRESULT ReSizeDevice(UINT iWidth, UINT iHeight); // Resize Device
bool CleanupDevice(); // Release this
public:
SDevice();
virtual ~SDevice();
};
|
cs |
SDevice는 DirectX를 사용하기 위해 초기화와 설정에 관련된 기능을 가지고 있다. DirectX의 장치에 관련된 인터페이스들을 멤버 변수로 들고 있다. 이 변수들이 없으면 화면에 이미지를 띄우는 것도 불가능하고, 관련 리소스도 사용할 수 없다.
- 초기화
SDevice에서 초기화과정은 다음과 같다.

CreateGIFactory() 함수는 CreateDevice 안에서 호출되지만, 순서상 위의 그림과 같다. InitDevice()함수로 한번에 처리되며, 하나라도 오류가 나면 반환값을 false로 반환해 프로그램을 종료시킨다.
- CreateDevice()
CreateDevice() 함수는 ID3D11Device와 ID3D11DeviceContext를 생성하기 위해 있는 함수이다. ID3D11Device는 리소스를 관리하는 클래스로서 DirectX에 관련된 리소스는 이 인터페이스 클래스로 생성된다. ID3D11DeviceContext는 렌더링을 담당하는 클래스이다. 이 클래스들을 생성하기 위해서는 드라이버 타입과 특성 레벨 배열을 설정해줘야 한다. 다음은 CreateDevice()의 작동 과정이다.

(1) Create Feature Level Array
특성 레벨(Feature Level)의 배열을 만든다. 특성 레벨이란 DirectX가 지원하는 버전이다. 이 특성 레벨이 높을 수록 사용할 수 있는 쉐이더 기능이 달라진다다. 단순히 높은 버전을 설정한다고 모든 하드웨어에 지원되지 않는다. 하드웨어에 따라서 지원되는 특성 레벨이 다르다. 이걸 확인하기 위해서 특성 레벨의 배열을 만드는 것이다.
(2) Create Driver Type
드라이버 타입(Driver Type)은 어댑터(그래픽 카드)의 종류를 뜻한다. 그래픽을 지원하는데 그래픽 카드를 사용하는지, 아니면 소프트웨어를 지원하는지 알 수 있다. 소프트웨어로 지원하는 것도 어떤 방식인가에 따라서 종류가 나뉘어진다. Device를 생성하기 위해서 무엇을 지원하는지 알아야 하기 때문에 드라이버 타입의 배열을 만든다.
(3) Create Device Loop
Driver Type Array의 크기만큼 반복한다. 생성에 성공하거나 드라이버 타입 배열을 전부 확인할때 반복문에서 빠져나온다. 전부 확인 했는데도 Device가 생성이 안되면 해당 게임을 플레이가 불가하기 때문에 반환 값을 false로 넘긴다.
- CreateGIFactory()
reateGIFactory() 함수는 IDXGIFactory를 생성하기 위한 함수이다. 특별히 다른 조건 없이 GIFactory를 생성한다. 이 GIFactory는 다른 Direct Interface 객체들을 생성할 수 있는 클래스이다. 여기서는 SwapChain을 생성하기 위해서 Factory를 생성했다.
- CreateSwapChain()
CreateSwapChain()은 스왑체인을 생성하기 위한 함수이다. SwapChain을 생성하기 위해서는 Factory가 생성되어 있어야 한다. 다른 방법으로 생성이 가능하지만, 제일 무난하게 생성할 수 있는 방법이 Factory를 사용하는 방법이다. SwapChain은 SwapChain Descriptor가 존재한다. 이 디스크립터를 설정해서 생성할때 넘겨줘야 SwapChain생성이 가능하다. SwapChain은 Rendering 하기 위한 버퍼를 관리하기 때문에 윈도우가 생성되지 않으면 생성할 수 없다.
- SetRenderTargetView()
SetRenderTargetView()는 RenderTargetView를 셋팅하는 함수이다. 렌더링 될 백 버퍼의 메모리를 관리하는 인터페이스이기 때문에 화면을 출력하려면 RenderTargetView를 설정해줘야 한다. 다음은 함수의 동작 과정이다.

(1) GetBuffer
스왑체인으로부터 버퍼를 얻는다. 임시로 ID3D11Texture2D 포인터를 생성해서 얻는다
(2) RenderTargetView Set Buffer
렌더 타겟 뷰에 버퍼를 셋팅한다. 이후 ID3D11Texture2D 포인터는 꼭 Release를 해줘야 한다. 그렇지 않으면 프로그램 종료 이후에도 참조 상태가 되어 메모리 누수가 일어난다.
(3) DeviceContext Set RenderTargetView
디바이스 컨텍스트에 렌더 타겟 뷰를 설정한다.
- SetViewPort()
SetViewPort()은 뷰포트(ViewPort)를 설정하는 함수이다. 뷰포트란 스크린의 어떤 위치에 작업한 내용을 표시할 것인지 구역을 설정하는 구조체이다. 이 구조체 또한 DeviceContext에 등록한다.
- 크기 조절
화면 크기 조절을 위해 ResizeDevice를 이용한다. 이 함수는 다음과 같은 과정을 거친다.

(1) Release RTV and Depth
렌더 타겟과 깊이 스텐실 버퍼를 해제한다.
(2) SwapChain Resize Buffer
스왑체인의 디스크립터를 받아 놓은 후 버퍼의 크기를 재설정할때 사용한다.
(3) Set RTV and ViewPort
렌더 타겟 뷰와 뷰포트를 다시 설정한다.
2-2 SWindow
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
|
class SWindow : public SDevice
{
public:
//=================================================================================================
// Handler
//=================================================================================================
HWND m_hWnd; // Window Handle
HINSTANCE m_hInstance; // Window Instance Handle
//=================================================================================================
// Window Value
//=================================================================================================
TCHAR* m_lpszClientName; // Window Name String
DWORD m_dwWindowStyle; // WIndow Style
RECT m_rcWindowBounds; // WIndow Size;
//=================================================================================================
// Client Size
//=================================================================================================
RECT m_rcClientRect; // Client Size
UINT m_nWindowWidth; // Window Width Size
UINT m_nWindowHeight; // Window Height Size
public:
//=================================================================================================
// Window Fuction
//=================================================================================================
virtual int WindowProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
// virtual Window Procedure
LRESULT WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
// Window Procedure
bool InitWindow(HINSTANCE hInstance, int iCmdShow, TCHAR* lpszClientName, BOOL IsFullScreen = FALSE);
// Window Initialize
void CenterWindow(HWND hWnd);
// Set Window Position to Center
public:
//=================================================================================================
// Game FrameWork
//=================================================================================================
virtual bool Run(); // Enter the Game FrameWork
virtual bool Init() { return true; } // Initialize
virtual bool Frame() { return true; } // Process
virtual bool Render() { return true; } // Draw
virtual bool Release() { return true; } // Clear
public:
SWindow();
virtual ~SWindow();
};
|
cs |
SWindow는 윈도우의 창과 윈도우 메세지를 관리하는 역할을 맡고 있다. Device 이전에 초기화가 되어있어야 하며, 이 클래스가 없이 다른 어떠한 작업이 불가능하다.
- InitWindow()
InitWindow() 함수는 윈도우를 생성 및 초기화 하는 함수이다. 이 라이브러리를 사용하려면 이 함수가 제일 먼저 실행되어야 한다. 이 함수의 동작 과정은 다음과 같다.
(1) Register Window Class
윈도우 정보를 등록한다. Window Class를 설정한 후 이 클래스를 등록시킨다. 주의할 점은 ClassName으로 후에 생성할 윈도우를 식별하기 때문에 ClassName은 잘 관리되어야 한다.
(2) Create Window
윈도우를 생성한다. 생성할 때 등록한 ClassName과 같아야한다. 윈도우를 생성하면 윈도우 핸들이 반환된다.
(3) Show Window
윈도우를 화면에 띄운다.
- WndProc()
WndProc()은 윈도우 메세지를 받는 함수이다. 윈도우 클래스에 직접 등록되어 있지 않다. 윈도우 클래스에 등록한 윈도우 프로시져 안에서 호출되는 방식이다. 여기서 기본적으로 처리할 메세지만 처리하고, 나머지는 virtual로 설정한 windowProc() 함수가 처리하도록 한다. 이것은 이후 상속될 클래스에서 메세지를 처리하기 위한 함수이다.
2-3 SCore
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
|
class SCore : public SWindow
{
public:
// CoreFrameWork
bool CoreInit();
bool CoreFrame();
bool CoreRender();
bool CoreRelease();
// GameFrameWork
virtual bool BeginInit();
virtual bool BeginFrame();
virtual bool BeginRender();
virtual bool BeginRelease();
virtual bool Init();
virtual bool Frame();
virtual bool Render();
virtual bool Release();
virtual bool EndInit();
virtual bool EndFrame();
virtual bool EndRender();
virtual bool EndRelease();
virtual int WindowProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
bool Run();
public:
SCore();
~SCore();
};
|
cs |
SCore는 게임 프레임 워크를 담당하는 코어 클래스이다. 게임의 모든 동작은 이 클래스 안에서 동작한다. 중요 기능들은 이름에 Core가 붙은 함수들 안에서 처리가 된다. 나머지는 Core에서 상속받은 클래스가 처리하도록 되어있다. 이 중요 기능들은 다음에 나오는 클래스들이 담당하고 있다.
3. ManagerClass
매니저 클래스들은 기본적으로 싱글턴 템플릿 클래스를 상속 받고 있다. 객체가 여러개 생성되면 치명적인 오류를 만드는 클래스들이기 때문에 싱글턴 패턴을 사용한다. 매니저 클래스들은 게임에서 중요한 기능들을 관리하는 클래스들이기 때문에 중요도가 높다.
3-1 STimer
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
|
class STimer : public Singleton<STimer>
{
private:
friend class Singleton<STimer>;
private:
//===================================================================================
// Basis Time
//===================================================================================
LARGE_INTEGER m_Frequency; // 초당 주파수
LARGE_INTEGER m_Current; // 현재 시간
LARGE_INTEGER m_Frame; // 이전 프레임 시간 체크
float m_fSecPerFrame; // 프레임 경과 시간
//===================================================================================
// Frame Time
//===================================================================================
LARGE_INTEGER m_FPS; // FPS 체크 타이머
int m_iFramePerSecond; // 초당 프레임
int m_iFPSElapse; // 초당 경과된 프레임
//===================================================================================
// Event Time
//===================================================================================
LARGE_INTEGER m_Start; // 이벤트 타이머 시작 시간
LARGE_INTEGER m_Elapse; // 이벤트 타이머 경과 시간
bool m_bStarted; // 이벤트 타이머 작동 여부
float m_fEventTime;
//===================================================================================
// Debug Render
//===================================================================================
bool m_bDebugFlag;
UINT m_iClientHeight;
UINT m_iClientWidth;
public:
//===================================================================================
// 엔진 코어에서 아용하는 지원 함수
//===================================================================================
bool Init();
bool Frame();
bool Render(UINT iStartX, UINT iStartY, UINT iClientWidth, UINT iClientHeight);
bool Release() { return true; }
//===================================================================================
// 경과한 시간에 대한 지원 함수
//===================================================================================
void Reset();
void Start();
void Stop();
bool IsStarted()const { return m_bStarted; }
float GetElapsedTime()
{
if (m_bStarted)
{
QueryPerformanceCounter((LARGE_INTEGER*)&m_Elapse);
m_fEventTime = static_cast<float>(m_Elapse.LowPart - m_Start.LowPart) / static_cast<float>(m_Frequency.LowPart);
}
return m_fEventTime;
}
//===================================================================================
// FPS
//===================================================================================
int GetFPS() { return m_iFramePerSecond; }
float GetSPF() { return m_fSecPerFrame; }
//===================================================================================
// Debug Render
//===================================================================================
void SetDebugFlag(bool bFlag) { m_bDebugFlag = bFlag; };
private:
STimer();
public:
virtual ~STimer();
};
#define I_Timer STimer::GetInstance()
|
cs |
STimer는 게임 시간을 담당하는 클래스이다. 초당 프레임과 프레임당 걸린 시간, 프로그램 경과 시간 등을 알려주는 기능들을 가지고 있다.
- 알아둬야 할 함수들
STimer 함수는 고해상도 타이머를 통해 시간을 확인한다. GetTickCount()같은 함수와 달리 값을 ms단위로 넘겨주지 않는다. STimer의 동작 원리를 이해하기 위해서는 고해상도 타이머를 사용하는 방법을 알고 있어야 한다.
(1) QueryPerformanceFrequency()
이 함수는 초당 주파수가 얼마나 나오는지 알려주는 함수이다. 값이 0으로 나온다면 고해상도 타이머가 지원되지 않는다는 뜻이다. 현재 DirectX 11이 사용될 컴퓨터에 지원되지 않는 경우는 없을테니 0이 나오면 false를 반환하게 만들었다.
(2) QueryPerformanceCounter()
현재까지 경과된 시간을 넘겨주는 함수이다. 프레임마다 이 함수를 통해 값을 받아서 시간을 계산한다.
- 동작 원리
Frame을 계산하기 위해서 타이머는 프레임마다 Counter를 통해 값을 얻는다. 그리고 이전에 받은 값을 빼면서 프레임당 걸린 주파수를 계산한다. 계산된 값은 시간을 나타내지 않는다. 이를 위해서 초당 주파수 값(QueryPerfomanceFrequency)으로 나눠 걸린 시간을 확인한다.
3-2 SDirectWrite
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
|
class SDirectWrite : public Singleton<SDirectWrite>
{
private:
friend class Singleton<SDirectWrite>;
public:
//===============================================================================================
// 화면 DPI
//===============================================================================================
float m_fDPIScaleX;
float m_fDPIScaleY;
FLOAT m_fdpiX;
FLOAT m_fdpiY;
//===============================================================================================
// Direct Interface Pointer
//===============================================================================================
ID2D1RenderTarget* m_pD2DRenderTargetView;
ID2D1Factory* m_pD2DFactory;
ID2D1SolidColorBrush* m_pBlackBrush;
IDWriteFactory* m_pDWriteFactory;
IDWriteTextFormat* m_pTextFormat;
IDWriteTextLayout* m_pTextLayout;
//===============================================================================================
// 레이아웃 문자열 설정 값
//===============================================================================================
DWRITE_FONT_WEIGHT m_FontWeight; // 폰트 굵기
DWRITE_FONT_STYLE m_FontStyle; // 폰트 스타일
BOOL m_fontUnderline; // 밑줄
wstring m_wszFontFamily; // Font용 문자열
float m_FontSize; // 폰트 사이즈
wstring m_wszText; // Layout용 문자열
UINT32 m_cTextLength; // 문자열 길이
//===============================================================================================
// Other Value
//===============================================================================================
HWND m_hWnd;
public:
//===============================================================================================
// Initialize and Create
//===============================================================================================
bool Set(HWND hWnd, int iWidth, int iHeight, IDXGISurface1* m_pSurface);
bool Init();
HRESULT CreateDeviceIndependentResources(); // 디바이스에 종속되지 않은 리소스 생성
HRESULT CreateDeviceResources(IDXGISurface1* m_pSurface); // 디바이스에 종속되는 리소스 생성
//===============================================================================================
// Render
//===============================================================================================
bool Render() {return true;}
bool Begin();
bool DrawText(RECT rc, TCHAR* pText, D2D1::ColorF Color = D2D1::ColorF(1, 0, 0, 1)); // Format 방식
bool DrawText(D2D1_POINT_2F origin, D2D1::ColorF Color = D2D1::ColorF(1, 0, 0, 1)); // Layout 방식
bool End();
//===============================================================================================
// Release
//===============================================================================================
bool Release(); // Enter Release Function
void DiscardDeviceIndependentResources(); // 디바이스에 종속되지 않은 리소스들 해제
void DiscardDeviceResources(); // 디바이스에 종속되는 리소스들 해제
//===============================================================================================
// Setter
//===============================================================================================
HRESULT SetText(D2D1_POINT_2F pos, wchar_t *text, D2D1::ColorF Color);
HRESULT SetFont(wchar_t *FontFamily);
HRESULT SetFontSize(float size);
HRESULT SetWeight(DWRITE_FONT_WEIGHT FontWeight);
HRESULT SetItalic(DWRITE_FONT_STYLE FontStyle);
HRESULT SetUnderline(bool underline);
// 출력시 필요한 값 셋팅
bool SetPragraghAlighment(DWRITE_PARAGRAPH_ALIGNMENT nPragraghAlighment);
bool SetTextAlighment(DWRITE_TEXT_ALIGNMENT nTextAlighment);
//===============================================================================================
// Other
//===============================================================================================
void OnResize(UINT width, UINT height, IDXGISurface1* pSurface);
bool Frame() { return true;}
private:
SDirectWrite();
public:
virtual ~SDirectWrite();
};
#define I_DirectWrite SDirectWrite::GetInstance()
|
cs |
SDirectWrite는 Debug와 임시로 화면에 문자열를 그리기 위해 사용되는 클래스이다. DirectInterface를 사용하기 때문에 관리하기 용이하게 객체를 하나로 두고 사용한다. 참고로 window 10 SDK와 충돌이 일어나므로 주의할 필요가 있다.
- 텍스트 출력 방식
DirectX 에서는 텍스트 출력 방식이 두 가지가 있다. Format을 지정해서 텍스트를 출력하는 방식과 Layout을 통해 텍스크를 출력하는 방법이있다.
Format 방식은 IDWriteTextFormat 객체를 사용한다. 이 객체는 한번 생성할 때 지정된 폰트 패밀리, 굵기, 크기 등의 값을 지정하고 새로 생성할 때까지 변경할 수 없다. 대신 문자열을 바꿔도 얼마든지 사용이 가능하다. 문자열을 자주 바꾼다면 이 방식을 사용하는 것이 좋다.
Layout 방식은 IDWriteTextLayout 객체를 사용한다. IDWriteText와 달리 폰트에 관한 설정은 자유롭게 바꿀 수 있다. 대신에 문자열을 바꾸려면 객체를 새로 생성해야한다. 문자열이 바뀔 일이 없는 메뉴에 사용하기 적합한 방식이다.
- 초기화 해제 방식
DirectWrite는 DirectX를 사용하기 때문에 Device에 종속된 부분이 있다. 그렇기 때문에 SDirectWrite는 Device가 필요한 부분과 필요하지 않는 부분을 나누어서 함수화 시켰다. 해제되면 가능하다.
3-3 SSoundManager
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
|
class SSound
{
private:
friend class SSoundManager;
private:
FMOD::System* m_pSystem;
std::string m_csFileName;
int m_iIndex;
private:
FMOD::Sound* m_pSound;
int m_iNumSound;
float m_fVolume;
FMOD::Channel* m_pChannel;
std::string m_csBuffer;
public:
void Play();
void Stop();
void Paused();
void Volume(int iVolume = 10, bool bUp = true);
void PlayEffect();
void SetMode(DWORD dwMode);
private:
bool Init();
bool Frame();
bool Render();
bool Release();
private:
SSound();
virtual ~SSound();
};
|
cs |
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
|
class SSoundManager : public Singleton<SSoundManager>
{
private:
friend Singleton<SSoundManager>;
typedef std::map<int, SSound*>::iterator ITOR;
private:
FMOD::System* m_pSystem;
float m_fVolume;
int m_iNumSound;
std::map<int, SSound*> m_SoundList;
public:
bool Init();
bool Frame();
bool Render();
bool Release();
int Load(const char* pFilePath);
SSound* GetPtr(int iKey);
bool Delete(int iKey);
void Play(int iKey);
public:
SSoundManager();
~SSoundManager();
};
#define I_SoundManager SSoundManager::GetInstance()
#define CHANNELMAXARRAY 32
|
cs |
SSoundManager는 FMOD Library를 사용한다. 사운드 부분은 사운드 프로그래머가 따로 존재할 정도로 복잡한 분야이다. 사운드를 직접 구현해 사용하기보다 이러한 라이브러리를 사용하는 것이 적합하다. SSoundManager는 SSound 클래스들을 관리한다. SSound들은 SSoundManager의 System 주소 값과 SSoundManager내에서의 해당되는 번호를 들고 있다. 나머지는 해당 사운드 파일, 볼륨, 사용할 채널 등을 들고 있다.
SSoundManager는 stl map을 이용해 SSound들을 관리하고 있다. key 값은 정수형으로 사용하고 있으며, 호출된 곳에서 키값을 넘겨 준 후에 필요할 떄 해당 SSound의 주소를 받을 수 있게 처리하고 있다.
FMOD의 사용법은 라이브러리 사용법으로 이 문서에서는 넘어가도록 하겠다.
3-4 SInputManager
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
|
class SKeyInput
{
friend class SInputManager;
private:
//===========================================================================
// Direct Input Pointer
//===========================================================================
LPDIRECTINPUTDEVICE8 m_pDiKeyDevice; // 키보드 디바이스
//===========================================================================
// State Value
//===========================================================================
BYTE m_KeyState[KEYSTATECOUNT];
BYTE m_KeyBeforeState[KEYSTATECOUNT];
public:
//===========================================================================
// Game FrameWork
//===========================================================================
bool Init(LPDIRECTINPUT8 DirectInput, HWND hWnd);
bool Frame();
bool Render();
bool Release();
//===========================================================================
// Other
//===========================================================================
DWORD KeyCheck(DWORD dwKey);
void SetAcquire(bool bActive);
private:
SKeyInput();
~SKeyInput();
};
|
cs |
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
|
enum MouseButton
{
MOUSE_LBUTTON,
MOUSE_RBUTTON,
MOUSE_WHELL,
MOUSE_OTHER
};
class SMouseInput
{
friend class SInputManager;
private:
//===========================================================================
// Direct Input Pointer
//===========================================================================
LPDIRECTINPUTDEVICE8 m_pDiMouseDevice; // 마우스 디바이스
//===========================================================================
// State Value
//===========================================================================
DIMOUSESTATE m_MouseState;
DIMOUSESTATE m_MouseBeforeState;
public:
//===========================================================================
// Game FrameWork
//===========================================================================
bool Init(LPDIRECTINPUT8 DirectInput, HWND hWnd);
bool Frame();
bool Render();
bool Release();
//===========================================================================
// Other
//===========================================================================
D3DVECTOR MouseLocation();
DWORD ButtonCheck(DWORD dwButton);
void SetAcquire(bool bActive);
private:
SMouseInput();
~SMouseInput();
};
|
cs |
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
|
class SStickInput
{
friend class SInputManager;
private:
//===========================================================================
// Direct Input Pointer
//===========================================================================
LPDIRECTINPUTDEVICE8 m_pDiJoyStickDevice; // 조이스틱 디바이스
//===========================================================================
// State Value
//===========================================================================
DIJOYSTATE m_JoyState;
DIJOYSTATE m_JoyBeforeState;
public:
//===========================================================================
// Game FrameWork
//===========================================================================
bool Init(LPDIRECTINPUT8 DirectInput, HWND hWnd);
bool Frame();
bool Render();
bool Release();
//===========================================================================
// Other
//===========================================================================
D3DVECTOR LeftStickLocation();
D3DVECTOR RightStickLocation();
DWORD ButtonCheck(DWORD dwButton);
void SetAcquire(bool bActive);
private:
SStickInput();
~SStickInput();
};
#define StickLocationNomalize(n) n = ((n / 65535) * 100) - 100
|
cs |
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
|
class SInputManager : public Singleton<SInputManager>
{
private:
friend class Singleton<SInputManager>;
public:
//===========================================================================
// Direct Input Pointer
//===========================================================================
LPDIRECTINPUT8 m_pDirectInput;
SKeyInput* m_pKeyInput;
SMouseInput* m_pMouseInput;
SStickInput* m_pStickInput;
//===========================================================================
// Other
//===========================================================================
HWND m_hWnd;
DWORD m_dwElements;
DWORD m_dwImmediate; // 직접 데이터 사용 여부
bool m_bDebugFlag;
public:
//===========================================================================
// Game FrameWork
//===========================================================================
bool Init();
bool Frame();
bool Render(UINT iStartX, UINT iStartY, UINT iClientWidth, UINT iClientHeight);
bool Release();
//===========================================================================
// Reset
//===========================================================================
bool ResetDevice();
bool ResetResource() { return true; }
//===========================================================================
// Init
//===========================================================================
bool InitDirectInput(HINSTANCE, HWND, bool, bool, bool);
//===========================================================================
// Other
//===========================================================================
DWORD KeyBoardState(DWORD dwKey);
DWORD MouseButtonState(DWORD dwKey);
DWORD JoystickButton(DWORD dwKey);
void DeviceAcquire();
void DeviceUnAcquire();
void SetAcquire(bool bActive);
void SetDebugFlag(bool bFlag)
{
m_bDebugFlag = bFlag;
}
private:
SInputManager();
public:
virtual ~SInputManager();
};
#define I_InputManager SInputManager::GetInstance()
|
cs |
SInputManager는 DirectInput으로 구현된 매니저 클래스이다. 디바이스 종류마다 클래스 하나씩 들고 있다. 이 클래스들을 InputDevice라고 부르겠다. InputDevice 클래스들은 SInputManager를 통해 관리되고 있다. 생성자 해제자도 Private로 설정되어 있어 friend로 설정한 SinputManager 외에는 생성 삭제가 불가능하다.
- 생성 및 초기화
DirectWrite와는 다르게 Rendering에 필요한 Device를 필요로 하지 않는다. 필요한 것은 인스턴스 핸들과 윈도우 핸들만 있으면 된다. 이 라이브러리에서는 DirectInputFactory(DirectInput8 class)를 Manager 클래스가 생성한 후 InputDevice 클래스들한테 넘겨준다. 이후 InputDevice 클래스들은 넘겨받은 팩토리를 통해 자신이 담당한 Device를 생성한후 설정한다.
- Acquire과 UnAcquire
Acquire은 응용 프로그램한테 해당 장치 권한을 얻게 해주는 함수이다. 권한을 얻지 않으면 장치로부터 상태 값을 받을 수 없다. 또한 프로그램 종료시에 장치 권한을 해제(UnAcquire)을 해주지 않으면 다른 프로그램에서 장치를 사용하지 못하게 되기 때문에 권한 해제를 필수적으로 해줘야 한다.
- 직접 데이터와 버퍼링 데이터
직접 데이터는 윈도우 메세지에서 키를 받는 것처럼 사용된다. 키의 수만큼 1바이트 배열을 생성해서 그 배열을 통해 키보드의 상태 값을 얻는다. 마우스나 조이패드의 경우 상태 구조체에 직접 데이터를 받는다.
이와 달리 버퍼 데이터는 어떤 장치의 키가 눌렸다는 정보를 가진 구조체 배열을 사용한다. 어떤 키가 눌렸다면 배열에다가 어떤 키가 눌렸는지에 대한 정보를 넣는다. 이 라이브러리에서는 사용되지 않는 방법이다.