-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWindow.cpp
More file actions
221 lines (205 loc) · 6.47 KB
/
Window.cpp
File metadata and controls
221 lines (205 loc) · 6.47 KB
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
#include "Window.h"
#include <sstream>
#include "imgui/imgui_impl_win32.h"
Window::WndClass Window::WndClass::wndClass;
Window::WndClass::WndClass() noexcept : hInstance(GetModuleHandle(nullptr)) {
//Creating and Registering a WindowClass
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(wc);
wc.style = CS_OWNDC;
wc.lpfnWndProc = HandleMsgSetup;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = nullptr;
wc.hCursor = nullptr;
wc.hbrBackground = nullptr;
wc.lpszMenuName = nullptr;
wc.lpszClassName = getName();
wc.hIconSm = nullptr;
RegisterClassEx(&wc);
}
Window::~Window() {
ImGui_ImplWin32_Shutdown();
DestroyWindow(hWnd);
}
Window::WndClass::~WndClass() { UnregisterClass(wndClassName, getInstance()); }
const char* Window::WndClass::getName() noexcept { return wndClassName; }
HINSTANCE Window::WndClass::getInstance() noexcept { return wndClass.hInstance; }
Window::Window(int w, int h, const char* name) : w(w), h(h) {
RECT wr;
wr.left = 100;
wr.right = w + wr.left;
wr.top = 100;
wr.bottom = h + wr.top;
if (AdjustWindowRect(&wr, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, false) == 0) {
throw WND_LAST_EXCEPT();
}
hWnd = CreateWindow(
WndClass::getName(),
name,
WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT,
wr.right - wr.left, wr.bottom - wr.top,
nullptr, nullptr,
WndClass::getInstance(),
this
);
if (hWnd == nullptr) {
throw WND_LAST_EXCEPT();
}
ShowWindow(hWnd, SW_SHOWDEFAULT);
ImGui_ImplWin32_Init(hWnd);
//Create a graphics object
graphics = std::make_unique<Graphics>(hWnd);
}
std::optional<int> Window::ProcessMessages() {
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
return msg.wParam;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return {};
}
Graphics& Window::accessGraphics() {
if (!graphics) {
throw WND_NOGRAPHICS_EXCEPT();
}
return *graphics;
}
LRESULT __stdcall Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
//Insane evil hack to use OOP on WinApi created windows.
if (msg == WM_NCCREATE) {
//https://en.cppreference.com/w/cpp/language/reinterpret_cast
//Extract the window pointer from created struct.
const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam);
Window* const pWnd = static_cast<Window*>(pCreate->lpCreateParams);
//Save the extracted pointer to GWLP_USERDATA (so now our window class is what is actualy on the WinApi side)
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWnd));
//Swap the message handling procedure to our own
SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::HandleMsgThunk));
//Forward message to our handler
return pWnd->HandleMsg(hWnd, msg, wParam, lParam);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
LRESULT __stdcall Window::HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
//Get pointer to window class
Window* const pWnd = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
return pWnd->HandleMsg(hWnd, msg, wParam, lParam);
}
LRESULT Window::HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept {
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)){
return true;
}
const ImGuiIO imguiIO = ImGui::GetIO();
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
//Check the 30th bit for if the key was being held before
//https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-syskeydown#parameters
if (!(lParam & 0x40000000) || keybd.autorepeatOn()) {
keybd.onKeyDown(static_cast<unsigned char>(wParam));
}
break;
case WM_SYSKEYDOWN: //For handling ALT-key and other systemkeys
if (imguiIO.WantCaptureKeyboard) {
break;
}
if (!(lParam & 0x40000000) || keybd.autorepeatOn()) {
keybd.onKeyDown(static_cast<unsigned char>(wParam));
}
break;
case WM_KEYUP:
keybd.onKeyUp(static_cast<unsigned char>(wParam));
break;
case WM_SYSKEYUP:
if (imguiIO.WantCaptureKeyboard) {
break;
}
keybd.onKeyUp(static_cast<unsigned char>(wParam));
break;
case WM_CHAR:
if (imguiIO.WantCaptureKeyboard) {
break;
}
keybd.onChar(static_cast<unsigned char>(wParam));
break;
case WM_KILLFOCUS:
keybd.clearState();
break;
case WM_MOUSEMOVE:
if (imguiIO.WantCaptureMouse) {
break;
}
const POINTS pt = MAKEPOINTS(lParam);
if (pt.x > 0 && pt.x < w && pt.y > 0 && pt.y < h) {
mouse.onMove(pt.x, pt.y);
if (!mouse.isInWindow()) {
SetCapture(hWnd);
mouse.onWindowEnter();
}
}
else {
if (wParam & (MK_LBUTTON | MK_RBUTTON)) {
mouse.onMove(pt.x, pt.y);
}
else {
ReleaseCapture();
mouse.onWindowLeave();
}
}
break;
case WM_MOUSEWHEEL:
if (imguiIO.WantCaptureMouse) {
break;
}
const POINTS ptWheel = MAKEPOINTS(lParam);
const int delta = GET_WHEEL_DELTA_WPARAM(wParam);
mouse.onMWheelDelta(ptWheel.x, ptWheel.y, delta);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// EXCEPTIONS
std::string Window::Exception::translateErrorCode(HRESULT hr) noexcept {
char* pMsgBuf = nullptr;
// windows will allocate memory for err string and make our pointer point to it
const DWORD nMsgLen = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPSTR>(&pMsgBuf), 0, nullptr
);
if (nMsgLen == 0) {
//failure
return "Unidentified error code";
}
// copy error string from windows-allocated buffer to std::string
std::string errorString = pMsgBuf;
// free windows buffer
LocalFree(pMsgBuf);
return errorString;
}
const char* Window::HRESException::what() const noexcept {
std::ostringstream oss;
oss << getType() << std::endl
<< "[Error Code] " << getErrorCode() << std::endl
<< "[Description] " << getErrorDescription() << std::endl
<< getOriginString();
buf = oss.str();
return buf.c_str();
}
Window::HRESException::HRESException(int line, const char* file, HRESULT hr) noexcept : Exception(line, file), hr(hr) {}
const char* Window::HRESException::getType() const noexcept { return "Corsa Engine: Window HRESException"; }
HRESULT Window::HRESException::getErrorCode() const noexcept { return hr; }
std::string Window::HRESException::getErrorDescription() const noexcept { return Exception::translateErrorCode(hr); }
const char* Window::NoGraphicsException::getType() const noexcept
{
return "Corsa Engine: No Graphics Exception";
}