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(1001)); // Format 방식
    bool            DrawText(D2D1_POINT_2F origin, D2D1::ColorF Color = D2D1::ColorF(1001));    // 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 = 10bool 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, boolboolbool);
    //===========================================================================
    //    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바이트 배열을 생성해서 그 배열을 통해 키보드의 상태 값을 얻는다. 마우스나 조이패드의 경우 상태 구조체에 직접 데이터를 받는다.
  이와 달리 버퍼 데이터는 어떤 장치의 키가 눌렸다는 정보를 가진 구조체 배열을 사용한다. 어떤 키가 눌렸다면 배열에다가 어떤 키가 눌렸는지에 대한 정보를 넣는다. 이 라이브러리에서는 사용되지 않는 방법이다.