├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── TestGame └── TestGame.cpp └── src ├── Core ├── EntryPoint.h ├── Events │ ├── Event.h │ ├── EventHandler.cpp │ ├── EventHandler.h │ ├── KeyEvents.h │ ├── MouseEvents.h │ └── WindowEvents.h ├── Game.cpp ├── Game.h ├── Log │ ├── Log.cpp │ ├── Log.h │ ├── MiniLogger.cpp │ └── MiniLogger.h ├── MiniEngine.h ├── MiniTime.cpp ├── MiniTime.h └── MiniWindow.h └── Platforms ├── Linux ├── LinuxWindow.cpp └── LinuxWindow.h └── Windows ├── WindowsWindow.cpp └── WindowsWindow.h /.gitignore: -------------------------------------------------------------------------------- 1 | #Directories 2 | bin/ 3 | .vs/ 4 | CMakeFiles/ 5 | Debug/ 6 | MiniEngine.dir/ 7 | x64/ 8 | 9 | #Extensions 10 | **.vcxproj 11 | **.filters 12 | **.cmake 13 | CMakeCache.txt 14 | **.sln 15 | **.user -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | set(CMAKE_CXX_STANDARD 17) 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | set(CMAKE_CXX_EXTENSIONS OFF) 6 | 7 | project(MiniEngine) 8 | 9 | option(PLATFORM_WINDOWS "Build for windows?" ON) 10 | 11 | # Only Defined when building the engine itself. 12 | list(APPEND COMPILE_DEFS "MINIENGINE_BUILD") 13 | 14 | # If MSVC compiler is used, define _CRT_SECURE_NO_WARNINGS to suppress the std::localtime() warning 15 | if(MSVC) 16 | list(APPEND COMPILE_DEFS "_CRT_SECURE_NO_WARNINGS") 17 | endif() 18 | 19 | 20 | if(PLATFORM_WINDOWS) 21 | list(APPEND COMPILE_DEFS "PLATFORM_WINDOWS") 22 | list(APPEND INCLUDES "${PROJECT_SOURCE_DIR}/src/Platforms/Windows") 23 | list(APPEND SOURCE_FILES src/Platforms/Windows/WindowsWindow.cpp src/Platforms/Windows/WindowsWindow.h) 24 | list(APPEND LIBS gdi32 user32) 25 | else() 26 | list(APPEND INCLUDES "${PROJECT_SOURCE_DIR}/src/Platforms/Linux") 27 | list(APPEND SOURCE_FILES src/Platforms/Linux/LinuxWindow.cpp src/Platforms/Linux/LinuxWindow.h) 28 | list(APPEND LIBS X11) 29 | endif() 30 | 31 | list(APPEND SOURCE_FILES src/Core/Game.cpp src/Core/Game.h src/Core/EntryPoint.h src/Core/MiniWindow.h src/Core/MiniTime.h src/Core/MiniTime.cpp 32 | src/Core/Log/MiniLogger.cpp src/Core/Log/MiniLogger.h src/Core/Log/Log.cpp src/Core/Log/Log.h 33 | src/Core/Events/Event.h src/Core/Events/EventHandler.h src/Core/Events/EventHandler.cpp 34 | src/Core/Events/KeyEvents.h src/Core/Events/MouseEvents.h src/Core/Events/WindowEvents.h) 35 | 36 | add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) 37 | target_compile_definitions(${PROJECT_NAME} PRIVATE ${COMPILE_DEFS} PRIVATE PROJECT_DIR="${PROJECT_SOURCE_DIR}/") 38 | target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDES}) 39 | target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBS}) 40 | 41 | project(TestGame) 42 | set(SOURCE_FILES TestGame/TestGame.cpp src/Core/MiniEngine.h) 43 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 44 | target_compile_definitions(${PROJECT_NAME} PRIVATE PROJECT_DIR="${PROJECT_SOURCE_DIR}/${PROJECT_NAME}/" PRIVATE "_CRT_SECURE_NO_WARNINGS") 45 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) 46 | target_include_directories(${PROJECT_NAME} PUBLIC src/Core) 47 | target_link_libraries(${PROJECT_NAME} PRIVATE MiniEngine) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Harsh Pandey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MiniEngine 2 | just a game engine. 3 | -------------------------------------------------------------------------------- /TestGame/TestGame.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "EntryPoint.h" 3 | 4 | using namespace MiniEngine; 5 | 6 | class TestGame : public Game 7 | { 8 | public: 9 | TestGame() 10 | { 11 | AddWindowEventListener(WindowEvents::WindowResize, TestGame::OnWindowEvent, this); 12 | AddWindowEventListener(WindowEvents::WindowClose, TestGame::OnWindowEvent, this); 13 | 14 | m_MouseMovedEventHandle = AddMouseEventListener(MouseEvents::MouseMoved, TestGame::OnMouseEvent, this); 15 | AddMouseEventListener(MouseEvents::MouseButtonDown, TestGame::OnMouseEvent, this); 16 | AddMouseEventListener(MouseEvents::MouseButtonUp, TestGame::OnMouseEvent, this); 17 | 18 | AddKeyEventListener(KeyEvents::KeyDown, TestGame::OnKeyEvent, this); 19 | AddKeyEventListener(KeyEvents::KeyUp, TestGame::OnKeyEvent, this); 20 | } 21 | ~TestGame() {} 22 | 23 | void OnWindowEvent(const Event& e) 24 | { 25 | if (e.GetType() == WindowEvents::WindowClose) 26 | { 27 | LogInfo("Window Close Event!"); 28 | } 29 | else if (e.GetType() == WindowEvents::WindowResize) 30 | { 31 | auto windowResizeEvent = e.ToType(); 32 | LogInfo("Window Resize Event! New Dimensions: %d x %d", windowResizeEvent.width, windowResizeEvent.height); 33 | } 34 | } 35 | 36 | void OnMouseEvent(const Event& e) 37 | { 38 | if (e.GetType() == MouseEvents::MouseMoved) 39 | { 40 | auto mouseMovedEvent = e.ToType(); 41 | LogInfo("Mouse Moved Event! Mouse Position: (%d, %d)", mouseMovedEvent.x, mouseMovedEvent.y); 42 | } 43 | else if (e.GetType() == MouseEvents::MouseButtonDown) 44 | { 45 | auto mouseButtonDownEvent = e.ToType(); 46 | LogInfo("Mouse Button Down Event! Mouse Button Down: %d", mouseButtonDownEvent.button); 47 | } 48 | else if (e.GetType() == MouseEvents::MouseButtonUp) 49 | { 50 | auto mouseButtonUpEvent = e.ToType(); 51 | LogInfo("Mouse Button Up Event! Mouse Button Up: %d", mouseButtonUpEvent.button); 52 | } 53 | } 54 | 55 | void OnKeyEvent(const Event& e) 56 | { 57 | if (e.GetType() == KeyEvents::KeyDown) 58 | { 59 | auto keyDownEvent = e.ToType(); 60 | LogInfo("Key Down Event! Keycode: %d", keyDownEvent.keycode); 61 | 62 | if (keyDownEvent.keycode == 32) 63 | { 64 | // Space Pressed! 65 | RemoveMouseEventListener(m_MouseMovedEventHandle); 66 | } 67 | } 68 | else if (e.GetType() == KeyEvents::KeyUp) 69 | { 70 | auto keyUpEvent = e.ToType(); 71 | LogInfo("Key Up Event! Keycode: %d", keyUpEvent.keycode); 72 | } 73 | } 74 | 75 | private: 76 | int m_MouseMovedEventHandle = 0; 77 | }; 78 | 79 | MiniEngine::Game* MiniEngine::CreateGame() 80 | { 81 | return new TestGame(); 82 | } -------------------------------------------------------------------------------- /src/Core/EntryPoint.h: -------------------------------------------------------------------------------- 1 | #include "Game.h" 2 | #include 3 | 4 | 5 | extern MiniEngine::Game* MiniEngine::CreateGame(); 6 | 7 | int main() 8 | { 9 | MiniEngine::Game* game = MiniEngine::CreateGame(); 10 | try 11 | { 12 | game->Run(); 13 | } 14 | catch (std::exception e) 15 | { 16 | std::cout << e.what(); 17 | delete game; 18 | return EXIT_FAILURE; 19 | } 20 | 21 | delete game; 22 | return EXIT_SUCCESS; 23 | } 24 | -------------------------------------------------------------------------------- /src/Core/Events/Event.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_H 2 | #define EVENT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace MiniEngine 10 | { 11 | /** 12 | @brief Base class for all events. 13 | */ 14 | template 15 | class Event 16 | { 17 | protected: 18 | T m_Type; 19 | std::string m_Name; 20 | bool m_Handled = false; 21 | public: 22 | Event() = default; 23 | Event(T type, const std::string& name = "") : m_Type(type), m_Name(name) {} 24 | virtual ~Event() {} 25 | inline const T GetType() const { return m_Type; } 26 | 27 | template 28 | inline EventType ToType() const 29 | { 30 | return static_cast(*this); 31 | } 32 | 33 | inline const std::string& GetName() const { return m_Name; } 34 | virtual bool Handled() const { return m_Handled; } 35 | }; 36 | 37 | /** 38 | @brief Dispatches events to listener. 39 | SendEvent(): Submit a given event to all the listeners. 40 | AddListener(): Become a listener of an Event. 41 | RemoveListener(): Stops listening to an event. 42 | */ 43 | template 44 | class EventDispatcher 45 | { 46 | private: 47 | using Func = std::function&)>; 48 | std::map> m_Listeners; 49 | int m_NextListenerID = 0; 50 | std::map::iterator>> m_ListenerHandles; 51 | public: 52 | /// @brief Add an Listener to the type of event. 53 | /// @param type Event Type 54 | /// @param func Listener Function 55 | /// @return A handle/ID for the added listener 56 | int AddListener(T type, const Func& func) 57 | { 58 | m_Listeners[type].push_back(func); 59 | int handle = m_NextListenerID++; 60 | m_ListenerHandles[handle] = { type, std::prev(m_Listeners[type].end()) }; 61 | return handle; 62 | } 63 | 64 | /// @brief Removes a listener based on its handle/ID. 65 | /// @param handle The handle/ID of the listener to remove 66 | void RemoveListener(int handle) 67 | { 68 | auto it = m_ListenerHandles.find(handle); 69 | if (it != m_ListenerHandles.end()) { 70 | const auto& listenerInfo = it->second; 71 | auto& listeners = m_Listeners[listenerInfo.first]; 72 | listeners.erase(listenerInfo.second); 73 | m_ListenerHandles.erase(it); 74 | } 75 | } 76 | 77 | #ifdef MINIENGINE_BUILD // To make sure Send Event is only accessible in the Mini Engine Project. 78 | 79 | /// @brief Sends the event to all its listeners. 80 | /// @param event Event To Send. 81 | void SendEvent(const Event& event) 82 | { 83 | if (m_Listeners.find(event.GetType()) == m_Listeners.end()) 84 | return; // Return if no Listner is there for this event. 85 | 86 | // Loop though all Listeners. If the event is not handled yet, we continue to process it. 87 | for (auto&& listener : m_Listeners.at(event.GetType())) { 88 | if (!event.Handled()) listener(event); 89 | } 90 | } 91 | 92 | #endif // MINIENGINE_BUILD 93 | 94 | }; 95 | } 96 | 97 | #endif // !EVENT_H -------------------------------------------------------------------------------- /src/Core/Events/EventHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "EventHandler.h" 2 | 3 | namespace MiniEngine 4 | { 5 | std::unique_ptr EventHandler::s_Instance = nullptr; 6 | 7 | EventHandler* EventHandler::GetInstance() 8 | { 9 | if (!s_Instance) 10 | s_Instance = std::make_unique(); 11 | 12 | return s_Instance.get(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/Events/EventHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_HANDLER_H 2 | #define EVENT_HANDLER_H 3 | 4 | #include "KeyEvents.h" 5 | #include "MouseEvents.h" 6 | #include "WindowEvents.h" 7 | #include 8 | 9 | namespace MiniEngine 10 | { 11 | class EventHandler 12 | { 13 | public: 14 | EventHandler() : WindowEventDispatcher(), MouseEventDispatcher(), KeyEventDispatcher() {} 15 | static EventHandler* GetInstance(); 16 | 17 | // Window Events 18 | EventDispatcher WindowEventDispatcher; 19 | // Mouse Events 20 | EventDispatcher MouseEventDispatcher; 21 | // Keyboard Events 22 | EventDispatcher KeyEventDispatcher; 23 | private: 24 | static std::unique_ptr s_Instance; 25 | }; 26 | 27 | #define AddWindowEventListener(eventType, func, arg) EventHandler::GetInstance()->WindowEventDispatcher.AddListener(eventType, std::bind(&func, arg, std::placeholders::_1)); 28 | #define AddMouseEventListener(eventType, func, arg) EventHandler::GetInstance()->MouseEventDispatcher.AddListener(eventType, std::bind(&func, arg, std::placeholders::_1)); 29 | #define AddKeyEventListener(eventType, func, arg) EventHandler::GetInstance()->KeyEventDispatcher.AddListener(eventType, std::bind(&func, arg, std::placeholders::_1)); 30 | 31 | #define RemoveWindowEventListener(handle) EventHandler::GetInstance()->WindowEventDispatcher.RemoveListener(handle); 32 | #define RemoveMouseEventListener(handle) EventHandler::GetInstance()->MouseEventDispatcher.RemoveListener(handle); 33 | #define RemoveKeyEventListener(handle) EventHandler::GetInstance()->KeyEventDispatcher.RemoveListener(handle); 34 | 35 | #ifdef MINIENGINE_BUILD 36 | 37 | #define SendWindowEvent(_event) EventHandler::GetInstance()->WindowEventDispatcher.SendEvent(_event) 38 | #define SendMouseEvent(_event) EventHandler::GetInstance()->MouseEventDispatcher.SendEvent(_event) 39 | #define SendKeyEvent(_event) EventHandler::GetInstance()->KeyEventDispatcher.SendEvent(_event) 40 | 41 | #endif // MINIENGINE_BUILD 42 | } 43 | 44 | #endif // !EVENT_HANDLER_H 45 | -------------------------------------------------------------------------------- /src/Core/Events/KeyEvents.h: -------------------------------------------------------------------------------- 1 | #ifndef KEY_EVENTS_H 2 | #define KEY_EVENTS_H 3 | 4 | #include "Event.h" 5 | 6 | namespace MiniEngine 7 | { 8 | enum class KeyEvents 9 | { 10 | KeyDown, 11 | KeyUp 12 | }; 13 | 14 | class KeyDownEvent : public Event 15 | { 16 | public: 17 | KeyDownEvent() : Event(KeyEvents::KeyDown, "KeyDownEvent") {} 18 | virtual ~KeyDownEvent() = default; 19 | int keycode = -1; // The ASCII of the key that was Pressed Down! 20 | }; 21 | 22 | class KeyUpEvent : public Event 23 | { 24 | public: 25 | KeyUpEvent() : Event(KeyEvents::KeyUp, "KeyUpEvent") {} 26 | virtual ~KeyUpEvent() = default; 27 | int keycode = -1; // The ASCII of the key that was Lifted Up! 28 | }; 29 | } 30 | 31 | #endif // !KEY_EVENTS_H 32 | -------------------------------------------------------------------------------- /src/Core/Events/MouseEvents.h: -------------------------------------------------------------------------------- 1 | #ifndef MOUSE_EVENTS_H 2 | #define MOUSE_EVENTS_H 3 | 4 | #include "Event.h" 5 | 6 | namespace MiniEngine 7 | { 8 | enum class MouseEvents 9 | { 10 | MouseMoved, 11 | MouseButtonDown, 12 | MouseButtonUp 13 | }; 14 | 15 | class MouseMovedEvent : public Event 16 | { 17 | public: 18 | MouseMovedEvent() : Event(MouseEvents::MouseMoved, "MouseMoved") {} 19 | virtual ~MouseMovedEvent() {} 20 | int x = -1, y = -1; // New Mouse Position in screen coordinates under the current window. 21 | }; 22 | 23 | class MouseButtonDownEvent : public Event 24 | { 25 | public: 26 | MouseButtonDownEvent() : Event(MouseEvents::MouseButtonDown, "MouseButtonDown") {} 27 | virtual ~MouseButtonDownEvent() {} 28 | int button = -1; // Mouse Button that was Down, 1 - LMB, 2 - MMB, 3 - RMB 29 | }; 30 | 31 | class MouseButtonUpEvent : public Event 32 | { 33 | public: 34 | MouseButtonUpEvent() : Event(MouseEvents::MouseButtonUp, "MouseButtonUp") {} 35 | virtual ~MouseButtonUpEvent() {} 36 | int button = -1; // Mouse Button that was Up, 1 - LMB, 2 - MMB, 3 - RMB 37 | }; 38 | } 39 | 40 | #endif // !MOUSE_EVENTS_H -------------------------------------------------------------------------------- /src/Core/Events/WindowEvents.h: -------------------------------------------------------------------------------- 1 | #ifndef WINDOW_EVENTS_H 2 | #define WINDOW_EVENTS_H 3 | 4 | #include "Event.h" 5 | 6 | namespace MiniEngine 7 | { 8 | enum class WindowEvents 9 | { 10 | WindowResize, 11 | WindowClose 12 | }; 13 | 14 | class WindowResizeEvent : public Event 15 | { 16 | public: 17 | WindowResizeEvent() : Event(WindowEvents::WindowResize, "WindowResize") {} 18 | virtual ~WindowResizeEvent() {} 19 | int width = 0, height = 0; // New Width & Height. 20 | }; 21 | 22 | class WindowCloseEvent : public Event 23 | { 24 | public: 25 | WindowCloseEvent() : Event(WindowEvents::WindowClose, "WindowClose") {} 26 | virtual ~WindowCloseEvent() {} 27 | }; 28 | } 29 | 30 | #endif // !WINDOW_EVENTS_H -------------------------------------------------------------------------------- /src/Core/Game.cpp: -------------------------------------------------------------------------------- 1 | #include "Game.h" 2 | #include "MiniTime.h" 3 | #include "Log/Log.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Events/EventHandler.h" 10 | 11 | namespace MiniEngine 12 | { 13 | Game::Game() 14 | { 15 | m_Window = MiniWindow::Create(); 16 | m_StartTime = 0.0f; 17 | } 18 | 19 | void Game::Run() 20 | { 21 | if (!Init()) throw std::runtime_error("Failed to Initialize Game!\n"); 22 | RenderLoop(); 23 | } 24 | 25 | bool Game::Init() 26 | { 27 | Log::Init(); 28 | LogEngineInfo("Initialized Game!"); 29 | m_StartTime = std::chrono::time_point_cast(std::chrono::high_resolution_clock::now()).time_since_epoch().count() / 1000000.0f; 30 | // Subscribe to Window Close Event. 31 | AddWindowEventListener(WindowEvents::WindowClose, Game::OnWindowEvent, this); 32 | return true; 33 | } 34 | 35 | void Game::RenderLoop() 36 | { 37 | MiniTime::timeScale = 1.0f; 38 | while (m_Running) 39 | { 40 | if (MiniTime::timeScale < 0.0f) MiniTime::timeScale = 0.0f; 41 | auto startTime = std::chrono::high_resolution_clock::now(); 42 | if (!m_Running) { Cleanup(); break; } 43 | // Keep on running the engine! 44 | m_Window->OnUpdate(); 45 | auto endTime = std::chrono::high_resolution_clock::now(); 46 | auto start = std::chrono::time_point_cast(startTime).time_since_epoch().count(); 47 | auto end = std::chrono::time_point_cast(endTime).time_since_epoch().count(); 48 | 49 | MiniTime::_unscaledDeltaTime = (float)(end - start) / 1000.0f; 50 | MiniTime::_deltaTime = MiniTime::_unscaledDeltaTime * MiniTime::timeScale; 51 | 52 | MiniTime::_realTimeSinceStartup = end / 1000000.0f - m_StartTime; 53 | MiniTime::_time = MiniTime::_realTimeSinceStartup * MiniTime::timeScale; 54 | MiniTime::_frameCount++; 55 | 56 | //LogEngineTrace("Time Format: %s\n\t\t\t Delta Time: %f\n\t\t\t Unscaled Delta Time: %f\n\t\t\t Time Scale: %f\n\t\t\t Time: %f\n\t\t\t Real Time Since Startup: %f\n\t\t\t Frame Count: %d", 57 | // MiniTime::GetLocalTimeFormat().c_str(), MiniTime::deltaTime(), MiniTime::unscaledDeltaTime(), MiniTime::timeScale, MiniTime::time(), MiniTime::realTimeSinceStartup(), 58 | // MiniTime::frameCount()); 59 | } 60 | } 61 | 62 | void Game::Cleanup() 63 | { 64 | LogEngineInfo("Cleaning Up!"); 65 | 66 | // Close the window. 67 | m_Window->OnClose(); 68 | } 69 | 70 | void Game::OnWindowEvent(const Event &e) 71 | { 72 | if (e.GetType() == WindowEvents::WindowClose) 73 | { 74 | // Tell the game to stop executing. 75 | m_Running = false; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Core/Game.h: -------------------------------------------------------------------------------- 1 | #ifndef GAME_H 2 | #define GAME_H 3 | 4 | #ifdef PLATFORM_WINDOWS 5 | #include "../Platforms/Windows/WindowsWindow.h" 6 | #else 7 | #include "../Platforms/Linux/LinuxWindow.h" 8 | #endif // PLATFORM_WINDOWS 9 | 10 | #include "Events/EventHandler.h" 11 | 12 | namespace MiniEngine 13 | { 14 | class Game 15 | { 16 | public: 17 | Game(); 18 | virtual ~Game(){} 19 | void Run(); 20 | private: 21 | bool Init(); 22 | void RenderLoop(); 23 | void Cleanup(); 24 | void OnWindowEvent(const Event& e); 25 | private: 26 | bool m_Running = true; 27 | std::unique_ptr m_Window; 28 | float m_StartTime; 29 | }; 30 | 31 | Game* CreateGame(); 32 | } 33 | 34 | #endif -------------------------------------------------------------------------------- /src/Core/Log/Log.cpp: -------------------------------------------------------------------------------- 1 | #include "Log.h" 2 | 3 | namespace MiniEngine 4 | { 5 | std::shared_ptr Log::s_EngineLogger = std::make_shared(); 6 | std::shared_ptr Log::s_GameLogger = std::make_shared(); 7 | 8 | void Log::Init() 9 | { 10 | s_EngineLogger->SetInitialString("Engine: "); 11 | s_EngineLogger->SetPriority(MiniLogger::TracePriority); 12 | 13 | s_GameLogger->SetInitialString("Game: "); 14 | s_GameLogger->SetPriority(MiniLogger::TracePriority); 15 | } 16 | } -------------------------------------------------------------------------------- /src/Core/Log/Log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include "MiniLogger.h" 5 | #include 6 | 7 | namespace MiniEngine 8 | { 9 | class Log 10 | { 11 | public: 12 | static void Init(); 13 | 14 | inline static std::shared_ptr& GetEngineLogger() { return s_EngineLogger; } 15 | inline static std::shared_ptr& GetGameLogger() { return s_GameLogger; } 16 | private: 17 | static std::shared_ptr s_EngineLogger; 18 | static std::shared_ptr s_GameLogger; 19 | }; 20 | 21 | #ifdef MINIENGINE_BUILD 22 | #ifndef NDEBUG 23 | #define LogEngineTrace(...) Log::GetEngineLogger()->Trace(__VA_ARGS__) 24 | #define LogEngineDebug(...) Log::GetEngineLogger()->Debug(__VA_ARGS__) 25 | #define LogEngineInfo(...) Log::GetEngineLogger()->Info(__VA_ARGS__) 26 | #define LogEngineWarning(...) Log::GetEngineLogger()->Warn(__VA_ARGS__) 27 | #define LogEngineError(...) Log::GetEngineLogger()->Error(__VA_ARGS__) 28 | #else 29 | #define LogEngineTrace(...) 30 | #define LogEngineDebug(...) 31 | #define LogEngineInfo(...) 32 | #define LogEngineWarning(...) 33 | #define LogEngineError(...) 34 | #endif 35 | #else 36 | #ifndef NDEBUG 37 | #define LogTrace(...) Log::GetGameLogger()->Trace(__VA_ARGS__) 38 | #define LogDebug(...) Log::GetGameLogger()->Debug(__VA_ARGS__) 39 | #define LogInfo(...) Log::GetGameLogger()->Info(__VA_ARGS__) 40 | #define LogWarning(...) Log::GetGameLogger()->Warn(__VA_ARGS__) 41 | #define LogError(...) Log::GetGameLogger()->Error(__VA_ARGS__) 42 | #else 43 | #define LogTrace(...) 44 | #define LogDebug(...) 45 | #define LogInfo(...) 46 | #define LogWarning(...) 47 | #define LogError(...) 48 | #endif 49 | #endif 50 | 51 | } 52 | 53 | #endif // !LOG_H -------------------------------------------------------------------------------- /src/Core/Log/MiniLogger.cpp: -------------------------------------------------------------------------------- 1 | #include "MiniLogger.h" 2 | 3 | namespace MiniEngine 4 | { 5 | const char* MiniLogger::NormalColorCode = "\x1B[0m"; 6 | const char* MiniLogger::WhiteColorCode = "\x1B[37m"; 7 | const char* MiniLogger::GreenColorCode = "\x1B[32m"; 8 | const char* MiniLogger::YellowColorCode = "\x1B[33m"; 9 | const char* MiniLogger::RedColorCode = "\x1B[31m"; 10 | 11 | MiniLogger::MiniLogger() : m_Priority(MiniLogger::Priority::DebugPriority), m_InitialString(""), m_FilePath(nullptr), m_File(nullptr), 12 | m_TimeBuffer(), m_TimestampFormat("[%T]") {} 13 | 14 | MiniLogger::~MiniLogger() { FreeFile(); } 15 | 16 | void MiniLogger::FreeFile() 17 | { 18 | if (m_File) 19 | { 20 | std::fclose(m_File); 21 | m_File = 0; 22 | } 23 | } 24 | 25 | bool MiniLogger::EnableFileOutput() 26 | { 27 | FreeFile(); 28 | m_File = std::fopen(m_FilePath, "a"); 29 | 30 | return m_File != 0; 31 | } 32 | 33 | const char* MiniLogger::MessagePriorityToString(Priority messagePriority) 34 | { 35 | const char* priorityString; 36 | 37 | switch (messagePriority) 38 | { 39 | case MiniLogger::TracePriority: priorityString = "[TRACE] "; break; 40 | case MiniLogger::DebugPriority: priorityString = "[DEBUG] "; break; 41 | case MiniLogger::InfoPriority: priorityString = "[INFO] "; break; 42 | case MiniLogger::WarnPriority: priorityString = "[WARN] "; break; 43 | case MiniLogger::ErrorPriority: priorityString = "[ERROR] "; break; 44 | default: priorityString = "[PRIORITY] "; break; 45 | } 46 | 47 | return priorityString; 48 | } 49 | 50 | void MiniLogger::SetColor(Priority messagePriority) 51 | { 52 | const char* color; 53 | switch (messagePriority) 54 | { 55 | case MiniLogger::TracePriority: color = WhiteColorCode; break; 56 | case MiniLogger::DebugPriority: color = WhiteColorCode; break; 57 | case MiniLogger::InfoPriority: color = GreenColorCode; break; 58 | case MiniLogger::WarnPriority: color = YellowColorCode; break; 59 | case MiniLogger::ErrorPriority: color = RedColorCode; break; 60 | default: color = NormalColorCode; break; 61 | } 62 | 63 | std::printf("%s", color); 64 | } 65 | } -------------------------------------------------------------------------------- /src/Core/Log/MiniLogger.h: -------------------------------------------------------------------------------- 1 | // A Simple Thread-safe logger with color coding & output to file options. 2 | #ifndef MINILOGGER_H 3 | #define MINILOGGER_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace MiniEngine 11 | { 12 | class MiniLogger 13 | { 14 | public: 15 | MiniLogger(); 16 | MiniLogger(const MiniLogger&) = delete; 17 | MiniLogger& operator=(const MiniLogger&) = delete; 18 | ~MiniLogger(); 19 | 20 | /// @brief Priority of the Logger, if the current priority is info, 21 | /// then all messages with the priority of Info & Above will be displayed. 22 | enum Priority 23 | { 24 | TracePriority, DebugPriority, InfoPriority, WarnPriority, ErrorPriority 25 | }; 26 | 27 | /// @brief Set The Priority to the given value. 28 | /// @param priority: new priority 29 | void SetPriority(Priority priority) { m_Priority = priority; } 30 | 31 | /// @brief Returns the Current Priority. 32 | const Priority GetPriority() const { return m_Priority; } 33 | 34 | // By setting this to the given string, this string will be printed every line after the time stamp and message priority. 35 | void SetInitialString(const char* initialString) { m_InitialString = initialString; } 36 | 37 | const char* GetInitialString() const { return m_InitialString; } 38 | 39 | // Enable file output 40 | // Logs will be written to /log.txt 41 | // If the file doesn't exist, it will create it automatically 42 | // File will be closed when program stops 43 | // Returns true if a file was successfully opened, false otherwise 44 | 45 | /// @brief If Called & Successfull, then the logs are written to ./log.txt 46 | /// @return Returns true if file was successfully opened. 47 | bool OutputToFile() 48 | { 49 | m_FilePath = "log.txt"; 50 | return EnableFileOutput(); 51 | } 52 | 53 | // Enable file output 54 | // Logs will be written to /filepath, provided the filepath is valid 55 | // If the file doesn't exist, it will create it automatically 56 | // File will be closed when program stops 57 | // Returns true if a file was successfully opened, false otherwise 58 | bool OutputToFile(const char* filepath) 59 | { 60 | m_FilePath = filepath; 61 | return EnableFileOutput(); 62 | } 63 | 64 | // If Output To File was called and no filename was specified, then it will return "log.txt" which is in the working directory. 65 | const char* GetFilePath() const { return m_FilePath; } 66 | 67 | // Format follows strftime format specification 68 | void SetTimestampFormat(const char* timestamp_format) { m_TimestampFormat = timestamp_format; } 69 | 70 | // Format follows strftime format specification 71 | const char* GetTimestampFormat() const { return m_TimestampFormat; } 72 | 73 | // Log a message (format + optional args, follow printf specification) 74 | // with log priority level MiniLogger::Trace 75 | template 76 | void Trace(const char* message, Args&& ... args) 77 | { 78 | Log(TracePriority, message, args...); 79 | } 80 | 81 | // Log a message (format + optional args, follow printf specification) 82 | // with log priority level MiniLogger::Debug 83 | template 84 | void Debug(const char* message, Args&& ... args) 85 | { 86 | Log(DebugPriority, message, args...); 87 | } 88 | 89 | // Log a message (format + optional args, follow printf specification) 90 | // with log priority level MiniLogger::Info 91 | template 92 | void Info(const char* message, Args&& ... args) 93 | { 94 | Log(InfoPriority, message, args...); 95 | } 96 | 97 | // Log a message (format + optional args, follow printf specification) 98 | // with log priority level MiniLogger::Warn 99 | template 100 | void Warn(const char* message, Args&& ... args) 101 | { 102 | Log(WarnPriority, message, args...); 103 | } 104 | 105 | // Log a message (format + optional args, follow printf specification) 106 | // with log priority level MiniLogger::Error 107 | template 108 | void Error(const char* message, Args&& ... args) 109 | { 110 | Log(ErrorPriority, message, args...); 111 | } 112 | 113 | private: 114 | void FreeFile(); 115 | bool EnableFileOutput(); 116 | 117 | const char* MessagePriorityToString(Priority messagePriority); 118 | 119 | void SetColor(Priority messagePriority); 120 | 121 | void Log(Priority messagePriority, const char* message, ...) 122 | { 123 | if (m_Priority <= messagePriority) 124 | { 125 | std::time_t currentTime = std::time(0); 126 | std::tm* timestamp = std::localtime(¤tTime); 127 | 128 | std::scoped_lock lock(m_LogLock); 129 | 130 | SetColor(messagePriority); 131 | std::strftime(m_TimeBuffer, 80, m_TimestampFormat, timestamp); 132 | std::printf("%s ", m_TimeBuffer); 133 | 134 | const char* messagePriorityString = MessagePriorityToString(messagePriority); 135 | std::printf(messagePriorityString, "%s"); 136 | std::printf(m_InitialString, "%s"); 137 | va_list arglist; 138 | va_start(arglist, message); 139 | std::vprintf(message, arglist); 140 | va_end(arglist); 141 | std::printf("\n"); 142 | 143 | std::printf("%s", NormalColorCode); 144 | 145 | if (m_File) 146 | { 147 | std::fprintf(m_File, "%s ", m_TimeBuffer); 148 | std::fprintf(m_File, "%s", messagePriorityString); 149 | std::fprintf(m_File, "%s", m_InitialString); 150 | va_start(arglist, message); 151 | std::vfprintf(m_File, message, arglist); 152 | va_end(arglist); 153 | std::fprintf(m_File, "\n"); 154 | } 155 | } 156 | } 157 | 158 | private: 159 | Priority m_Priority; 160 | std::mutex m_LogLock; 161 | const char* m_InitialString; 162 | char m_TimeBuffer[80]; 163 | const char* m_TimestampFormat; 164 | const char* m_FilePath; 165 | FILE* m_File; 166 | 167 | static const char* NormalColorCode; 168 | static const char* WhiteColorCode; 169 | static const char* GreenColorCode; 170 | static const char* YellowColorCode; 171 | static const char* RedColorCode; 172 | 173 | }; 174 | } 175 | 176 | #endif // !MINILOGGER_H -------------------------------------------------------------------------------- /src/Core/MiniEngine.h: -------------------------------------------------------------------------------- 1 | // Contains all the header files of the game engine that a game needs. 2 | 3 | #ifndef MINIENGINE_H 4 | #define MINIENGINE_H 5 | 6 | #include "Game.h" 7 | #include "MiniTime.h" 8 | #include "Log/Log.h" 9 | #include "Events/EventHandler.h" 10 | 11 | #endif // !MINIENGINE_H -------------------------------------------------------------------------------- /src/Core/MiniTime.cpp: -------------------------------------------------------------------------------- 1 | #include "MiniTime.h" 2 | 3 | namespace MiniEngine 4 | { 5 | float MiniTime::_deltaTime = 0.0f; 6 | float MiniTime::_unscaledDeltaTime = 0.0f; 7 | float MiniTime::_time = 0.0f; 8 | float MiniTime::timeScale = 1.0f; 9 | float MiniTime::_realTimeSinceStartup = 0.0f; 10 | uint32_t MiniTime::_frameCount = 0; 11 | } -------------------------------------------------------------------------------- /src/Core/MiniTime.h: -------------------------------------------------------------------------------- 1 | #ifndef MINITIME_H 2 | #define MINITIME_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace MiniEngine 9 | { 10 | class MiniTime 11 | { 12 | public: 13 | MiniTime() = delete; 14 | MiniTime(const MiniTime&) = delete; 15 | MiniTime& operator=(const MiniTime&) = delete; 16 | 17 | /// @brief Ranges from 0.0f to positive infinity. 18 | static float timeScale; 19 | 20 | /// @brief The MiniTime it took to render this frame(in milliseconds). 21 | static inline float deltaTime() { return _deltaTime; } 22 | /// @brief The MiniTime it took to render this frame unscaled by the timeScale(in milliseconds). 23 | static inline float unscaledDeltaTime() { return _unscaledDeltaTime; } 24 | /// @brief The Real MiniTime since the Engine Started(in seconds). 25 | static inline float realTimeSinceStartup() { return _realTimeSinceStartup; } 26 | /// @brief The MiniTime since the Engine Started scaled by timeScale(in seconds). 27 | static inline float time() { return _time; } 28 | /// @brief The Amount of Frames since Rendering started. 29 | static inline uint32_t frameCount() { return _frameCount; } 30 | /// @brief Returns the Local MiniTime Format as a std::string 31 | static inline std::string GetLocalTimeFormat() 32 | { 33 | auto t = std::time(0); 34 | auto tm = *std::localtime(&t); 35 | 36 | std::ostringstream os; 37 | os << std::put_time(&tm, "%H:%M:%S %d-%m-%Y"); 38 | return os.str(); 39 | } 40 | 41 | friend class Game; 42 | private: 43 | static float _deltaTime; 44 | static float _unscaledDeltaTime; 45 | static float _realTimeSinceStartup; 46 | static float _time; 47 | static uint32_t _frameCount; 48 | }; 49 | } 50 | 51 | #endif // !MINITIME_H -------------------------------------------------------------------------------- /src/Core/MiniWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MINIWINDOW_H 2 | #define MINIWINDOW_H 3 | 4 | #include 5 | 6 | namespace MiniEngine 7 | { 8 | struct WindowProperties 9 | { 10 | const char* Title; 11 | uint32_t Width; 12 | uint32_t Height; 13 | 14 | WindowProperties(const char* title = "Mini Engine", uint32_t width = 800, uint32_t height = 600) 15 | : Title(title), Width(width), Height(height) {} 16 | }; 17 | 18 | class MiniWindow 19 | { 20 | public: 21 | virtual ~MiniWindow() {} 22 | 23 | virtual void OnUpdate() = 0; 24 | virtual void OnDraw() = 0; 25 | virtual void OnClose() = 0; 26 | virtual uint32_t GetWidth() const = 0; 27 | virtual uint32_t GetHeight() const = 0; 28 | 29 | static std::unique_ptr Create(const WindowProperties& props = WindowProperties()); 30 | }; 31 | } 32 | 33 | #endif // !MINIWINDOW_H -------------------------------------------------------------------------------- /src/Platforms/Linux/LinuxWindow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "LinuxWindow.h" 5 | #include "../../Core/Events/EventHandler.h" 6 | #include "../../Core/Log/Log.h" 7 | 8 | namespace MiniEngine 9 | { 10 | std::unique_ptr MiniWindow::Create(const WindowProperties& props) 11 | { 12 | return std::make_unique(props); 13 | } 14 | 15 | LinuxWindow::LinuxWindow(const WindowProperties &windowProps) 16 | { 17 | Init(windowProps); 18 | } 19 | 20 | void LinuxWindow::OnUpdate() 21 | { 22 | Atom wmDeleteMessage = XInternAtom(m_Display, "WM_DELETE_WINDOW", False); 23 | XSetWMProtocols(m_Display, m_Window, &wmDeleteMessage, 1); 24 | 25 | if(XNextEvent(m_Display, &m_Event) == 0) 26 | { 27 | switch(m_Event.type) 28 | { 29 | case ClientMessage: 30 | { 31 | if (m_Event.xclient.data.l[0] == wmDeleteMessage) 32 | { 33 | // Send Window Close Event. 34 | WindowCloseEvent wc; 35 | SendWindowEvent(wc); 36 | } 37 | break; 38 | } 39 | case ConfigureNotify: 40 | { 41 | XConfigureEvent xce = m_Event.xconfigure; 42 | /* This event type is generated for a variety of 43 | happenings, so check whether the window has been 44 | resized. */ 45 | if (xce.width != m_Data.Width || xce.height != m_Data.Height) 46 | { 47 | m_Data.Width = xce.width; 48 | m_Data.Height = xce.height; 49 | 50 | // Send Window Resize Event. 51 | WindowResizeEvent wr; 52 | wr.width = m_Data.Width; 53 | wr.height = m_Data.Height; 54 | SendWindowEvent(wr); 55 | } 56 | break; 57 | } 58 | case MotionNotify: 59 | { 60 | MouseMovedEvent mm; 61 | mm.x = m_Event.xmotion.x; 62 | mm.y = m_Event.xmotion.y; 63 | SendMouseEvent(mm); 64 | break; 65 | } 66 | case ButtonPress: 67 | { 68 | MouseButtonDownEvent mb; 69 | mb.button = m_Event.xbutton.button; 70 | SendMouseEvent(mb); 71 | break; 72 | } 73 | case ButtonRelease: 74 | { 75 | MouseButtonUpEvent mu; 76 | mu.button = m_Event.xbutton.button; 77 | SendMouseEvent(mu); 78 | break; 79 | } 80 | case KeyPress: 81 | { 82 | KeySym key; 83 | char text; 84 | if(XLookupString(&m_Event.xkey, &text, 1, &key,0) == 1) 85 | { 86 | KeyDownEvent kd; 87 | kd.keycode = text; 88 | if(m_RepeatKeys.count(text) == 0) 89 | { 90 | SendKeyEvent(kd); 91 | m_RepeatKeys.insert(text); 92 | } 93 | } 94 | break; 95 | } 96 | case KeyRelease: 97 | { 98 | KeySym key; 99 | char text; 100 | if(XLookupString(&m_Event.xkey, &text, 1, &key,0) == 1) 101 | { 102 | KeyUpEvent ku; 103 | ku.keycode = text; 104 | if(m_RepeatKeys.count(text) >= 0) 105 | { 106 | SendKeyEvent(ku); 107 | m_RepeatKeys.erase(text); 108 | } 109 | } 110 | break; 111 | } 112 | } 113 | } 114 | } 115 | 116 | void LinuxWindow::OnDraw() 117 | { 118 | 119 | } 120 | 121 | void LinuxWindow::OnClose() 122 | { 123 | // Unmap the window, destroy the window 124 | // & close the connection with X Server. 125 | XUnmapWindow(m_Display, m_Window); 126 | XDestroyWindow(m_Display, m_Window); 127 | XCloseDisplay(m_Display); 128 | } 129 | 130 | bool LinuxWindow::Init(const WindowProperties &windowProps) 131 | { 132 | m_Data.Width = windowProps.Width; 133 | m_Data.Height = windowProps.Height; 134 | 135 | if((m_Display = XOpenDisplay(NULL)) == nullptr) 136 | { 137 | LogEngineError("Failed to establish connection with X server."); 138 | return false; 139 | } 140 | 141 | // Get Default display & Root window. 142 | m_Screen = DefaultScreen(m_Display); 143 | m_RootWindow = RootWindow(m_Display, m_Screen); 144 | 145 | // Creating a simple window. 146 | m_Window = XCreateSimpleWindow(m_Display, m_RootWindow, 0, 0, 147 | windowProps.Width, windowProps.Height, 15, BlackPixel(m_Display, m_Screen), BlackPixel(m_Display, m_Screen)); 148 | 149 | if(m_Window == 0) 150 | { 151 | LogEngineError("Failed to create window."); 152 | return false; 153 | } 154 | 155 | XSetStandardProperties(m_Display, m_Window, m_Data.Title, m_Data.Title, None, NULL, 0, NULL); 156 | XSelectInput(m_Display, m_Window, ExposureMask | StructureNotifyMask 157 | | PointerMotionMask | ButtonPressMask | ButtonReleaseMask 158 | | KeyPressMask | KeyReleaseMask); 159 | 160 | // Disable auto-repeat for the window 161 | XkbSetDetectableAutoRepeat(m_Display, true, nullptr); 162 | 163 | // Map window to display server 164 | XMapWindow(m_Display, m_Window); 165 | 166 | return true; 167 | } 168 | } -------------------------------------------------------------------------------- /src/Platforms/Linux/LinuxWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef LINUXWINDOWS_H 2 | #define LINUXWINDOWS_H 3 | 4 | #include 5 | #include 6 | #include "../../Core/MiniWindow.h" 7 | 8 | namespace MiniEngine 9 | { 10 | class LinuxWindow : public MiniWindow 11 | { 12 | public: 13 | LinuxWindow(const WindowProperties& windowProps); 14 | LinuxWindow(const LinuxWindow&) = delete; 15 | LinuxWindow& operator=(const LinuxWindow&) = delete; 16 | virtual ~LinuxWindow() {} 17 | 18 | virtual void OnUpdate() override; 19 | virtual void OnDraw() override; 20 | virtual void OnClose() override; 21 | 22 | virtual uint32_t GetWidth() const override { return m_Data.Width; }; 23 | virtual uint32_t GetHeight() const override { return m_Data.Height; }; 24 | private: 25 | bool Init(const WindowProperties& windowProps); 26 | private: 27 | Display* m_Display; 28 | int m_Screen; 29 | Window m_RootWindow, m_Window; 30 | XEvent m_Event; 31 | // To ignore key events from repeating. 32 | std::unordered_set m_RepeatKeys; 33 | struct WindowData 34 | { 35 | const char* Title; 36 | uint32_t Width, Height; 37 | }m_Data; 38 | }; 39 | } 40 | 41 | #endif // !LINUXWINDOWS_H -------------------------------------------------------------------------------- /src/Platforms/Windows/WindowsWindow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "WindowsWindow.h" 4 | #include "../../Core/Events/EventHandler.h" 5 | 6 | namespace MiniEngine 7 | { 8 | LRESULT WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 9 | { 10 | switch (uMsg) 11 | { 12 | case WM_KEYDOWN: 13 | { 14 | if ((HIWORD(lParam) & KF_REPEAT) != KF_REPEAT) 15 | { 16 | // Key Down Event without repeating. 17 | KeyDownEvent kd; 18 | kd.keycode = (int)wParam; 19 | SendKeyEvent(kd); 20 | } 21 | break; 22 | } 23 | case WM_KEYUP: 24 | { 25 | // Key Up Event. 26 | KeyUpEvent ku; 27 | ku.keycode = (int)wParam; 28 | SendKeyEvent(ku); 29 | break; 30 | } 31 | case WM_MOUSEMOVE: 32 | { 33 | // Mouse Move Event. 34 | MouseMovedEvent me; 35 | me.x = GET_X_LPARAM(lParam); 36 | me.y = GET_Y_LPARAM(lParam); 37 | SendMouseEvent(me); 38 | break; 39 | } 40 | case WM_LBUTTONDOWN: 41 | case WM_MBUTTONDOWN: 42 | case WM_RBUTTONDOWN: 43 | { 44 | // Mouse Button Down Event. 45 | MouseButtonDownEvent md; 46 | // To make sure the input is synonymous in both linux & windows. 47 | // 1 - LMB, 2 - MMB, 3 - RMB 48 | md.button = (uMsg == WM_RBUTTONDOWN) ? 3 : (uMsg == WM_MBUTTONDOWN ? 2 : 1); 49 | SendMouseEvent(md); 50 | break; 51 | } 52 | case WM_LBUTTONUP: 53 | case WM_MBUTTONUP: 54 | case WM_RBUTTONUP: 55 | { 56 | // Mouse Button Up Event. 57 | MouseButtonUpEvent mu; 58 | mu.button = (uMsg == WM_RBUTTONUP) ? 3 : (uMsg == WM_MBUTTONUP ? 2 : 1); 59 | SendMouseEvent(mu); 60 | break; 61 | } 62 | case WM_SIZE: 63 | { 64 | // Window Resize Event. 65 | WindowResizeEvent wr; 66 | wr.width = LOWORD(lParam); // Macro to get the low-order word. 67 | wr.height = HIWORD(lParam); // Macro to get the high-order word. 68 | 69 | // Send Resize Event. 70 | SendWindowEvent(wr); 71 | break; 72 | } 73 | case WM_PAINT: 74 | { 75 | // Paint all the area again. 76 | PAINTSTRUCT ps; 77 | HDC hdc = BeginPaint(hWnd, &ps); 78 | SetDCBrushColor(hdc, RGB(10, 20, 30)); 79 | // All painting occurs here, between BeginPaint and EndPaint. 80 | FillRect(hdc, &ps.rcPaint, (HBRUSH)(GetStockObject(DC_BRUSH))); 81 | EndPaint(hWnd, &ps); 82 | break; 83 | } 84 | case WM_CLOSE: 85 | { 86 | // Window Close Event. 87 | WindowCloseEvent wc; 88 | SendWindowEvent(wc); 89 | break; 90 | } 91 | case WM_DESTROY: 92 | return 0; 93 | } 94 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 95 | } 96 | 97 | std::unique_ptr MiniWindow::Create(const WindowProperties& props) 98 | { 99 | return std::make_unique(props); 100 | } 101 | 102 | WindowsWindow::WindowsWindow(const WindowProperties& windowProps) 103 | : m_hInstance(GetModuleHandle(nullptr)) 104 | { 105 | Init(windowProps); 106 | } 107 | 108 | void WindowsWindow::OnUpdate() 109 | { 110 | if (!ProcessMessages()) return; 111 | } 112 | 113 | void WindowsWindow::OnDraw() 114 | { 115 | 116 | } 117 | 118 | void WindowsWindow::OnClose() 119 | { 120 | // Free the resources. 121 | DestroyWindow(m_hWnd); 122 | PostQuitMessage(0); 123 | UnregisterClass(m_Classname, m_hInstance); 124 | } 125 | 126 | bool WindowsWindow::Init(const WindowProperties& windowProps) 127 | { 128 | m_Data.Title = windowProps.Title; 129 | m_Data.Width = windowProps.Width; 130 | m_Data.Height = windowProps.Height; 131 | 132 | WNDCLASS wndClass = {}; 133 | wndClass.lpszClassName = m_Classname; 134 | wndClass.hInstance = m_hInstance; 135 | wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 136 | wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 137 | wndClass.lpfnWndProc = WindowProc; 138 | 139 | DWORD style = WS_OVERLAPPEDWINDOW; 140 | 141 | RECT rect; 142 | rect.left = 250; 143 | rect.bottom = 250; 144 | rect.right = rect.left + m_Data.Width; 145 | rect.top = rect.bottom + m_Data.Height; 146 | 147 | // To make sure that our window size is the whole canvas and not the outer border. 148 | AdjustWindowRect(&rect, style, false); 149 | 150 | if (!RegisterClass(&wndClass)) 151 | return GetLastError(); 152 | 153 | m_Data.Width = rect.right - rect.left; 154 | m_Data.Height = rect.top - rect.bottom; 155 | printf("WIDTH & HEIGHT of Rect: %d\t%d\n", m_Data.Width, m_Data.Height); 156 | 157 | m_hWnd = CreateWindowEx(0, m_Classname, TEXT(m_Data.Title), style, rect.left, rect.bottom, m_Data.Width, m_Data.Height, NULL, NULL, m_hInstance, NULL); 158 | 159 | if (!m_hWnd) 160 | return GetLastError(); 161 | 162 | ShowWindow(m_hWnd, SW_SHOW); 163 | 164 | return true; 165 | } 166 | 167 | bool WindowsWindow::ProcessMessages() 168 | { 169 | MSG msg = {}; 170 | while (PeekMessage(&msg, m_hWnd, 0u, 0u, PM_REMOVE)) 171 | { 172 | if (msg.message == WM_QUIT) return false; 173 | TranslateMessage(&msg); 174 | DispatchMessage(&msg); 175 | } 176 | 177 | return true; 178 | } 179 | } -------------------------------------------------------------------------------- /src/Platforms/Windows/WindowsWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef WINDOWSWINDOW_H 2 | #define WINDOWSWINDOW_H 3 | 4 | #include 5 | #include "../../Core/MiniWindow.h" 6 | 7 | namespace MiniEngine 8 | { 9 | LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 10 | 11 | class WindowsWindow : public MiniWindow 12 | { 13 | public: 14 | WindowsWindow(const WindowProperties& windowProps); 15 | WindowsWindow(const WindowsWindow&) = delete; 16 | WindowsWindow& operator=(const WindowsWindow&) = delete; 17 | virtual ~WindowsWindow() {} 18 | 19 | virtual void OnUpdate() override; 20 | virtual void OnDraw() override; 21 | virtual void OnClose() override; 22 | 23 | virtual uint32_t GetWidth() const override { return m_Data.Width; }; 24 | virtual uint32_t GetHeight() const override { return m_Data.Height; }; 25 | private: 26 | bool Init(const WindowProperties& windowProps); 27 | bool ProcessMessages(); 28 | private: 29 | HINSTANCE m_hInstance; 30 | HWND m_hWnd; 31 | const TCHAR* m_Classname = TEXT("MiniEngine"); 32 | struct WindowData 33 | { 34 | const char* Title; 35 | uint32_t Width, Height; 36 | }m_Data; 37 | }; 38 | } 39 | 40 | #endif // !WINDOWSWINDOW_H --------------------------------------------------------------------------------