From ecae5287cc89f9840c6b05df170280b6cc4ee86e Mon Sep 17 00:00:00 2001 From: Brett Date: Fri, 3 May 2024 22:14:48 -0400 Subject: [PATCH] post processing --- CMakeLists.txt | 2 +- include/blt/gfx/framebuffer.h | 2 + include/blt/gfx/renderer/batch_2d_renderer.h | 3 +- .../{post_process.h => postprocess.h} | 78 +++++---- .../blt/gfx/renderer/shaders/postprocess.vert | 32 ++++ .../gfx/renderer/shaders/pp_to_screen.frag | 22 +++ include/blt/gfx/window.h | 23 ++- src/blt/gfx/framebuffer.cpp | 7 +- src/blt/gfx/renderer/batch_2d_renderer.cpp | 38 +++-- src/blt/gfx/renderer/postprocess.cpp | 106 +++++++++++- src/blt/gfx/window.cpp | 156 ++++++++++-------- 11 files changed, 342 insertions(+), 127 deletions(-) rename include/blt/gfx/renderer/{post_process.h => postprocess.h} (54%) create mode 100644 include/blt/gfx/renderer/shaders/postprocess.vert create mode 100644 include/blt/gfx/renderer/shaders/pp_to_screen.frag diff --git a/CMakeLists.txt b/CMakeLists.txt index 61a4957..9ae4b44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.25) -set(BLT_GRAPHICS_VERSION 0.13.2) +set(BLT_GRAPHICS_VERSION 0.13.3) set(BLT_GRAPHICS_TEST_VERSION 0.0.1) project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION}) diff --git a/include/blt/gfx/framebuffer.h b/include/blt/gfx/framebuffer.h index a535583..94bb604 100644 --- a/include/blt/gfx/framebuffer.h +++ b/include/blt/gfx/framebuffer.h @@ -123,6 +123,8 @@ namespace blt::gfx static void unbind(); + static void bindScreen(draw_t type); + void destroy(); [[nodiscard]] i32 getHeight() const diff --git a/include/blt/gfx/renderer/batch_2d_renderer.h b/include/blt/gfx/renderer/batch_2d_renderer.h index 9b2f8bd..e34d925 100644 --- a/include/blt/gfx/renderer/batch_2d_renderer.h +++ b/include/blt/gfx/renderer/batch_2d_renderer.h @@ -23,6 +23,7 @@ #include "blt/gfx/shader.h" #include "blt/gfx/framebuffer.h" #include "blt/gfx/renderer/resource_manager.h" +#include "blt/gfx/renderer/postprocess.h" #include #include #include @@ -148,7 +149,7 @@ namespace blt::gfx class batch_renderer_2d { private: - frame_buffer_t draw_buffer; + pp_engine_t engine; template struct render_object_t diff --git a/include/blt/gfx/renderer/post_process.h b/include/blt/gfx/renderer/postprocess.h similarity index 54% rename from include/blt/gfx/renderer/post_process.h rename to include/blt/gfx/renderer/postprocess.h index f1d267a..7d6cbc4 100644 --- a/include/blt/gfx/renderer/post_process.h +++ b/include/blt/gfx/renderer/postprocess.h @@ -28,56 +28,74 @@ namespace blt::gfx { - namespace detail - { - class pp_link; - - class pp_iterator; - - class pp_link - { - public: - - private: - - }; - - class pp_iterator - { - public: - - private: - - }; - } + class pp_engine_t; - class pp_step + class pp_step_t; + + class pp_step_t { public: - virtual void create(i32 width, i32 height) = 0; + virtual void create() = 0; - virtual void draw(i32 width, i32 height) = 0; + virtual void draw() = 0; frame_buffer_t& getBuffer() { return draw_buffer; } + + shader_t& getShader() + { + return *shader; + } + + virtual ~pp_step_t() = default; protected: frame_buffer_t draw_buffer; + std::unique_ptr shader; }; - class pp_engine + class pp_render_target_t : public pp_step_t + { + public: + void create() override; + + void draw() override; + }; + + class pp_to_screen_step_t : public pp_step_t + { + public: + void create() override; + + void draw() override; + }; + + class pp_engine_t { public: void create(); - void render(i32 width, i32 height); + void bind(); + + void render(); + + void cleanup(); + + void addStep(std::unique_ptr step) + { + steps.emplace_back(std::move(step)); + } + + static std::unique_ptr createShader(std::string_view fragment); private: - std::vector> steps; - shader_t screen_shader; - + std::vector> steps; + std::unique_ptr screen_vao; +#ifdef __EMSCRIPTEN__ + std::unique_ptr to_screen; +#endif }; } diff --git a/include/blt/gfx/renderer/shaders/postprocess.vert b/include/blt/gfx/renderer/shaders/postprocess.vert new file mode 100644 index 0000000..0e73261 --- /dev/null +++ b/include/blt/gfx/renderer/shaders/postprocess.vert @@ -0,0 +1,32 @@ +#ifdef __cplusplus +#include +const std::string shader_postprocess_vert = R"(" +#version 300 es +precision mediump float; + +layout (location = 0) in vec3 vertex; +layout (location = 1) in vec2 uv_in; + +out vec2 pos; +out vec2 uv; + +layout (std140) uniform GlobalMatrices +{ + mat4 projection; + mat4 ortho; + mat4 view; + mat4 pvm; + mat4 ovm; +}; + +uniform mat4 model; +uniform float z_index; + +void main() { + gl_Position = ovm * model * vec4(vertex.xy, z_index, 1.0); + pos = vertex.xy; + uv = uv_in; +} + +")"; +#endif \ No newline at end of file diff --git a/include/blt/gfx/renderer/shaders/pp_to_screen.frag b/include/blt/gfx/renderer/shaders/pp_to_screen.frag new file mode 100644 index 0000000..307d1b8 --- /dev/null +++ b/include/blt/gfx/renderer/shaders/pp_to_screen.frag @@ -0,0 +1,22 @@ +#ifdef __cplusplus +#include +const std::string shader_pp_to_screen_frag = R"(" +#version 300 es +precision mediump float; + +out vec4 FragColor; +in vec2 uv; +in vec2 pos; + +uniform sampler2D tex; + +vec4 linear_iter(vec4 i, vec4 p, float factor){ + return (i + p) * factor; +} + +void main() { + FragColor = texture(tex, uv); +} + +")"; +#endif \ No newline at end of file diff --git a/include/blt/gfx/window.h b/include/blt/gfx/window.h index 8d53480..0bacabd 100644 --- a/include/blt/gfx/window.h +++ b/include/blt/gfx/window.h @@ -9,6 +9,7 @@ #define BLT_WITH_GRAPHICS_TEMPLATE_WINDOW_H #include +#include #include #include #include @@ -19,11 +20,11 @@ namespace blt::gfx { struct window_context { - std::int32_t GL_MAJOR = 4; - std::int32_t GL_MINOR = 6; - std::int32_t DOUBLE_BUFFER = GLFW_TRUE; - std::int32_t GL_PROFILE = GLFW_OPENGL_CORE_PROFILE; - std::int32_t SAMPLES = 8; + i32 GL_MAJOR = 4; + i32 GL_MINOR = 6; + i32 DOUBLE_BUFFER = GLFW_TRUE; + i32 GL_PROFILE = GLFW_OPENGL_CORE_PROFILE; + i32 SAMPLES = 8; }; struct window_data @@ -39,9 +40,9 @@ namespace blt::gfx window_context context{}; std::int32_t sync_interval = 0; - window_data(std::string title, std::function init, std::function update, - std::int32_t width = 640, std::int32_t height = 480): init(std::move(init)), update(std::move(update)), - title(std::move(title)), width(width), height(height) + window_data(std::string_view title, std::function init, std::function update, + i32 width = 640, i32 height = 480): init(std::move(init)), update(std::move(update)), + title(title), width(width), height(height) {} inline void call_init() const @@ -128,7 +129,11 @@ namespace blt::gfx double getFrameDeltaMilliseconds(); - std::int64_t getFrameDelta(); + i64 getFrameDelta(); + + i32 getWindowWidth(); + + i32 getWindowHeight(); void cleanup(); diff --git a/src/blt/gfx/framebuffer.cpp b/src/blt/gfx/framebuffer.cpp index bc6939d..fd6db4a 100644 --- a/src/blt/gfx/framebuffer.cpp +++ b/src/blt/gfx/framebuffer.cpp @@ -279,9 +279,14 @@ namespace blt::gfx fbo.attachRenderBuffer(depth_rbo, attachment_t::DEPTH_STENCIL); if (!frame_buffer_t::validate()) - BLT_ERROR("Failed to create multi-sampled render texture framebuffer!"); + BLT_ERROR("Failed to create render texture framebuffer!"); frame_buffer_t::unbind(); return fbo; } + + void frame_buffer_t::bindScreen(frame_buffer_t::draw_t type) + { + glBindFramebuffer(static_cast(type), 0); + } } \ No newline at end of file diff --git a/src/blt/gfx/renderer/batch_2d_renderer.cpp b/src/blt/gfx/renderer/batch_2d_renderer.cpp index baa301c..4f70f6d 100644 --- a/src/blt/gfx/renderer/batch_2d_renderer.cpp +++ b/src/blt/gfx/renderer/batch_2d_renderer.cpp @@ -89,20 +89,23 @@ namespace blt::gfx point_shader->bindAttribute(0, "vertex"); point_shader->bindAttribute(1, "uv_in"); - draw_buffer.create(); - draw_buffer.bind(); + engine.addStep(std::make_unique()); + engine.create(); - auto* texture = new texture_gl2D(1440, 720); - draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0); - auto* mask = new texture_gl2D(1440, 720); - draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1); - - render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, 1440, 720); - draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL); - - if (!frame_buffer_t::validate()) - BLT_ERROR("Failed to create render framebuffer!"); - frame_buffer_t::unbind(); +// draw_buffer.create(); +// draw_buffer.bind(); +// +// auto* texture = new texture_gl2D(1440, 720); +// draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0); +// auto* mask = new texture_gl2D(1440, 720); +// draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1); +// +// render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, 1440, 720); +// draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL); +// +// if (!frame_buffer_t::validate()) +// BLT_ERROR("Failed to create render framebuffer!"); +// frame_buffer_t::unbind(); } void batch_renderer_2d::drawRectangleInternal(const std::string_view texture, const rectangle2d_t& rectangle, const f32 z_index) @@ -161,6 +164,7 @@ namespace blt::gfx void batch_renderer_2d::cleanup() { + engine.cleanup(); delete square_vao; delete square_shader; delete point_shader; @@ -168,8 +172,8 @@ namespace blt::gfx void batch_renderer_2d::render(i32 width, i32 height, const bool transparency) { - draw_buffer.bind(); - draw_buffer.updateBuffersStorage(width, height); + //draw_buffer.bind(); + //draw_buffer.updateBuffersStorage(width, height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (transparency) { @@ -179,6 +183,7 @@ namespace blt::gfx glEnable(GL_DEPTH_TEST); glActiveTexture(GL_TEXTURE0); + engine.bind(); draw_objects(); glDisable(GL_DEPTH_TEST); @@ -186,8 +191,9 @@ namespace blt::gfx glDisable(GL_BLEND); render_reset(); - draw_buffer.blitToScreen(width, height); frame_buffer_t::unbind(); + + engine.render(); } void batch_renderer_2d::draw_objects() diff --git a/src/blt/gfx/renderer/postprocess.cpp b/src/blt/gfx/renderer/postprocess.cpp index bfbcf47..eb0c93a 100644 --- a/src/blt/gfx/renderer/postprocess.cpp +++ b/src/blt/gfx/renderer/postprocess.cpp @@ -15,17 +15,115 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include +#include +#include +#include +#include +#include + + +float full_screen_vertices[20] = { + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f +}; +const unsigned int full_screen_indices[6] = { + 0, 1, 3, + 1, 2, 3 +}; namespace blt::gfx { - void pp_engine::create() + void pp_engine_t::create() { - + { + vertex_buffer_t vertices_vbo; + element_buffer_t indices_vbo; + + vertices_vbo.create(); + indices_vbo.create(); + + vertices_vbo.allocate(sizeof(full_screen_vertices), full_screen_vertices); + indices_vbo.allocate(sizeof(full_screen_indices), full_screen_indices); + + screen_vao = std::make_unique(); + const auto tb = screen_vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); + screen_vao->bindVBO(tb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); + screen_vao->bindElement(indices_vbo); + } +#ifdef __EMSCRIPTEN__ + to_screen = std::make_unique(); +#endif + for (auto& step : steps) + step->create(); } - void pp_engine::render(i32 width, i32 height) + void pp_engine_t::render() { + screen_vao->bind(); + for (const auto& [index, step] : blt::enumerate(steps)) + { + if (index == 0) + { + continue; + } else + steps[index - 1]->getBuffer().bind(frame_buffer_t::draw_t::READ); + step->draw(); + step->getBuffer().bind(frame_buffer_t::draw_t::DRAW); + step->getShader().bind(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + } + frame_buffer_t::unbind(); +#ifdef __EMSCRIPTEN__ + to_screen->getShader().bind(); + steps.back()->getBuffer().bind(frame_buffer_t::draw_t::READ); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); +#else + steps.back()->getBuffer().blitToScreen(getWindowWidth(), getWindowHeight()); +#endif + } + void pp_engine_t::cleanup() + { + screen_vao = nullptr; + for (auto& v : steps) + v = nullptr; + steps.clear(); + } + + std::unique_ptr pp_engine_t::createShader(std::string_view fragment) + { + auto shader = std::make_unique(shader_postprocess_vert, std::string(fragment)); + shader->bindAttribute(0, "vertex"); + shader->bindAttribute(1, "uv_in"); + return shader; + } + + void pp_engine_t::bind() + { + steps.front()->draw(); + steps.front()->getBuffer().bind(frame_buffer_t::draw_t::DRAW); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + void pp_to_screen_step_t::create() + { + shader = pp_engine_t::createShader(shader_pp_to_screen_frag); + } + + void pp_to_screen_step_t::draw() + {} + + void pp_render_target_t::create() + { + shader = pp_engine_t::createShader(shader_pp_to_screen_frag); + draw_buffer = frame_buffer_t::make_render_target(getWindowWidth(), getWindowHeight()); + } + + void pp_render_target_t::draw() + { + draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); } } \ No newline at end of file diff --git a/src/blt/gfx/window.cpp b/src/blt/gfx/window.cpp index 88b90a8..83dc50d 100644 --- a/src/blt/gfx/window.cpp +++ b/src/blt/gfx/window.cpp @@ -46,7 +46,7 @@ namespace blt::gfx double nanoDelta = 0; double millisDelta = 0; } window_state; - + void create_callbacks() { /* Setup keyboard callback */ @@ -68,7 +68,7 @@ namespace blt::gfx window_state.inputManager.key(key) = state; window_state.inputManager.key_pressed = true; }); - + /* Setup mouse button callback */ glfwSetMouseButtonCallback(window_state.window, [](GLFWwindow*, int button, int action, int) { if (button < 0) @@ -86,40 +86,40 @@ namespace blt::gfx window_state.inputManager.mouse(button) = state; window_state.inputManager.mouse_pressed = true; }); - + /* 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; @@ -131,9 +131,9 @@ namespace blt::gfx 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__ @@ -145,7 +145,7 @@ namespace blt::gfx io.IniFilename = nullptr; #endif } - + void loop(void* arg) { auto& data = *((window_data*) arg); @@ -156,24 +156,24 @@ namespace blt::gfx 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; @@ -183,7 +183,7 @@ namespace blt::gfx } #ifdef __EMSCRIPTEN__ - + EM_BOOL emscripten_resize_callback(int, const EmscriptenUiEvent* event, void* data) { int width = event->documentBodyClientWidth; @@ -203,7 +203,7 @@ namespace blt::gfx }); #endif - + void init(window_data data) { #ifdef __EMSCRIPTEN__ @@ -217,28 +217,28 @@ namespace blt::gfx /* -- 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); - + /* -- Create the Window -- */ window_state.window = glfwCreateWindow(data.width, data.height, data.title.c_str(), nullptr, nullptr); 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 - + /* -- Set up our local callbacks, ImGUI will then call these -- */ create_callbacks(); - + /* -- Set up ImGUI -- */ setup_ImGUI(); @@ -246,7 +246,10 @@ namespace blt::gfx 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(); @@ -264,31 +267,38 @@ namespace blt::gfx loop((void*) &data); #endif } - + 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; } - + + 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__ @@ -298,7 +308,7 @@ namespace blt::gfx return glfwGetWindowAttrib(window_state.window, GLFW_HOVERED); #endif } - + void setRawInput(bool state) { #ifdef __EMSCRIPTEN__ @@ -308,7 +318,7 @@ namespace blt::gfx glfwSetInputMode(window_state.window, GLFW_RAW_MOUSE_MOTION, state ? GLFW_TRUE : GLFW_FALSE); #endif } - + bool isRawInput() { #ifdef __EMSCRIPTEN__ @@ -317,27 +327,43 @@ namespace blt::gfx 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; } - - std::int64_t 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; } - + + 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; } + window_data& window_data::setWindowSize(int32_t new_width, int32_t new_height) { width = new_width;