Khaotic Engine Reborn
Loading...
Searching...
No Matches
system_class.cpp
1#include "system_class.h"
2#include <iostream>
3#include <shellapi.h> // Include for DragAcceptFiles and DragQueryFile
4#include <windows.h>
5extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
6
7system_class::system_class()
8{
9 input_ = 0;
10 application_ = 0;
11 imgui_manager_ = 0;
12 application_name_ = 0;
13 hinstance_ = 0;
14 hwnd_ = 0;
15 initial_window_width_ = 0;
16 initial_window_height_ = 0;
17 is_direct_3d_initialized_ = false;
18
19}
20
21system_class::~system_class()
22{
23}
24
25bool system_class::initialize()
26{
27 int screenHeight, screenWidth = 0;
28 bool result;
29
30 Logger::Get().Log("Initializing system class", __FILE__, __LINE__, Logger::LogLevel::Initialize);
31
32 try
33 {
34 // initialize the windows api.
35 initialize_windows(screenWidth, screenHeight);
36
37 // Create and initialize the input object. This object will be used to handle reading the keyboard input from the user.
38 input_ = std::make_shared<input_class>();
39
40 result = input_->Initialize(hinstance_, hwnd_, screenWidth, screenHeight);
41 if (!result)
42 {
43 Logger::Get().Log("Failed to initialize input class", __FILE__, __LINE__, Logger::LogLevel::Error);
44 return false;
45 }
46
47 // Create and initialize the application class object. This object will handle rendering all the graphics for this application.
48 application_ = std::make_shared<application_class>();
49
50 result = application_->initialize(screenWidth, screenHeight, hwnd_, false);
51 if (!result)
52 {
53 return false;
54 }
55
56 is_direct_3d_initialized_ = true;
57
58 // If we received a WM_SIZE message before Direct3D was initialized, resize the swap chain now
59 if (initial_window_width_ > 0 && initial_window_height_ > 0)
60 {
61 application_->get_direct_3d()->resize_swap_chain(initial_window_width_, initial_window_height_);
62 }
63
64 // initialize imgui
65 if(DEBUG_MODE)
66 {
67 imgui_manager_ = std::make_shared<imguiManager>();
68 imgui_manager_->SetApp(application_);
69 result = imgui_manager_->Initialize(hwnd_, application_->get_direct_3d()->get_device(), application_->get_direct_3d()->get_device_context());
70 if (!result)
71 {
72 return false;
73 }
74 }
75
76 }
77 catch (const std::exception& e)
78 {
79 Logger::Get().Log(std::string("Exception caught during initialization: ") + e.what(), __FILE__, __LINE__, Logger::LogLevel::Error);
80 return false;
81 }
82
83 Logger::Get().Log("System class initialized", __FILE__, __LINE__, Logger::LogLevel::Initialize);
84
85 return true;
86}
87
88void system_class::shutdown()
89{
90 Logger::Get().Log("Shutting down system class", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
91
92 std::lock_guard<std::mutex> guard(render_mutex_);
93
94 // shutdown the window.
95 shutdown_windows();
96
97 Logger::Get().Log("System class shut down", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
98
99}
100
101void system_class::run()
102{
103 MSG msg;
104 bool done, result;
105
106 Logger::Get().Log("Running the system", __FILE__, __LINE__);
107
108 // initialize the message structure.
109 ZeroMemory(&msg, sizeof(MSG));
110
111 // Loop until there is a quit message from the window or the user.
112 done = false;
113
114 while (!done)
115 {
116 // Handle the windows messages.
117 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
118 {
119 if(msg.message == WM_QUIT)
120 {
121 done = true;
122 }
123 else
124 {
125 TranslateMessage(&msg);
126 DispatchMessage(&msg);
127 }
128 }
129
130 // If windows signals to end the application then exit out.
131 if (application_ != nullptr && application_->get_should_quit())
132 {
133 Logger::Get().Log("Received quit signal from application", __FILE__, __LINE__);
134 done = true;
135 }
136 else
137 {
138 // Otherwise do the frame processing.
139 result = frame();
140 if (!result)
141 {
142 Logger::Get().Log("Failed to process frame", __FILE__, __LINE__, Logger::LogLevel::Error);
143 done = true;
144 }
145 }
146
147 }
148
149 return;
150}
151
152bool system_class::frame()
153{
154 // Clear the buffers to begin the scene.
155 application_->get_direct_3d()->begin_scene(0.0f, 0.0f, 0.0f, 1.0f);
156
157 std::lock_guard<std::mutex> guard(render_mutex_);
158 bool result;
159
160 result = input_->Frame();
161 if (!result)
162 {
163 Logger::Get().Log("Failed to process input frame", __FILE__, __LINE__, Logger::LogLevel::Error);
164 return false;
165 }
166
167 // Do the frame processing for the application class object.
168 result = application_->frame(input_.get());
169 if (!result)
170 {
171 Logger::Get().Log("Failed to process application frame", __FILE__, __LINE__, Logger::LogLevel::Error);
172 return false;
173 }
174
175 if(!input_->IsKeyDown(222))
176 {
177 //log the key press
178 is_debug_key_pressed_ = false;
179 }
180 else if (input_->IsKeyDown(222) && !is_debug_key_pressed_)
181 {
182 // Log the key release state
183 is_debug_key_pressed_ = true;
184 DEBUG_MODE = !DEBUG_MODE;
185 }
186
187 if (DEBUG_MODE)
188 {
189 // render ImGui
190 result = imgui_manager_->ImGuiWidgetRenderer();
191 if (!result)
192 {
193 Logger::Get().Log("Failed to render ImGui widgets", __FILE__, __LINE__, Logger::LogLevel::Error);
194 return false;
195 }
196 }
197
198 application_->get_direct_3d()->end_scene();
199
200 return true;
201}
202
203LRESULT CALLBACK system_class::message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
204{
205
206 if (ImGui_ImplWin32_WndProcHandler(hwnd, umsg, wparam, lparam))
207 {
208 return true;
209 }
210
211 switch (umsg)
212 {
213 // Check if a key has been pressed on the keyboard.
214 case WM_KEYDOWN:
215 {
216 // If a key is pressed send it to the input object so it can record that state.
217 input_->KeyDown((unsigned int)wparam);
218 return 0;
219 }
220
221 // Check if a key has been released on the keyboard.
222 case WM_KEYUP:
223 {
224 // If a key is released then send it to the input object so it can unset the state for that key.
225 input_->KeyUp((unsigned int)wparam);
226 return 0;
227 }
228 case WM_SIZE:
229 {
230 int newWidth = LOWORD(lparam);
231 int newHeight = HIWORD(lparam);
232
233 // If Direct3D is initialized, update the swap chain. Otherwise, store the window dimensions
234 if (is_direct_3d_initialized_ && application_ && application_->get_direct_3d())
235 {
236 application_->set_screen_width(newWidth);
237 application_->set_screen_height(newHeight);
238 application_->get_direct_3d()->resize_swap_chain(newWidth, newHeight);
239 }
240 else
241 {
242 initial_window_width_ = newWidth;
243 initial_window_height_ = newHeight;
244 }
245 return 0;
246 }
247 case WM_ENTERSIZEMOVE:
248 {
249 is_resizing_ = true;
250 break;
251 }
252 case WM_EXITSIZEMOVE:
253 {
254 is_resizing_ = false;
255 break;
256 }
257 case WM_DROPFILES:
258 {
259 HDROP hDrop = reinterpret_cast<HDROP>(wparam);
260 UINT numFiles = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0);
261
262 if (numFiles > 0) {
263 for (UINT i = 0; i < numFiles; ++i) {
264 WCHAR filePath[MAX_PATH];
265 DragQueryFile(hDrop, i, filePath, MAX_PATH);
266
267 // Get the file extension
268 std::wstring fileName = filePath;
269 std::wstring extension = fileName.substr(fileName.find_last_of(L".") + 1);
270
271 // Check if the file has a valid extension
272 if (extension == L"txt" || extension == L"kobj") {
273 // Handle dropped files with valid extensions
274 std::wcout << L"File dropped: " << filePath << std::endl;
275 application_->add_kobject(fileName);
276 }
277 else {
278 // Handle files with invalid extensions (optional)
279 std::wcout << L"Ignored file: " << filePath << std::endl;
280 }
281 }
282 }
283
284 DragFinish(hDrop);
285 return 0;
286 }
287 case WM_CLOSE:
288 {
289 Logger::Get().Log("WM_CLOSE message received", __FILE__, __LINE__);
290 application_->set_should_quit(true);
291 return 0;
292 }
293 // Any other messages send to the default message handler as our application won't make use of them.
294 default:
295 {
296 return DefWindowProc(hwnd, umsg, wparam, lparam);
297 }
298
299 }
300
301 return 0;
302}
303
304void system_class::initialize_windows(int& screenWidth, int& screenHeight)
305{
306 WNDCLASSEX wc;
307 DEVMODE dmScreenSettings;
308 int posX, posY;
309
310 Logger::Get().Log("Initializing windows", __FILE__, __LINE__, Logger::LogLevel::Initialize);
311 // Get an external pointer to this object.
312 application_handle = this;
313
314 // Get the instance of this application.
315 hinstance_ = GetModuleHandle(NULL);
316
317 // Give the application a name.
318 application_name_ = L"Khaotic Engine";
319
320 // Setup the windows class with default settings.
321 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
322 wc.lpfnWndProc = wnd_proc;
323 wc.cbClsExtra = 0;
324 wc.cbWndExtra = 0;
325 wc.hInstance = hinstance_;
326 wc.hIcon = LoadIcon(hinstance_,MAKEINTRESOURCE(IDI_ICON1));
327 wc.hIconSm = LoadIcon(hinstance_, MAKEINTRESOURCE(IDI_ICON1));
328 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
329 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
330 wc.lpszMenuName = NULL;
331 wc.lpszClassName = application_name_;
332 wc.cbSize = sizeof(WNDCLASSEX);
333
334 // Register the window class.
335 RegisterClassEx(&wc);
336
337 // Determine the resolution of the clients desktop screen.
338 screenWidth = GetSystemMetrics(SM_CXSCREEN);
339 screenHeight = GetSystemMetrics(SM_CYSCREEN);
340
341 // Setup the screen settings depending on whether it is running in full screen or in windowed mode.
342 if (full_screen)
343 {
344 // If full screen set the screen to maximum size of the users desktop and 32bit.
345 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
346 dmScreenSettings.dmSize = sizeof(dmScreenSettings);
347 dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
348 dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
349 dmScreenSettings.dmBitsPerPel = 32;
350 dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
351
352 // Change the display settings to full screen.
353 ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
354
355 // Set the position of the window to the top left corner.
356 posX = posY = 0;
357 }
358 else
359 {
360 // If windowed then set it to 1600x900 resolution.
361 screenWidth = 1600;
362 screenHeight = 900;
363
364 // Place the window in the middle of the screen.
365 posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2;
366 posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
367 }
368
369 // Create the window with the screen settings and get the handle to it.
370 hwnd_ = CreateWindowEx(WS_EX_APPWINDOW, application_name_, application_name_,
371 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
372 posX, posY, screenWidth, screenHeight, NULL, NULL, hinstance_, NULL);
373
374 // Bring the window up on the screen and set it as main focus.
375 ShowWindow(hwnd_, SW_SHOW);
376 SetForegroundWindow(hwnd_);
377 SetFocus(hwnd_);
378
379 // Hide the mouse cursor.
380 ShowCursor(true);
381
382 //drag and drop
383 DragAcceptFiles(hwnd_, TRUE);
384
385 return;
386}
387
388void system_class::shutdown_windows()
389{
390 Logger::Get().Log("Shutting down the windows", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
391 // Show the mouse cursor.
392 ShowCursor(true);
393
394 // Fix the display settings if leaving full screen mode.
395 if (full_screen)
396 {
397 ChangeDisplaySettings(NULL, 0);
398 }
399
400 // Remove the window.
401 DestroyWindow(hwnd_);
402 hwnd_ = NULL;
403
404 // Remove the application instance.
405 UnregisterClass(application_name_, hinstance_);
406 hinstance_ = NULL;
407
408 // Release the pointer to this class.
409 application_handle = NULL;
410
411 return;
412}
413
414LRESULT CALLBACK wnd_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
415{
416 switch (umessage)
417 {
418 // Check if the window is being destroyed.
419 case WM_DESTROY:
420 {
421 PostQuitMessage(0);
422 return 0;
423 }
424
425 // Check if the window is being closed.
426 case WM_CLOSE:
427 {
428 PostQuitMessage(0);
429 return 0;
430 }
431
432 case WM_DROPFILES:
433 {
434 application_handle->message_handler(hwnd, umessage, wparam, lparam);
435 return(0);
436 }
437
438 // All other messages pass to the message handler in the system class.
439 default:
440 {
441 return application_handle->message_handler(hwnd, umessage, wparam, lparam);
442 }
443 }
444}
445
446void system_class::send_path(wchar_t* path, std::filesystem::path w_folder)
447{
448 application_->set_path(path);
449 application_->set_w_folder(w_folder);
450}
static Logger & Get()
Definition Logger.h:20
void Log(const std::string &message, const std::string &fileName, int lineNumber, LogLevel level=LogLevel::Info)
Definition Logger.h:158