diff --git a/CMakeLists.txt b/CMakeLists.txt index 9540d7f..5876df0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.25) include(FetchContent) -set(BLT_GRAPHICS_VERSION 2.0.9) +set(BLT_GRAPHICS_VERSION 2.0.10) set(BLT_GRAPHICS_TEST_VERSION 0.0.1) project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION}) diff --git a/libraries/BLT b/libraries/BLT index 9a05c86..e2dc35f 160000 --- a/libraries/BLT +++ b/libraries/BLT @@ -1 +1 @@ -Subproject commit 9a05c86b02c9c45c2b384c531007416148ec4b56 +Subproject commit e2dc35fea98cc62897169cfc50dbf59fd820cd0e diff --git a/src/blt/gfx/window.cpp b/src/blt/gfx/window.cpp index 900de13..4a42624 100644 --- a/src/blt/gfx/window.cpp +++ b/src/blt/gfx/window.cpp @@ -16,423 +16,461 @@ #include #ifdef __EMSCRIPTEN__ - - #include + +#include #include #endif void error_callback(int error, const char* description) { - BLT_ERROR("GLFW Error (%d): %s", error, description); - std::abort(); + BLT_ERROR("GLFW Error (%d): %s", error, description); + std::abort(); } void gl_error_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei, const GLchar* message, const void*) { - // do not log performance concerns - if (type == GL_DEBUG_TYPE_OTHER) - return; - if (type == GL_DEBUG_TYPE_ERROR) - { - BLT_ERROR("[OpenGL Error] message = '{}', type = 0x{:x}, severity = 0x{:x}, source = 0x{:x}, id = {}", - message, type, severity, source, id); - } else - { - BLT_WARN("[OpenGL Error] message = '{}', type = 0x{:x}, severity = 0x{:x}, source = 0x{:x}, id = {}", - message, type, severity, source, id); - } + // do not log performance concerns + if (type == GL_DEBUG_TYPE_OTHER) + return; + if (type == GL_DEBUG_TYPE_ERROR) + { + BLT_ERROR("[OpenGL Error] message = '{}', type = 0x{:x}, severity = 0x{:x}, source = 0x{:x}, id = {}", message, type, severity, source, id); + } else + { + BLT_WARN("[OpenGL Error] message = '{}', type = 0x{:x}, severity = 0x{:x}, source = 0x{:x}, id = {}", message, type, severity, source, id); + } } namespace blt::gfx { - struct - { - /* GLFW Window Object */ - GLFWwindow* window = nullptr; - /* BLT internal input state manager, handles keyboard/mouse allocations + states */ - input_manager inputManager; - /* stores any drag and dropped paths for processing */ - std::queue pendingPaths; - /* current width and height of the window */ - std::int32_t width = 0; - std::int32_t height = 0; - /* Frame time information (last frame) */ - std::int64_t lastTime = blt::system::nanoTime(); - std::int64_t deltaTime = 0; - double nanoDelta = 0; - double millisDelta = 0; - window_data* data = nullptr; - } window_state; - - void create_callbacks() - { - /* Setup keyboard callback */ - glfwSetKeyCallback(window_state.window, [](GLFWwindow*, int key, int, int action, int) { - if (key < 0 || key == GLFW_KEY_UNKNOWN) - return; - KEY_STATE state; - switch (action) - { - case GLFW_PRESS: - state = KEY_STATE::PRESS; - window_state.inputManager.key_pressed = true; - break; - case GLFW_REPEAT: - state = KEY_STATE::REPEAT; - break; - default: - state = KEY_STATE::RELEASE; - window_state.inputManager.key_released = true; - break; - } - window_state.inputManager.key(key) = state; - }); - - /* Setup mouse button callback */ - glfwSetMouseButtonCallback(window_state.window, [](GLFWwindow*, int button, int action, int) { - if (button < 0) - return; - MOUSE_STATE state; - switch (action) - { - case GLFW_PRESS: - state = MOUSE_STATE::PRESS; - window_state.inputManager.mouse_pressed = true; - break; - default: - state = MOUSE_STATE::RELEASE; - window_state.inputManager.mouse_released = true; - break; - } - window_state.inputManager.mouse(button) = state; - }); - - /* Setup mouse cursor callback */ - glfwSetCursorPosCallback(window_state.window, [](GLFWwindow*, double x, double y) { - window_state.inputManager.updateMousePos(x, y); - window_state.inputManager.mouse_moved = true; - }); - - /* Setup mouse scroll callback */ - glfwSetScrollCallback(window_state.window, [](GLFWwindow*, double, double s) { window_state.inputManager.updateScroll(s); }); - - /* Setup drop input callback */ - glfwSetDropCallback(window_state.window, [](GLFWwindow*, int count, const char** paths) { - for (int i = 0; i < count; i++) - window_state.pendingPaths.emplace(paths[i]); - }); - } - - void setup_ImGUI() - { - const char* glsl_version = "#version 100"; - - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - - // Setup Dear ImGui style - ImGui::StyleColorsDark(); -// ImGui::Spectrum::StyleColorsSpectrum(); - ImGui::Spectrum::LoadFont(); - ImGui::SetupImGuiStyle(true, 1.0); - - // Setup FA - ImFontConfig config; - config.MergeMode = true; - config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced - static constexpr ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0}; - io.Fonts->AddFontFromMemoryCompressedBase85TTF(fontAwesomeRegular_compressed_data_base85, 13.0f, &config, icon_ranges); - io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeSolid_compressed_data, static_cast(fontAwesomeSolid_compressed_size), 13.0, &config, - icon_ranges); - io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeBrands_compressed_data, static_cast(fontAwesomeBrands_compressed_size), 13.0, - &config, - icon_ranges); - - //ImGui::StyleColorsLight(); - - // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForOpenGL(window_state.window, true); -#ifdef __EMSCRIPTEN__ -// ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas"); -#endif - ImGui_ImplOpenGL3_Init(glsl_version); + struct + { + /* GLFW Window Object */ + GLFWwindow* window = nullptr; + /* BLT internal input state manager, handles keyboard/mouse allocations + states */ + input_manager inputManager; + /* stores any drag and dropped paths for processing */ + std::queue pendingPaths; + /* current width and height of the window */ + std::int32_t width = 0; + std::int32_t height = 0; + /* Frame time information (last frame) */ + std::int64_t lastTime = blt::system::nanoTime(); + std::int64_t deltaTime = 0; + double nanoDelta = 0; + double millisDelta = 0; + window_data* data = nullptr; + } window_state; -#ifdef __EMSCRIPTEN__ - io.IniFilename = nullptr; -#endif - } - - void loop(void* arg) - { - auto& data = *((window_data*) arg); - /* -- Get the current framebuffer size, update the global width/height state, along with OpenGL viewport -- */ - glfwGetFramebufferSize(window_state.window, &window_state.width, &window_state.height); - glViewport(0, 0, window_state.width, window_state.height); - data.width = window_state.width; - data.height = window_state.height; - // TODO: user option for this - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - /* -- Begin the next ImGUI frame -- */ - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - /* -- Call user update function -- */ - data.call_update(); - - /* -- Render the ImGUI frame -- */ - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - /* -- Update GLFW state -- */ - window_state.inputManager.clear(); - glfwSwapBuffers(window_state.window); - glfwPollEvents(); - - /* -- Update Frame Timing Information -- */ - const auto current_time = system::nanoTime(); - window_state.deltaTime = current_time - window_state.lastTime; - window_state.lastTime = current_time; - window_state.nanoDelta = static_cast(window_state.deltaTime) / 1e9f; - window_state.millisDelta = static_cast(window_state.deltaTime) / 1e6f; - } + void create_callbacks() + { + /* Setup keyboard callback */ + glfwSetKeyCallback(window_state.window, [](GLFWwindow*, int key, int, int action, int) { + if (key < 0 || key == GLFW_KEY_UNKNOWN) + return; + KEY_STATE state; + switch (action) + { + case GLFW_PRESS: + state = KEY_STATE::PRESS; + window_state.inputManager.key_pressed = true; + break; + case GLFW_REPEAT: + state = KEY_STATE::REPEAT; + break; + default: + state = KEY_STATE::RELEASE; + window_state.inputManager.key_released = true; + break; + } + window_state.inputManager.key(key) = state; + }); -#ifdef __EMSCRIPTEN__ - - EM_BOOL emscripten_resize_callback(int, const EmscriptenUiEvent* event, void* data) - { - int width = event->documentBodyClientWidth; - int height = event->documentBodyClientHeight; + /* Setup mouse button callback */ + glfwSetMouseButtonCallback(window_state.window, [](GLFWwindow*, int button, int action, int) { + if (button < 0) + return; + MOUSE_STATE state; + switch (action) + { + case GLFW_PRESS: + state = MOUSE_STATE::PRESS; + window_state.inputManager.mouse_pressed = true; + break; + default: + state = MOUSE_STATE::RELEASE; + window_state.inputManager.mouse_released = true; + break; + } + window_state.inputManager.mouse(button) = state; + }); - glfwSetWindowSize(window_state.window, width, height); + /* Setup mouse cursor callback */ + glfwSetCursorPosCallback(window_state.window, [](GLFWwindow*, double x, double y) { + window_state.inputManager.updateMousePos(x, y); + window_state.inputManager.mouse_moved = true; + }); - return false; - } + /* Setup mouse scroll callback */ + glfwSetScrollCallback(window_state.window, [](GLFWwindow*, double, double s) { + window_state.inputManager.updateScroll(s); + }); - EM_JS(int, get_screen_width, (), { - return document.body.clientWidth; - }); + /* Setup drop input callback */ + glfwSetDropCallback(window_state.window, [](GLFWwindow*, int count, const char** paths) { + for (int i = 0; i < count; i++) + window_state.pendingPaths.emplace(paths[i]); + }); + } - EM_JS(int, get_screen_height, (), { - return document.body.clientHeight; - }); + void setup_ImGUI() + { + const char* glsl_version = "#version 100"; -#endif - - void init(window_data data) - { - window_state.data = &data; // NOLINT -#ifdef __EMSCRIPTEN__ - blt::logging::setLogOutputFormat("[${{TIME}}] [${{LOG_LEVEL}}] (${{FILE}}:${{LINE}}) ${{STR}}\n"); - emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, false, - emscripten_resize_callback); + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - data.width = get_screen_width(); - data.height = get_screen_height(); -#endif - /* -- Set up Error Callback -- */ - glfwSetErrorCallback(error_callback); - BLT_ASSERT(glfwInit() && "Unable to init GLFW. Aborting."); - - /* -- Set up Window Context -- */ - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, data.context.GL_MAJOR); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, data.context.GL_MINOR); - glfwWindowHint(GLFW_DOUBLEBUFFER, data.context.DOUBLE_BUFFER); - glfwWindowHint(GLFW_OPENGL_PROFILE, data.context.GL_PROFILE); - glfwWindowHint(GLFW_SAMPLES, data.context.SAMPLES); - glfwWindowHint(GLFW_MAXIMIZED, data.maximized); - - /* -- Create the Window -- */ - window_state.window = glfwCreateWindow(data.width, data.height, data.title.c_str(), data.monitor, data.share); - data.window = window_state.window; - BLT_ASSERT(window_state.window && "Unable to create GLFW window."); - - /* -- Set Window Specifics + OpenGL -- */ - glfwMakeContextCurrent(window_state.window); -#ifndef __EMSCRIPTEN__ + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + // ImGui::Spectrum::StyleColorsSpectrum(); + ImGui::Spectrum::LoadFont(); + ImGui::SetupImGuiStyle(true, 1.0); + + // Setup FA + ImFontConfig config; + config.MergeMode = true; + config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced + static constexpr ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0}; + io.Fonts->AddFontFromMemoryCompressedBase85TTF(fontAwesomeRegular_compressed_data_base85, 13.0f, &config, icon_ranges); + io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeSolid_compressed_data, static_cast(fontAwesomeSolid_compressed_size), 13.0, &config, + icon_ranges); + io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeBrands_compressed_data, static_cast(fontAwesomeBrands_compressed_size), 13.0, + &config, icon_ranges); + + //ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplGlfw_InitForOpenGL(window_state.window, true); + #ifdef __EMSCRIPTEN__ + // ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas"); + #endif + ImGui_ImplOpenGL3_Init(glsl_version); + + #ifdef __EMSCRIPTEN__ + io.IniFilename = nullptr; + #endif + } + + void loop(void* arg) + { + auto& data = *((window_data*) arg); + /* -- Get the current framebuffer size, update the global width/height state, along with OpenGL viewport -- */ + glfwGetFramebufferSize(window_state.window, &window_state.width, &window_state.height); + glViewport(0, 0, window_state.width, window_state.height); + data.width = window_state.width; + data.height = window_state.height; + // TODO: user option for this + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + /* -- Begin the next ImGUI frame -- */ + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + /* -- Call user update function -- */ + data.call_update(); + + /* -- Render the ImGUI frame -- */ + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + /* -- Update GLFW state -- */ + window_state.inputManager.clear(); + glfwSwapBuffers(window_state.window); + glfwPollEvents(); + + /* -- Update Frame Timing Information -- */ + const auto current_time = system::nanoTime(); + window_state.deltaTime = current_time - window_state.lastTime; + window_state.lastTime = current_time; + window_state.nanoDelta = static_cast(window_state.deltaTime) / 1e9f; + window_state.millisDelta = static_cast(window_state.deltaTime) / 1e6f; + } + + #ifdef __EMSCRIPTEN__ + + EM_BOOL emscripten_resize_callback(int, const EmscriptenUiEvent* event, void* data) + { + int width = event->documentBodyClientWidth; + int height = event->documentBodyClientHeight; + + glfwSetWindowSize(window_state.window, width, height); + + return false; + } + + EM_JS(int, get_screen_width, (), { return document.body.clientWidth; }); + + EM_JS(int, get_screen_height, (), { return document.body.clientHeight; }); + + #endif + + void init(window_data data) + { + window_state.data = &data; // NOLINT + #ifdef __EMSCRIPTEN__ + logging::get_global_config().set_log_format( + std::string("[") + logging::tags::FULL_TIME + "] [" + logging::tags::LOG_LEVEL + "] (" + logging::tags::FILE + ":" + logging::tags::LINE + + ") " + logging::tags::STR + "\n"); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, false, emscripten_resize_callback); + + data.width = get_screen_width(); + data.height = get_screen_height(); + #endif + /* -- Set up Error Callback -- */ + glfwSetErrorCallback(error_callback); + BLT_ASSERT(glfwInit() && "Unable to init GLFW. Aborting."); + + /* -- Set up Window Context -- */ + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, data.context.GL_MAJOR); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, data.context.GL_MINOR); + glfwWindowHint(GLFW_DOUBLEBUFFER, data.context.DOUBLE_BUFFER); + glfwWindowHint(GLFW_OPENGL_PROFILE, data.context.GL_PROFILE); + glfwWindowHint(GLFW_SAMPLES, data.context.SAMPLES); + glfwWindowHint(GLFW_MAXIMIZED, data.maximized); + + /* -- Create the Window -- */ + window_state.window = glfwCreateWindow(data.width, data.height, data.title.c_str(), data.monitor, data.share); + data.window = window_state.window; + BLT_ASSERT(window_state.window && "Unable to create GLFW window."); + + /* -- Set Window Specifics + OpenGL -- */ + glfwMakeContextCurrent(window_state.window); + #ifndef __EMSCRIPTEN__ glfwSwapInterval(data.sync_interval); gladLoadGL(glfwGetProcAddress); -#endif + #endif -#ifndef __EMSCRIPTEN__ + #ifndef __EMSCRIPTEN__ glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(gl_error_callback, nullptr); -#endif - - /* -- Set up our local callbacks, ImGUI will then call these -- */ - create_callbacks(); - - /* -- Set up ImGUI -- */ - setup_ImGUI(); + #endif -#ifdef GL_MULTISAMPLE + /* -- Set up our local callbacks, ImGUI will then call these -- */ + create_callbacks(); + + /* -- Set up ImGUI -- */ + setup_ImGUI(); + + #ifdef GL_MULTISAMPLE if (data.context.SAMPLES > 0) glEnable(GL_MULTISAMPLE); -#endif - - window_state.width = data.width; - window_state.height = data.height; - - /* -- Call User Provided post-window-init function -- */ - data.call_init(); + #endif -#ifdef __EMSCRIPTEN__ - /* - * "setting 0 or a negative value as the fps will use the browser’s requestAnimationFrame mechanism to call the main loop function. - * This is HIGHLY recommended if you are doing rendering, as the browser’s requestAnimationFrame will - * make sure you render at a proper smooth rate that lines up properly with the browser and monitor." - * https://emscripten.org/docs/api_reference/emscripten.h.html - */ - emscripten_set_main_loop_arg(loop, (void*) &data, 0, true); -#else + window_state.width = data.width; + window_state.height = data.height; + + /* -- Call User Provided post-window-init function -- */ + data.call_init(); + + #ifdef __EMSCRIPTEN__ + /* + * "setting 0 or a negative value as the fps will use the browser’s requestAnimationFrame mechanism to call the main loop function. + * This is HIGHLY recommended if you are doing rendering, as the browser’s requestAnimationFrame will + * make sure you render at a proper smooth rate that lines up properly with the browser and monitor." + * https://emscripten.org/docs/api_reference/emscripten.h.html + */ + emscripten_set_main_loop_arg(loop, (void*) &data, 0, true); + #else /* -- General Loop -- */ while (!glfwWindowShouldClose(window_state.window)) loop((void*) &data); -#endif - - /* -- Call User provided post-loop destroy function. Added for consistency -- */ - data.call_destroy(); - } - - void cleanup() - { - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - - glfwDestroyWindow(window_state.window); - glfwTerminate(); - } - - double getMouseX() - { return window_state.inputManager.mouseX; } - - double getMouseY() - { return window_state.inputManager.mouseY; } - - double getMouseDX() - { return window_state.inputManager.deltaX; } - - double getMouseDY() - { return window_state.inputManager.deltaY; } - - void lockCursor() - { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); } - - void unlockCursor() - { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); } - - bool isCursorLocked() - { return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; } - - bool isCursorInWindow() - { -#ifdef __EMSCRIPTEN__ - // TODO: - return true; -#else + #endif + + /* -- Call User provided post-loop destroy function. Added for consistency -- */ + data.call_destroy(); + } + + void cleanup() + { + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + glfwDestroyWindow(window_state.window); + glfwTerminate(); + } + + double getMouseX() + { + return window_state.inputManager.mouseX; + } + + double getMouseY() + { + return window_state.inputManager.mouseY; + } + + double getMouseDX() + { + return window_state.inputManager.deltaX; + } + + double getMouseDY() + { + return window_state.inputManager.deltaY; + } + + void lockCursor() + { + glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } + + void unlockCursor() + { + glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + + bool isCursorLocked() + { + return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; + } + + bool isCursorInWindow() + { + #ifdef __EMSCRIPTEN__ + // TODO: + return true; + #else return glfwGetWindowAttrib(window_state.window, GLFW_HOVERED); -#endif - } - - void setRawInput(bool state) - { -#ifdef __EMSCRIPTEN__ - // TODO? -#else + #endif + } + + void setRawInput(bool state) + { + #ifdef __EMSCRIPTEN__ + // TODO? + #else if (glfwRawMouseMotionSupported()) glfwSetInputMode(window_state.window, GLFW_RAW_MOUSE_MOTION, state ? GLFW_TRUE : GLFW_FALSE); -#endif - } - - bool isRawInput() - { -#ifdef __EMSCRIPTEN__ - return false; -#else + #endif + } + + bool isRawInput() + { + #ifdef __EMSCRIPTEN__ + return false; + #else return glfwGetInputMode(window_state.window, GLFW_RAW_MOUSE_MOTION); -#endif - } - - void setClipboard(const std::string& str) - { glfwSetClipboardString(window_state.window, str.c_str()); } - - std::string getClipboard() - { return glfwGetClipboardString(window_state.window); } - - bool isMousePressed(int button) - { return window_state.inputManager.isMousePressed(button); } - - bool isKeyPressed(int key) - { return window_state.inputManager.isKeyPressed(key); } - - double getFrameDeltaSeconds() - { return window_state.nanoDelta; } - - double getFrameDeltaMilliseconds() - { return window_state.millisDelta; } - - i64 getFrameDelta() - { return window_state.deltaTime; } - - bool mouseMovedLastFrame() - { return window_state.inputManager.mouse_moved; } - - bool mousePressedLastFrame() - { return window_state.inputManager.mouse_pressed; } - - bool keyPressedLastFrame() - { return window_state.inputManager.key_pressed; } - - i32 getWindowHeight() - { return window_state.height; } - - i32 getWindowWidth() - { return window_state.width; } - - bool keyReleasedLastFrame() - { return window_state.inputManager.key_released; } - - bool mouseReleaseLastFrame() - { return window_state.inputManager.mouse_released; } + #endif + } - void setWindowSize(const i32 width, const i32 height) - { - window_state.data->setWindowSize(width, height); - } + void setClipboard(const std::string& str) + { + glfwSetClipboardString(window_state.window, str.c_str()); + } - window_data& window_data::setWindowSize(int32_t new_width, int32_t new_height) - { - width = new_width; - height = new_height; - glfwSetWindowSize(window_state.window, width, height); - return *this; - } - - window_data& window_data::setMonitor(GLFWmonitor* m) - { - window_data::monitor = m; - return *this; - } - - window_data& window_data::setShare(GLFWwindow* s) - { - window_data::share = s; - return *this; - } - - window_data& window_data::setMaximized(bool b) - { - if (b) - window_data::maximized = GLFW_TRUE; - else - window_data::maximized = GLFW_FALSE; - return *this; - } + std::string getClipboard() + { + return glfwGetClipboardString(window_state.window); + } + + bool isMousePressed(int button) + { + return window_state.inputManager.isMousePressed(button); + } + + bool isKeyPressed(int key) + { + return window_state.inputManager.isKeyPressed(key); + } + + double getFrameDeltaSeconds() + { + return window_state.nanoDelta; + } + + double getFrameDeltaMilliseconds() + { + return window_state.millisDelta; + } + + i64 getFrameDelta() + { + return window_state.deltaTime; + } + + bool mouseMovedLastFrame() + { + return window_state.inputManager.mouse_moved; + } + + bool mousePressedLastFrame() + { + return window_state.inputManager.mouse_pressed; + } + + bool keyPressedLastFrame() + { + return window_state.inputManager.key_pressed; + } + + i32 getWindowHeight() + { + return window_state.height; + } + + i32 getWindowWidth() + { + return window_state.width; + } + + bool keyReleasedLastFrame() + { + return window_state.inputManager.key_released; + } + + bool mouseReleaseLastFrame() + { + return window_state.inputManager.mouse_released; + } + + void setWindowSize(const i32 width, const i32 height) + { + window_state.data->setWindowSize(width, height); + } + + window_data& window_data::setWindowSize(int32_t new_width, int32_t new_height) + { + width = new_width; + height = new_height; + glfwSetWindowSize(window_state.window, width, height); + return *this; + } + + window_data& window_data::setMonitor(GLFWmonitor* m) + { + window_data::monitor = m; + return *this; + } + + window_data& window_data::setShare(GLFWwindow* s) + { + window_data::share = s; + return *this; + } + + window_data& window_data::setMaximized(bool b) + { + if (b) + window_data::maximized = GLFW_TRUE; + else + window_data::maximized = GLFW_FALSE; + return *this; + } }