diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj
index 0e1ebf5..d920499 100644
--- a/DX11Starter.vcxproj
+++ b/DX11Starter.vcxproj
@@ -125,11 +125,13 @@
+
+
diff --git a/DX11Starter.vcxproj.filters b/DX11Starter.vcxproj.filters
index 4f0fa0b..c7deda6 100644
--- a/DX11Starter.vcxproj.filters
+++ b/DX11Starter.vcxproj.filters
@@ -27,6 +27,9 @@
Source Files
+
+ Source Files
+
@@ -38,6 +41,9 @@
Header Files
+
+ Header Files
+
diff --git a/DXCore.cpp b/DXCore.cpp
index e7553a9..daa290d 100644
--- a/DXCore.cpp
+++ b/DXCore.cpp
@@ -1,4 +1,5 @@
#include "DXCore.h"
+#include "Input.h"
#include
#include
@@ -72,6 +73,9 @@ DXCore::~DXCore()
// we don't need to explicitly clean up those DirectX objects
// - If we weren't using smart pointers, we'd need
// to call Release() on each DirectX object created in DXCore
+
+ // Delete input manager singleton
+ delete& Input::GetInstance();
}
// --------------------------------------------------------
@@ -147,6 +151,9 @@ HRESULT DXCore::InitWindow()
// We need to tell Windows to show it, and how to show it
ShowWindow(hWnd, SW_SHOW);
+ // Initialize the input manager now that we definitely have a window
+ Input::GetInstance().Initialize(hWnd);
+
// Return an "everything is ok" HRESULT value
return S_OK;
}
@@ -396,9 +403,15 @@ HRESULT DXCore::Run()
if(titleBarStats)
UpdateTitleBarStats();
+ // Update the input manager
+ Input::GetInstance().Update();
+
// The game loop
Update(deltaTime, totalTime);
Draw(deltaTime, totalTime);
+
+ // Frame is over, notify the input manager
+ Input::GetInstance().EndOfFrame();
}
}
@@ -532,7 +545,7 @@ void DXCore::CreateConsoleWindow(int bufferLines, int bufferColumns, int windowL
//
// - As it turns out, the relative path for a program is different when
// running through VS and when running the .exe directly, which makes
-// it a pain to properly load files external files (like textures)
+// it a pain to properly load external files (like textures)
// - Running through VS: Current Dir is the *project folder*
// - Running from .exe: Current Dir is the .exe's folder
// - This has nothing to do with DEBUG and RELEASE modes - it's purely a
@@ -540,7 +553,7 @@ void DXCore::CreateConsoleWindow(int bufferLines, int bufferColumns, int windowL
// for it. In fact, it could be fixed by changing a setting in VS, but
// the option is stored in a user file (.suo), which is ignored by most
// version control packages by default. Meaning: the option must be
-// changed every on every PC. Ugh. So instead, here's a helper.
+// changed on every PC. Ugh. So instead, here's a helper.
// --------------------------------------------------------------------------
std::string DXCore::GetExePath()
{
@@ -660,6 +673,11 @@ LRESULT DXCore::ProcessMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
OnResize();
return 0;
+
+ // Has the mouse wheel been scrolled?
+ case WM_MOUSEWHEEL:
+ Input::GetInstance().SetWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA);
+ return 0;
// Is our focus state changing?
case WM_SETFOCUS: hasFocus = true; return 0;
diff --git a/Game.cpp b/Game.cpp
index 9cbc56a..b3c4405 100644
--- a/Game.cpp
+++ b/Game.cpp
@@ -1,5 +1,6 @@
#include "Game.h"
#include "Vertex.h"
+#include "Input.h"
// Needed for a helper function to read compiled shader files from the hard drive
#pragma comment(lib, "d3dcompiler.lib")
@@ -236,8 +237,8 @@ void Game::OnResize()
// --------------------------------------------------------
void Game::Update(float deltaTime, float totalTime)
{
- // Quit if the escape key is pressed
- if (GetAsyncKeyState(VK_ESCAPE))
+ // Example input checking: Quit if the escape key is pressed
+ if (Input::GetInstance().KeyDown(VK_ESCAPE))
Quit();
}
diff --git a/Input.cpp b/Input.cpp
new file mode 100644
index 0000000..ef3d6c0
--- /dev/null
+++ b/Input.cpp
@@ -0,0 +1,282 @@
+#include "Input.h"
+
+// Singleton requirement
+Input* Input::instance;
+
+// --------------- Basic usage -----------------
+//
+// The keyboard functions all take a single character
+// like 'W', ' ' or '8' (which will implicitly cast
+// to an int) or a pre-defined virtual key code like
+// VK_SHIFT, VK_ESCAPE or VK_TAB. These virtual key
+// codes are are accessible through the Windows.h
+// file (already included in Input.h). See the
+// following for a complete list of virtual key codes:
+// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
+//
+// Checking if various keys are down or up:
+//
+// if (Input::GetInstance().KeyDown('W')) { }
+// if (Input::GetInstance().KeyUp('2')) { }
+// if (Input::GetInstance().KeyDown(VK_SHIFT)) { }
+//
+//
+// Checking if a key was initially pressed or released
+// this frame:
+//
+// if (Input::GetInstance().KeyPressed('Q')) { }
+// if (Input::GetInstance().KeyReleased(' ')) { }
+//
+// (Note that these functions will only return true on
+// the FIRST frame that a key is pressed or released.)
+//
+//
+// Checking for mouse input:
+//
+// if (Input::GetInstance().MouseLeftDown()) { }
+// if (Input::GetInstance().MouseRightDown()) { }
+// if (Input::GetInstance().MouseMiddleUp()) { }
+// if (Input::GetInstance().MouseLeftPressed()) { }
+// if (Input::GetInstance().MouseRightReleased()) { }
+//
+// ---------------------------------------------
+
+// -------------- Less verbose -----------------
+//
+// If you'd rather not have to type Input::GetInstance()
+// over and over, you can save the reference in a variable:
+//
+// Input& input = Input::GetInstance();
+// if (input.KeyDown('W')) { }
+// if (input.KeyDown('A')) { }
+// if (input.KeyDown('S')) { }
+// if (input.KeyDown('D')) { }
+//
+// ---------------------------------------------
+
+
+// --------------------------
+// Cleans up the key arrays
+// --------------------------
+Input::~Input()
+{
+ delete[] kbState;
+ delete[] prevKbState;
+}
+
+// ---------------------------------------------------
+// Initializes the input variables and sets up the
+// initial arrays of key states
+//
+// windowHandle - the handle (id) of the window,
+// which is necessary for mouse input
+// ---------------------------------------------------
+void Input::Initialize(HWND windowHandle)
+{
+ kbState = new unsigned char[256];
+ prevKbState = new unsigned char[256];
+
+ memset(kbState, 0, sizeof(unsigned char) * 256);
+ memset(prevKbState, 0, sizeof(unsigned char) * 256);
+
+ wheelDelta = 0.0f;
+ mouseX = 0; mouseY = 0;
+ prevMouseX = 0; prevMouseY = 0;
+ mouseXDelta = 0; mouseYDelta = 0;
+
+ this->windowHandle = windowHandle;
+}
+
+// ----------------------------------------------------------
+// Updates the input manager for this frame. This should
+// be called at the beginning of every Game::Update(),
+// before anything that might need input
+// ----------------------------------------------------------
+void Input::Update()
+{
+ // Copy the old keys so we have last frame's data
+ memcpy(prevKbState, kbState, sizeof(unsigned char) * 256);
+
+ // Get the latest keys (from Windows)
+ GetKeyboardState(kbState);
+
+ // Get the current mouse position then make it relative to the window
+ POINT mousePos = {};
+ GetCursorPos(&mousePos);
+ ScreenToClient(windowHandle, &mousePos);
+
+ // Save the previous mouse position, then the current mouse
+ // position and finally calculate the change from the previous frame
+ prevMouseX = mouseX;
+ prevMouseY = mouseY;
+ mouseX = mousePos.x;
+ mouseY = mousePos.y;
+ mouseXDelta = mouseX - prevMouseX;
+ mouseYDelta = mouseY - prevMouseY;
+}
+
+// ----------------------------------------------------------
+// Resets the mouse wheel value at the end of the frame.
+// This cannot occur earlier in the frame, since the wheel
+// input comes from Win32 windowing messages, which are
+// handled between frames.
+// ----------------------------------------------------------
+void Input::EndOfFrame()
+{
+ // Reset wheel value
+ wheelDelta = 0;
+}
+
+// ----------------------------------------------------------
+// Get the mouse's current position in pixels relative
+// to the top left corner of the window.
+// ----------------------------------------------------------
+int Input::GetMouseX() { return mouseX; }
+int Input::GetMouseY() { return mouseY; }
+
+
+// ---------------------------------------------------------------
+// Get the mouse's change (delta) in position since last
+// frame in pixels relative to the top left corner of the window.
+// ---------------------------------------------------------------
+int Input::GetMouseXDelta() { return mouseXDelta; }
+int Input::GetMouseYDelta() { return mouseYDelta; }
+
+
+// ---------------------------------------------------------------
+// Get the mouse wheel delta for this frame. Note that there is
+// no absolute position for the mouse wheel; this is either a
+// positive number, a negative number or zero.
+// ---------------------------------------------------------------
+float Input::GetMouseWheel() { return wheelDelta; }
+
+
+// ---------------------------------------------------------------
+// Sets the mouse wheel delta for this frame. This is called
+// by DXCore whenever an OS-level mouse wheel message is sent
+// to the application. You'll never need to call this yourself.
+// ---------------------------------------------------------------
+void Input::SetWheelDelta(float delta)
+{
+ wheelDelta = delta;
+}
+
+
+// ----------------------------------------------------------
+// Is the given key down this frame?
+//
+// key - The key to check, which could be a single character
+// like 'W' or '3', or a virtual key code like VK_TAB,
+// VK_ESCAPE or VK_SHIFT.
+// ----------------------------------------------------------
+bool Input::KeyDown(int key)
+{
+ if (key < 0 || key > 255) return false;
+
+ return (kbState[key] & 0x80) != 0;
+}
+
+// ----------------------------------------------------------
+// Is the given key up this frame?
+//
+// key - The key to check, which could be a single character
+// like 'W' or '3', or a virtual key code like VK_TAB,
+// VK_ESCAPE or VK_SHIFT.
+// ----------------------------------------------------------
+bool Input::KeyUp(int key)
+{
+ if (key < 0 || key > 255) return false;
+
+ return !(kbState[key] & 0x80);
+}
+
+// ----------------------------------------------------------
+// Was the given key initially pressed this frame?
+//
+// key - The key to check, which could be a single character
+// like 'W' or '3', or a virtual key code like VK_TAB,
+// VK_ESCAPE or VK_SHIFT.
+// ----------------------------------------------------------
+bool Input::KeyPress(int key)
+{
+ if (key < 0 || key > 255) return false;
+
+ return
+ kbState[key] & 0x80 && // Down now
+ !(prevKbState[key] & 0x80); // Up last frame
+}
+
+// ----------------------------------------------------------
+// Was the given key initially released this frame?
+//
+// key - The key to check, which could be a single character
+// like 'W' or '3', or a virtual key code like VK_TAB,
+// VK_ESCAPE or VK_SHIFT.
+// ----------------------------------------------------------
+bool Input::KeyRelease(int key)
+{
+ if (key < 0 || key > 255) return false;
+
+ return
+ !(kbState[key] & 0x80) && // Up now
+ prevKbState[key] & 0x80; // Down last frame
+}
+
+
+// ----------------------------------------------------------
+// A utility function to fill a given array of booleans
+// with the current state of the keyboard. This is most
+// useful when hooking the engine's input up to another
+// system, such as a user interface library. (You probably
+// won't use this very much, if at all!)
+//
+// keyArray - pointer to a boolean array which will be
+// filled with the current keyboard state
+// size - the size of the boolean array (up to 256)
+//
+// Returns true if the size parameter was valid and false
+// if it was <= 0 or > 256
+// ----------------------------------------------------------
+bool Input::GetKeyArray(bool* keyArray, int size)
+{
+ if (size <= 0 || size > 256) return false;
+
+ // Loop through the given size and fill the
+ // boolean array. Note that the double exclamation
+ // point is on purpose; it's a quick way to
+ // convert any number to a boolean.
+ for (int i = 0; i < size; i++)
+ keyArray[i] = !!(kbState[i] & 0x80);
+
+ return true;
+}
+
+
+// ----------------------------------------------------------
+// Is the specific mouse button down this frame?
+// ----------------------------------------------------------
+bool Input::MouseLeftDown() { return (kbState[VK_LBUTTON] & 0x80) != 0; }
+bool Input::MouseRightDown() { return (kbState[VK_RBUTTON] & 0x80) != 0; }
+bool Input::MouseMiddleDown() { return (kbState[VK_MBUTTON] & 0x80) != 0; }
+
+
+// ----------------------------------------------------------
+// Is the specific mouse button up this frame?
+// ----------------------------------------------------------
+bool Input::MouseLeftUp() { return !(kbState[VK_LBUTTON] & 0x80); }
+bool Input::MouseRightUp() { return !(kbState[VK_RBUTTON] & 0x80); }
+bool Input::MouseMiddleUp() { return !(kbState[VK_MBUTTON] & 0x80); }
+
+
+// ----------------------------------------------------------
+// Was the specific mouse button initially
+// pressed or released this frame?
+// ----------------------------------------------------------
+bool Input::MouseLeftPress() { return kbState[VK_LBUTTON] & 0x80 && !(prevKbState[VK_LBUTTON] & 0x80); }
+bool Input::MouseLeftRelease() { return !(kbState[VK_LBUTTON] & 0x80) && prevKbState[VK_LBUTTON] & 0x80; }
+
+bool Input::MouseRightPress() { return kbState[VK_RBUTTON] & 0x80 && !(prevKbState[VK_RBUTTON] & 0x80); }
+bool Input::MouseRightRelease() { return !(kbState[VK_RBUTTON] & 0x80) && prevKbState[VK_RBUTTON] & 0x80; }
+
+bool Input::MouseMiddlePress() { return kbState[VK_MBUTTON] & 0x80 && !(prevKbState[VK_MBUTTON] & 0x80); }
+bool Input::MouseMiddleRelease() { return !(kbState[VK_MBUTTON] & 0x80) && prevKbState[VK_MBUTTON] & 0x80; }
diff --git a/Input.h b/Input.h
new file mode 100644
index 0000000..7914a11
--- /dev/null
+++ b/Input.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include
+
+class Input
+{
+#pragma region Singleton
+public:
+ // Gets the one and only instance of this class
+ static Input& GetInstance()
+ {
+ if (!instance)
+ {
+ instance = new Input();
+ }
+
+ return *instance;
+ }
+
+ // Remove these functions (C++ 11 version)
+ Input(Input const&) = delete;
+ void operator=(Input const&) = delete;
+
+private:
+ static Input* instance;
+ Input() {};
+#pragma endregion
+
+public:
+ ~Input();
+
+ void Initialize(HWND windowHandle);
+ void Update();
+ void EndOfFrame();
+
+ int GetMouseX();
+ int GetMouseY();
+ int GetMouseXDelta();
+ int GetMouseYDelta();
+ float GetMouseWheel();
+ void SetWheelDelta(float delta);
+
+ bool KeyDown(int key);
+ bool KeyUp(int key);
+
+ bool KeyPress(int key);
+ bool KeyRelease(int key);
+
+ bool GetKeyArray(bool* keyArray, int size = 256);
+
+ bool MouseLeftDown();
+ bool MouseRightDown();
+ bool MouseMiddleDown();
+
+ bool MouseLeftUp();
+ bool MouseRightUp();
+ bool MouseMiddleUp();
+
+ bool MouseLeftPress();
+ bool MouseLeftRelease();
+
+ bool MouseRightPress();
+ bool MouseRightRelease();
+
+ bool MouseMiddlePress();
+ bool MouseMiddleRelease();
+
+private:
+ // Arrays for the current and previous key states
+ unsigned char* kbState;
+ unsigned char* prevKbState;
+
+ // Mouse position and wheel data
+ int mouseX;
+ int mouseY;
+ int prevMouseX;
+ int prevMouseY;
+ int mouseXDelta;
+ int mouseYDelta;
+ float wheelDelta;
+
+ // The window's handle (id) from the OS, so
+ // we can get the cursor's position
+ HWND windowHandle;
+};
+