[DirectX11] Tutorial 13 - Direct Input
Tutorial 13 - Direct Input
원문 : http://www.rastertek.com/dx11tut13.html
이 튜토리얼은 DirectX 11의 Direct input을 다룹니다. 역시나 소스코드는 이전 튜토리얼에서 이어집니다.
Direct input은 DirectX API가 제공하는 고속의 입력 함수의 모음입니다. Direct input은 DirectX 11에서도 그 내용이 바뀌지 않았으며 현재 버전은 8입니다. 하지만 Direct input은 애초에 잘 만들어져 있기 때문에 더 이상 업데이트를 할 필요가 없나 봅니다(Direct Sound도 비슷합니다). Direct input은 일반적인 윈도우의 입력 시스템의 비해 믿을 수 없을 정도로 빠릅니다. 입력에 대한 빠른 응답시간을 요구하는 어플리케이션이라면 Direct input을 사용해야 합니다.
이 튜토리얼에서는 키보드와 마우스 장치에 대한 Direct input의 구현을 다룰 것입니다. 또한 TextClass를 사용하여 현재 마우스 포인터의 위치를 표시하게 할 것입니다. 이전 튜토리얼에 InputClass가 있기 때문에 전에 사용했던 기본 입력 대신 Direct input을 사용하도록 바꿀 것입니다.
Inputclass.h
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 | #pragma once class InputClass { public: InputClass(); InputClass(const InputClass&); ~InputClass(); bool Initialize(HINSTANCE, HWND, int, int); void Shutdown(); bool Frame(); bool IsEscapePressed(); void GetMouseLocation(int&, int&); private: bool ReadKeyboard(); bool ReadMouse(); void ProcessInput(); private: IDirectInput8* m_directInput = nullptr; IDirectInputDevice8* m_keyboard = nullptr; IDirectInputDevice8* m_mouse = nullptr; unsigned char m_keyboardState[256] = { 0, }; DIMOUSESTATE m_mouseState; int m_screenWidth = 0; int m_screenHeight = 0; int m_mouseX = 0; int m_mouseY = 0; }; | cs |
Inputclass.cpp
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 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | #include "stdafx.h" #include "inputclass.h" InputClass::InputClass() { } InputClass::InputClass(const InputClass& other) { } InputClass::~InputClass() { } bool InputClass::Initialize(HINSTANCE hinstance, HWND hwnd, int screenWidth, int screenHeight) { // 마우스 커서의 위치 지정에 사용될 화면 크기를 설정합니다. m_screenWidth = screenWidth; m_screenHeight = screenHeight; // Direct Input 인터페이스를 초기화 합니다. HRESULT result = DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_directInput, NULL); if (FAILED(result)) { return false; } // 키보드의 Direct Input 인터페이스를 생성합니다 result = m_directInput->CreateDevice(GUID_SysKeyboard, &m_keyboard, NULL); if (FAILED(result)) { return false; } // 데이터 형식을 설정하십시오. 이 경우 키보드이므로 사전 정의 된 데이터 형식을 사용할 수 있습니다. result = m_keyboard->SetDataFormat(&c_dfDIKeyboard); if (FAILED(result)) { return false; } // 다른 프로그램과 공유하지 않도록 키보드의 협조 수준을 설정합니다 result = m_keyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE); if (FAILED(result)) { return false; } // 키보드를 할당받는다 result = m_keyboard->Acquire(); if (FAILED(result)) { return false; } // 마우스 Direct Input 인터페이스를 생성합니다. result = m_directInput->CreateDevice(GUID_SysMouse, &m_mouse, NULL); if (FAILED(result)) { return false; } // 미리 정의 된 마우스 데이터 형식을 사용하여 마우스의 데이터 형식을 설정합니다. result = m_mouse->SetDataFormat(&c_dfDIMouse); if (FAILED(result)) { return false; } // 다른 프로그램과 공유 할 수 있도록 마우스의 협력 수준을 설정합니다. result = m_mouse->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); if (FAILED(result)) { return false; } // 마우스를 할당받는다 result = m_mouse->Acquire(); if (FAILED(result)) { return false; } return true; } void InputClass::Shutdown() { // 마우스를 반환합니다. if (m_mouse) { m_mouse->Unacquire(); m_mouse->Release(); m_mouse = 0; } // 키보드를 반환합니다. if (m_keyboard) { m_keyboard->Unacquire(); m_keyboard->Release(); m_keyboard = 0; } // m_directInput 객체를 반환합니다. if (m_directInput) { m_directInput->Release(); m_directInput = 0; } } bool InputClass::Frame() { // 키보드의 현재 상태를 읽는다. if (!ReadKeyboard()) { return false; } // 마우스의 현재 상태를 읽는다. if (!ReadMouse()) { return false; } // 키보드와 마우스의 변경상태를 처리합니다. ProcessInput(); return true; } bool InputClass::ReadKeyboard() { // 키보드 디바이스를 얻는다. HRESULT result = m_keyboard->GetDeviceState(sizeof(m_keyboardState), (LPVOID)&m_keyboardState); if (FAILED(result)) { // 키보드가 포커스를 잃었거나 획득되지 않은 경우 컨트롤을 다시 가져 온다 if ((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED)) { m_keyboard->Acquire(); } else { return false; } } return true; } bool InputClass::ReadMouse() { // 마우스 디바이스를 얻는다. HRESULT result = m_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&m_mouseState); if (FAILED(result)) { // 마우스가 포커스를 잃었거나 획득되지 않은 경우 컨트롤을 다시 가져 온다 if ((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED)) { m_mouse->Acquire(); } else { return false; } } return true; } void InputClass::ProcessInput() { // 프레임 동안 마우스 위치의 변경을 기반으로 마우스 커서의 위치를 업데이트 합니다. m_mouseX += m_mouseState.lX; m_mouseY += m_mouseState.lY; // 마우스 위치가 화면 너비 또는 높이를 초과하지 않는지 확인한다. if (m_mouseX < 0) { m_mouseX = 0; } if (m_mouseY < 0) { m_mouseY = 0; } if (m_mouseX > m_screenWidth) { m_mouseX = m_screenWidth; } if (m_mouseY > m_screenHeight) { m_mouseY = m_screenHeight; } } bool InputClass::IsEscapePressed() { // escape 키가 현재 눌려지고 있는지 bit값을 계산하여 확인한다. if (m_keyboardState[DIK_ESCAPE] & 0x80) { return true; } return false; } void InputClass::GetMouseLocation(int& mouseX, int& mouseY) { mouseX = m_mouseX; mouseY = m_mouseY; } | cs |
기존에 사용하던 윈도우 입력 시스템을 없애고 Direct input을 사용하기 때문에 바뀐 함수들을 위주로 설명하겠습니다. 기존의 Systemclass 헤더파일은 변함이 없으므로 생략하도록 하겠습니다.
Systemclass.cpp
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 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | #include "stdafx.h" #include "inputclass.h" #include "graphicsclass.h" #include "systemclass.h" SystemClass::SystemClass() { } SystemClass::SystemClass(const SystemClass& other) { } SystemClass::~SystemClass() { } bool SystemClass::Initialize() { // 윈도우 창 가로, 세로 넓이 변수 초기화 int screenWidth = 0; int screenHeight = 0; // 윈도우 생성 초기화 InitializeWindows(screenWidth, screenHeight); // m_Input 객체 생성. 이 클래스는 추후 사용자의 키보드 입력 처리에 사용됩니다. m_Input = new InputClass; if (!m_Input) { return false; } // m_Input 객체 초기화 if(!m_Input->Initialize(m_hinstance, m_hwnd, screenWidth, screenHeight)) { MessageBox(m_hwnd, L"Could not initialize the input object.", L"Error", MB_OK); return false; } // m_Graphics 객체 생성. 그래픽 랜더링을 처리하기 위한 객체입니다. m_Graphics = new GraphicsClass; if (!m_Graphics) { return false; } // m_Graphics 객체 초기화. return m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd); } void SystemClass::Shutdown() { // m_Graphics 객체 반환 if (m_Graphics) { m_Graphics->Shutdown(); delete m_Graphics; m_Graphics = 0; } // m_Input 객체 반환 if (m_Input) { m_Input->Shutdown(); delete m_Input; m_Input = 0; } // Window 종료 처리 ShutdownWindows(); } void SystemClass::Run() { // 메시지 구조체 생성 및 초기화 MSG msg; ZeroMemory(&msg, sizeof(MSG)); // 사용자로부터 종료 메시지를 받을때까지 메시지루프를 돕니다 while (true) { // 윈도우 메시지를 처리합니다 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // 종료 메시지를 받을 경우 메시지 루프를 탈출합니다 if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else { // 그 외에는 Frame 함수를 처리합니다. if (!Frame()) { MessageBox(m_hwnd, L"Frame Processing Failed", L"Error", MB_OK); break; } } // 사용자가 ESC키를 눌렀는지 확인 후 종료 처리함 if(m_Input->IsEscapePressed() == true) { break; } } } bool SystemClass::Frame() { int mouseX = 0, mouseY = 0; // 입력 프레임 처리를 수행합니다 if(!m_Input->Frame()) { return false; } // 입력 객체에서 마우스 위치를 가져옵니다 m_Input->GetMouseLocation(mouseX, mouseY); // 그래픽 객체의 Frame을 처리합니다 if(!m_Graphics->Frame(mouseX, mouseY)) { return false; } return m_Graphics->Render(); } LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) { return DefWindowProc(hwnd, umsg, wparam, lparam); } void SystemClass::InitializeWindows(int& screenWidth, int& screenHeight) { // 외부 포인터를 이 객체로 지정합니다 ApplicationHandle = this; // 이 프로그램의 인스턴스를 가져옵니다 m_hinstance = GetModuleHandle(NULL); // 프로그램 이름을 지정합니다 m_applicationName = L"Dx11Demo_13"; // windows 클래스를 아래와 같이 설정합니다. WNDCLASSEX wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = m_hinstance; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hIconSm = wc.hIcon; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = m_applicationName; wc.cbSize = sizeof(WNDCLASSEX); // windows class를 등록합니다 RegisterClassEx(&wc); // 모니터 화면의 해상도를 읽어옵니다 screenWidth = GetSystemMetrics(SM_CXSCREEN); screenHeight = GetSystemMetrics(SM_CYSCREEN); int posX = 0; int posY = 0; // FULL_SCREEN 변수 값에 따라 화면을 설정합니다. if (FULL_SCREEN) { // 풀스크린 모드로 지정했다면 모니터 화면 해상도를 데스크톱 해상도로 지정하고 색상을 32bit로 지정합니다. DEVMODE dmScreenSettings; memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); dmScreenSettings.dmSize = sizeof(dmScreenSettings); dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth; dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight; dmScreenSettings.dmBitsPerPel = 32; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; // 풀스크린으로 디스플레이 설정을 변경합니다. ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); } else { // 윈도우 모드의 경우 800 * 600 크기를 지정합니다. screenWidth = 800; screenHeight = 600; // 윈도우 창을 가로, 세로의 정 가운데 오도록 합니다. posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2; posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2; } // 윈도우를 생성하고 핸들을 구합니다. m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP, posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL); // 윈도우를 화면에 표시하고 포커스를 지정합니다 ShowWindow(m_hwnd, SW_SHOW); SetForegroundWindow(m_hwnd); SetFocus(m_hwnd); } void SystemClass::ShutdownWindows() { // 풀스크린 모드였다면 디스플레이 설정을 초기화합니다. if (FULL_SCREEN) { ChangeDisplaySettings(NULL, 0); } // 창을 제거합니다 DestroyWindow(m_hwnd); m_hwnd = NULL; // 프로그램 인스턴스를 제거합니다 UnregisterClass(m_applicationName, m_hinstance); m_hinstance = NULL; // 외부포인터 참조를 초기화합니다 ApplicationHandle = NULL; } LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam) { switch (umessage) { // 윈도우 종료를 확인합니다 case WM_DESTROY: { PostQuitMessage(0); return 0; } // 윈도우가 닫히는지 확인합니다 case WM_CLOSE: { PostQuitMessage(0); return 0; } // 그 외의 모든 메시지들은 시스템 클래스의 메시지 처리로 넘깁니다. default: { return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam); } } } | cs |
Graphicsclass.h
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 | #pragma once ///////////// // GLOBALS // ///////////// const bool FULL_SCREEN = false; const bool VSYNC_ENABLED = true; const float SCREEN_DEPTH = 1000.0f; const float SCREEN_NEAR = 0.1f; class D3DClass; class CameraClass; class TextClass; class GraphicsClass { public: GraphicsClass(); GraphicsClass(const GraphicsClass&); ~GraphicsClass(); bool Initialize(int, int, HWND); void Shutdown(); bool Frame(int, int); bool Render(); private: D3DClass* m_Direct3D = nullptr; CameraClass* m_Camera = nullptr; TextClass* m_Text = nullptr; }; | cs |
Graphicsclass.cpp
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 | #include "stdafx.h" #include "d3dclass.h" #include "cameraclass.h" #include "textclass.h" #include "graphicsclass.h" GraphicsClass::GraphicsClass() { } GraphicsClass::GraphicsClass(const GraphicsClass& other) { } GraphicsClass::~GraphicsClass() { } bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hwnd) { // Direct3D 객체 생성 m_Direct3D = new D3DClass; if(!m_Direct3D) { return false; } // Direct3D 객체 초기화 if(!m_Direct3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR)) { MessageBox(hwnd, L"Could not initialize Direct3D.", L"Error", MB_OK); return false; } // m_Camera 객체 생성 m_Camera = new CameraClass; if (!m_Camera) { return false; } // 카메라 포지션 설정 XMMATRIX baseViewMatrix; m_Camera->SetPosition(0.0f, 0.0f, -1.0f); m_Camera->Render(); m_Camera->GetViewMatrix(baseViewMatrix); // m_Text 객체 생성 m_Text = new TextClass; if(!m_Text) { return false; } // m_Text 객체 초기화 if (!m_Text->Initialize(m_Direct3D->GetDevice(), m_Direct3D->GetDeviceContext(), hwnd, screenWidth, screenHeight, baseViewMatrix)) { MessageBox(hwnd, L"Could not initialize the text object.", L"Error", MB_OK); return false; } return true; } void GraphicsClass::Shutdown() { // m_Text 객체 반환 if (m_Text) { m_Text->Shutdown(); delete m_Text; m_Text = 0; } // m_Camera 객체 반환 if (m_Camera) { delete m_Camera; m_Camera = 0; } // Direct3D 객체 반환 if (m_Direct3D) { m_Direct3D->Shutdown(); delete m_Direct3D; m_Direct3D = 0; } } bool GraphicsClass::Frame(int mouseX, int mouseY) { // 마우스 위치 설정 if(!m_Text->SetMousePosition(mouseX, mouseY, m_Direct3D->GetDeviceContext())) { return false; } // 카메라 위치 설정 m_Camera->SetPosition(0.0f, 0.0f, -10.0f); return true; } bool GraphicsClass::Render() { // 씬을 그리기 위해 버퍼를 지웁니다 m_Direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f); // 카메라의 위치에 따라 뷰 행렬을 생성합니다 m_Camera->Render(); // 카메라 및 d3d 객체에서 월드, 뷰 및 투영 행렬을 가져옵니다 XMMATRIX worldMatrix, viewMatrix, projectionMatrix, orthoMatrix; m_Camera->GetViewMatrix(viewMatrix); m_Direct3D->GetWorldMatrix(worldMatrix); m_Direct3D->GetProjectionMatrix(projectionMatrix); m_Direct3D->GetOrthoMatrix(orthoMatrix); // 모든 2D 렌더링을 시작하려면 Z 버퍼를 끕니다. m_Direct3D->TurnZBufferOff(); // 텍스트를 렌더링하기 전에 알파 블렌딩을 켭니다 m_Direct3D->TurnOnAlphaBlending(); // 텍스트 문자열을 렌더링 합니다 if(!m_Text->Render(m_Direct3D->GetDeviceContext(), worldMatrix, orthoMatrix)) { return false; } // 텍스트를 렌더링 한 후 알파 블렌딩을 해제합니다 m_Direct3D->TurnOffAlphaBlending(); // 모든 2D 렌더링이 완료되었으므로 Z 버퍼를 다시 켜십시오. m_Direct3D->TurnZBufferOn(); // 버퍼의 내용을 화면에 출력합니다 m_Direct3D->EndScene(); return true; } | cs |
TextClass.h
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 | #pragma once class FontClass; class FontShaderClass; class TextClass : public AlignedAllocationPolicy<16> { private: struct SentenceType { ID3D11Buffer *vertexBuffer, *indexBuffer; int vertexCount, indexCount, maxLength; float red, green, blue; }; struct VertexType { XMFLOAT3 position; XMFLOAT2 texture; }; public: TextClass(); TextClass(const TextClass&); ~TextClass(); bool Initialize(ID3D11Device*, ID3D11DeviceContext*, HWND, int, int, XMMATRIX); void Shutdown(); bool Render(ID3D11DeviceContext*, XMMATRIX, XMMATRIX); bool SetMousePosition(int, int, ID3D11DeviceContext*); private: bool InitializeSentence(SentenceType**, int, ID3D11Device*); bool UpdateSentence(SentenceType*, char*, int, int, float, float, float, ID3D11DeviceContext*); void ReleaseSentence(SentenceType**); bool RenderSentence(ID3D11DeviceContext*, SentenceType*, XMMATRIX, XMMATRIX); private: FontClass* m_Font = nullptr; FontShaderClass* m_FontShader = nullptr; int m_screenWidth = 0; int m_screenHeight = 0; XMMATRIX m_baseViewMatrix; SentenceType* m_sentence1; SentenceType* m_sentence2; }; | cs |
TextClass.cpp
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 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | #include "stdafx.h" #include "FontClass.h" #include "FontShaderClass.h" #include "TextClass.h" TextClass::TextClass() { } TextClass::TextClass(const TextClass& other) { } TextClass::~TextClass() { } bool TextClass::Initialize(ID3D11Device* device, ID3D11DeviceContext* deviceContext, HWND hwnd, int screenWidth, int screenHeight, XMMATRIX baseViewMatrix) { // 화면 너비와 높이를 저장합니다. m_screenWidth = screenWidth; m_screenHeight = screenHeight; // 기본 뷰 매트릭스를 저장합니다. m_baseViewMatrix = baseViewMatrix; // 폰트 객체를 생성합니다. m_Font = new FontClass; if (!m_Font) { return false; } // 폰트 객체를 초기화 합니다. bool result = m_Font->Initialize(device, "../Dx11Demo_13/data/fontdata.txt", L"../Dx11Demo_13/data/font.dds"); if (!result) { MessageBox(hwnd, L"Could not initialize the font object.", L"Error", MB_OK); return false; } // 폰트 쉐이더 객체를 생성합니다. m_FontShader = new FontShaderClass; if (!m_FontShader) { return false; } // 폰트 쉐이더 객체를 초기화 합니다. result = m_FontShader->Initialize(device, hwnd); if (!result) { MessageBox(hwnd, L"Could not initialize the font shader object.", L"Error", MB_OK); return false; } // 첫 번째 문장을 초기화합니다. result = InitializeSentence(&m_sentence1, 16, device); if (!result) { return false; } // 문장 정점 버퍼를 새 문자열 정보로 업데이트합니다. result = UpdateSentence(m_sentence1, "Hello", 100, 100, 1.0f, 1.0f, 1.0f, deviceContext); if (!result) { return false; } // 첫 번째 문장을 초기화합니다. result = InitializeSentence(&m_sentence2, 16, device); if (!result) { return false; } // 문장 정점 버퍼를 새 문자열 정보로 업데이트합니다. result = UpdateSentence(m_sentence2, "Goodbye", 100, 200, 1.0f, 1.0f, 0.0f, deviceContext); if (!result) { return false; } return true; } void TextClass::Shutdown() { // 첫번째 문장을 반환합니다. ReleaseSentence(&m_sentence1); // 두번째 문장을 반환합니다. ReleaseSentence(&m_sentence2); // 폰트 쉐이더 객체를 반환합니다. if (m_FontShader) { m_FontShader->Shutdown(); delete m_FontShader; m_FontShader = 0; } // 폰트 객체를 반환합니다. if (m_Font) { m_Font->Shutdown(); delete m_Font; m_Font = 0; } } bool TextClass::Render(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX orthoMatrix) { // 첫번째 문장을 그립니다. if (!RenderSentence(deviceContext, m_sentence1, worldMatrix, orthoMatrix)) { return false; } // 두번째 문장을 그립니다. return RenderSentence(deviceContext, m_sentence2, worldMatrix, orthoMatrix); } bool TextClass::InitializeSentence(SentenceType** sentence, int maxLength, ID3D11Device* device) { // 새로운 문장 개체를 만듭니다. *sentence = new SentenceType; if (!*sentence) { return false; } // 문장 버퍼를 null로 초기화합니다. (*sentence)->vertexBuffer = 0; (*sentence)->indexBuffer = 0; // 문장의 최대 길이를 설정합니다. (*sentence)->maxLength = maxLength; // 정점 배열의 정점 수를 설정합니다. (*sentence)->vertexCount = 6 * maxLength; // 인덱스 배열의 인덱스 수를 설정합니다. (*sentence)->indexCount = (*sentence)->vertexCount; // 정점 배열을 만듭니다. VertexType* vertices = new VertexType[(*sentence)->vertexCount]; if (!vertices) { return false; } // 인덱스 배열을 만듭니다. unsigned long* indices = new unsigned long[(*sentence)->indexCount]; if (!indices) { return false; } // 처음에는 정점 배열을 0으로 초기화합니다. memset(vertices, 0, (sizeof(VertexType) * (*sentence)->vertexCount)); // 인덱스 배열을 초기화합니다. for (int i = 0; i<(*sentence)->indexCount; i++) { indices[i] = i; } // 동적 인 정점 버퍼의 설명을 설정한다. D3D11_BUFFER_DESC vertexBufferDesc; vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; vertexBufferDesc.ByteWidth = sizeof(VertexType) * (*sentence)->vertexCount; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; vertexBufferDesc.MiscFlags = 0; vertexBufferDesc.StructureByteStride = 0; // subresource 구조에 정점 데이터에 대한 포인터를 제공합니다. D3D11_SUBRESOURCE_DATA vertexData; vertexData.pSysMem = vertices; vertexData.SysMemPitch = 0; vertexData.SysMemSlicePitch = 0; // 정점 버퍼를 만든다. if (FAILED(device->CreateBuffer(&vertexBufferDesc, &vertexData, &(*sentence)->vertexBuffer))) { return false; } // 정적 인덱스 버퍼의 설명을 설정합니다. D3D11_BUFFER_DESC indexBufferDesc; indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(unsigned long) * (*sentence)->indexCount; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; indexBufferDesc.StructureByteStride = 0; // 하위 리소스 구조에 인덱스 데이터에 대한 포인터를 제공합니다. D3D11_SUBRESOURCE_DATA indexData; indexData.pSysMem = indices; indexData.SysMemPitch = 0; indexData.SysMemSlicePitch = 0; // 인덱스 버퍼를 만듭니다. if (FAILED(device->CreateBuffer(&indexBufferDesc, &indexData, &(*sentence)->indexBuffer))) { return false; } // 더 이상 필요하지 않은 정점 배열을 해제합니다. delete[] vertices; vertices = 0; // 더 이상 필요하지 않은 인덱스 배열을 해제합니다. delete[] indices; indices = 0; return true; } bool TextClass::UpdateSentence(SentenceType* sentence, char* text, int positionX, int positionY, float red, float green, float blue, ID3D11DeviceContext* deviceContext) { // 문장의 색을 저장한다. sentence->red = red; sentence->green = green; sentence->blue = blue; // 가능한 버퍼 오버 플로우를 확인합니다. if ((int)strlen(text) > sentence->maxLength) { return false; } // 정점 배열을 만듭니다. VertexType* vertices = new VertexType[sentence->vertexCount]; if (!vertices) { return false; } // 처음에는 정점 배열을 0으로 초기화합니다. memset(vertices, 0, (sizeof(VertexType) * sentence->vertexCount)); // 그리기를 시작할 화면에서 X 및 Y 픽셀 위치를 계산합니다. float drawX = (float)(((m_screenWidth / 2) * -1) + positionX); float drawY = (float)((m_screenHeight / 2) - positionY); // 폰트 클래스를 사용하여 문장 텍스트와 문장 그리기 위치에서 정점 배열을 만듭니다. m_Font->BuildVertexArray((void*)vertices, text, drawX, drawY); // 버텍스 버퍼를 쓸 수 있도록 잠급니다. D3D11_MAPPED_SUBRESOURCE mappedResource; if (FAILED(deviceContext->Map(sentence->vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource))) { return false; } // 정점 버퍼의 데이터를 가리키는 포인터를 얻는다. VertexType* verticesPtr = (VertexType*)mappedResource.pData; // 데이터를 정점 버퍼에 복사합니다. memcpy(verticesPtr, (void*)vertices, (sizeof(VertexType) * sentence->vertexCount)); // 정점 버퍼의 잠금을 해제합니다. deviceContext->Unmap(sentence->vertexBuffer, 0); // 더 이상 필요하지 않은 정점 배열을 해제합니다. delete[] vertices; vertices = 0; return true; } void TextClass::ReleaseSentence(SentenceType** sentence) { if (*sentence) { // 문장 버텍스 버퍼를 해제합니다. if ((*sentence)->vertexBuffer) { (*sentence)->vertexBuffer->Release(); (*sentence)->vertexBuffer = 0; } // 문장 인덱스 버퍼를 해제합니다. if ((*sentence)->indexBuffer) { (*sentence)->indexBuffer->Release(); (*sentence)->indexBuffer = 0; } // 문장을 해제합니다. delete *sentence; *sentence = 0; } } bool TextClass::RenderSentence(ID3D11DeviceContext* deviceContext, SentenceType* sentence, XMMATRIX worldMatrix, XMMATRIX orthoMatrix) { // 정점 버퍼 간격 및 오프셋을 설정합니다. unsigned int stride = sizeof(VertexType); unsigned int offset = 0; // 렌더링 할 수 있도록 입력 어셈블러에서 정점 버퍼를 활성으로 설정합니다. deviceContext->IASetVertexBuffers(0, 1, &sentence->vertexBuffer, &stride, &offset); // 렌더링 할 수 있도록 입력 어셈블러에서 인덱스 버퍼를 활성으로 설정합니다. deviceContext->IASetIndexBuffer(sentence->indexBuffer, DXGI_FORMAT_R32_UINT, 0); // 이 정점 버퍼에서 렌더링 되어야 하는 프리미티브 유형을 설정합니다.이 경우에는 삼각형입니다. deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 입력 된 문장 색상으로 픽셀 색상 벡터를 만듭니다. XMFLOAT4 pixelColor = XMFLOAT4(sentence->red, sentence->green, sentence->blue, 1.0f); // 폰트 셰이더를 사용하여 텍스트를 렌더링합니다. if (!m_FontShader->Render(deviceContext, sentence->indexCount, worldMatrix, m_baseViewMatrix, orthoMatrix, m_Font->GetTexture(), pixelColor)) { false; } return true; } bool TextClass::SetMousePosition(int mouseX, int mouseY, ID3D11DeviceContext* deviceContext) { // mouseX 정수를 문자열 형식으로 변환합니다. char tempString[16] = { 0, }; _itoa_s(mouseX, tempString, 10); // mouseX 문자열을 설정합니다. char mouseString[16] = { 0, }; strcpy_s(mouseString, "Mouse X: "); strcat_s(mouseString, tempString); // 문장 정점 버퍼를 새 문자열 정보로 업데이트합니다. if(!UpdateSentence(m_sentence1, mouseString, 20, 20, 1.0f, 1.0f, 1.0f, deviceContext)) { return false; } // mouseY 정수를 문자열 형식으로 변환합니다. _itoa_s(mouseY, tempString, 10); // mouseY 문자열을 설정합니다. strcpy_s(mouseString, "Mouse Y: "); strcat_s(mouseString, tempString); // 문장 정점 버퍼를 새 문자열 정보로 업데이트합니다. if(!UpdateSentence(m_sentence2, mouseString, 20, 40, 1.0f, 1.0f, 1.0f, deviceContext)) { return false; } return true; } | cs |
출력 화면
마치면서
보신 것처럼 DirectX 11에서 direct input을 설정하는 것은 정말 간단하지만 입력 장치에 고속의 접근을 가능하게 해 줍니다.
연습문제
1. 프로그램을 컴파일하고 실행해 보십시오. 마우스를 화면 내에서 이동하고 위치를 표시하는 글자가 바뀌는 것을 확인해 보십시오.
2. 2D 렌더링 튜토리얼의 내용을 활용하여 마우스 이동이 반영되는 마우스 포인터를 만들어 보십시오.
3. 키보드 버퍼를 읽어 화면에 어떤 글자가 타이핑되는지 표시하는 함수를 만들어 보십시오.
소스코드
소스코드 : Dx11Demo_13.zip
'DirectX 11 > Basic' 카테고리의 다른 글
[DirectX11] Tutorial 15 - FPS, CPU 사용량, 타이머 (1) | 2017.12.10 |
---|---|
[DirectX11] Tutorial 14 - Direct Sound (0) | 2017.12.09 |
[DirectX11] Tutorial 12 - 글꼴 엔진 (0) | 2017.12.08 |
[DirectX11] Tutorial 11 - 2D 렌더링 (1) | 2017.12.07 |
[DirectX11] Tutorial 10 - 정반사광 (0) | 2017.12.06 |