From c0626790767e306171c0628ecb846ab4921eb46e Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 30 Sep 2025 20:22:22 -0400 Subject: [PATCH 01/56] some formatting --- src/gui/gui_logging.hpp | 2 +- src/gui/render/gpu_data/texture.cpp | 2 +- src/gui/render/gpu_data/texture.hpp | 7 ++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/gui/gui_logging.hpp b/src/gui/gui_logging.hpp index 265fe5d9..b2416bf1 100644 --- a/src/gui/gui_logging.hpp +++ b/src/gui/gui_logging.hpp @@ -28,9 +28,9 @@ #include #include +#include #include #include -#include namespace gui { diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index 21822536..b6fedcb9 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -1,7 +1,7 @@ #include "texture.hpp" #include "gui/handler.hpp" -#include "util/color.hpp" +#include "logging.hpp" namespace gui { diff --git a/src/gui/render/gpu_data/texture.hpp b/src/gui/render/gpu_data/texture.hpp index 1f0fa699..16cd629e 100644 --- a/src/gui/render/gpu_data/texture.hpp +++ b/src/gui/render/gpu_data/texture.hpp @@ -2,10 +2,7 @@ #pragma once #include "data_types.hpp" -#include "global_context.hpp" -#include "logging.hpp" #include "types.hpp" -#include "util/color.hpp" #include "util/image.hpp" #include @@ -118,12 +115,12 @@ class Texture2D : virtual public GPUDataRenderBuffer { virtual void connect_depth_texture(GLuint framebuffer_ID) override; inline virtual GPUPixelType - get_type() const { + get_type() const override { return settings_.type; } inline virtual GPUPixelStorageFormat - get_format() const { + get_format() const override { return settings_.internal_format; } From 7d05ad573dc012e84ec24c050f1e5fc951ecba66 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 29 Nov 2025 08:38:09 -0500 Subject: [PATCH 02/56] Create User Interface --- src/gui/render/gpu_data/texture.cpp | 3 +- src/gui/render/structures/window_texture.hpp | 23 +++ src/gui/scene/input.hpp | 2 +- src/gui/scene/scene.hpp | 1 + src/gui/the_buttons/bordered_window.cpp | 11 ++ src/gui/the_buttons/bordered_window.hpp | 24 +++ src/gui/the_buttons/frame.hpp | 166 +++++++++++++++++++ src/gui/the_buttons/user_interface.cpp | 47 ++++++ src/gui/the_buttons/user_interface.hpp | 37 +++++ src/gui/the_buttons/widget.hpp | 10 ++ src/gui/ui/imgui_gui.cpp | 8 + src/gui/ui/user_interface_setup.cpp | 22 +++ src/gui/ui/user_interface_setup.hpp | 9 + 13 files changed, 361 insertions(+), 2 deletions(-) create mode 100644 src/gui/render/structures/window_texture.hpp create mode 100644 src/gui/the_buttons/bordered_window.cpp create mode 100644 src/gui/the_buttons/bordered_window.hpp create mode 100644 src/gui/the_buttons/frame.hpp create mode 100644 src/gui/the_buttons/user_interface.cpp create mode 100644 src/gui/the_buttons/user_interface.hpp create mode 100644 src/gui/the_buttons/widget.hpp create mode 100644 src/gui/ui/user_interface_setup.cpp create mode 100644 src/gui/ui/user_interface_setup.hpp diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index b6fedcb9..5cc75365 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -120,7 +120,8 @@ Texture2D::setup(std::shared_ptr image) { Texture2D::Texture2D( screen_size_t width, screen_size_t height, TextureSettings settings, bool differed ) : - width_(width), height_(height), settings_(settings) { + width_(width), + height_(height), settings_(settings) { if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { setup(nullptr); }); diff --git a/src/gui/render/structures/window_texture.hpp b/src/gui/render/structures/window_texture.hpp new file mode 100644 index 00000000..2dcafd33 --- /dev/null +++ b/src/gui/render/structures/window_texture.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "gui/render/gpu_data/texture.hpp" +#include "screen_data.hpp" + +#include + +namespace gui { +namespace render { + +class WindowTexture : public virtual gpu_data::ScreenData { + private: + // gpu_data::Texture2D texture; + + std::array sub_texture_locations; + + public: + inline WindowTexture(){}; // std::filesystem::path file); + inline virtual ~WindowTexture(){}; +}; + +} // namespace render +} // namespace gui \ No newline at end of file diff --git a/src/gui/scene/input.hpp b/src/gui/scene/input.hpp index 37406e7e..0ba77c43 100644 --- a/src/gui/scene/input.hpp +++ b/src/gui/scene/input.hpp @@ -42,7 +42,7 @@ class Inputs { * @param int action GLFW action one of GLFW_PRESS, GLFW_RELEASE, GLFW_REPEAT * @param int mods GLFW mods enum */ - void + virtual void handle_key_event_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, [[maybe_unused]] int scancode, [[maybe_unused]] int action, diff --git a/src/gui/scene/scene.hpp b/src/gui/scene/scene.hpp index 5a5fc16f..63e310b8 100644 --- a/src/gui/scene/scene.hpp +++ b/src/gui/scene/scene.hpp @@ -28,6 +28,7 @@ #include "gui/render/gpu_data/shadow_map.hpp" #include "gui/render/graphics_shaders/render_types.hpp" #include "gui/render/structures/screen_data.hpp" +#include "gui/the_buttons/bordered_window.hpp" #include "helio.hpp" #include diff --git a/src/gui/the_buttons/bordered_window.cpp b/src/gui/the_buttons/bordered_window.cpp new file mode 100644 index 00000000..ef1e5dd1 --- /dev/null +++ b/src/gui/the_buttons/bordered_window.cpp @@ -0,0 +1,11 @@ +#include "bordered_window.hpp" + +namespace gui { + +namespace the_buttons { + +BorderedWindow::BorderedWindow(std::shared_ptr data) : + data_(data) {} + +} // namespace the_buttons +} // namespace gui \ No newline at end of file diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp new file mode 100644 index 00000000..c4b52759 --- /dev/null +++ b/src/gui/the_buttons/bordered_window.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "gui/render/structures/screen_data.hpp" +#include "gui/render/structures/window_texture.hpp" +#include "widget.hpp" + +#include + +namespace gui { + +namespace the_buttons { + +class BorderedWindow : public virtual Widget { + private: + std::shared_ptr data_; + + public: + BorderedWindow(std::shared_ptr data); + inline virtual ~BorderedWindow(){}; +}; + +} // namespace the_buttons + +} // namespace gui diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp new file mode 100644 index 00000000..ecaaf1e1 --- /dev/null +++ b/src/gui/the_buttons/frame.hpp @@ -0,0 +1,166 @@ +#pragma once + +#include "gui/scene/input.hpp" +#include "types.hpp" + +#include +#include +#include +#include + +namespace gui { + +namespace the_buttons { + +class Frame : public virtual scene::Inputs { + private: + screen_size_t x_position; + screen_size_t y_position; + std::vector> exterior_points; + + Frame* parent; + std::unordered_set children; + /* data */ + void exterior_changed(); // need to change exterior for parent. + + bool is_selected; + + public: + Frame(/* args */){}; + inline virtual ~Frame(){}; // kill children + + bool is_interior(screen_size_t x, screen_size_t y) const; + + bool check_children(); + + bool is_visible(); + + void on_select(); + + void on_end_select(); + + /** + * @brief Handle key input including mouse keys + * + * @param GLFWwindow* window window event came from + * @param int key GLFW key enum + * @param int scancode GLFW scancode enum + * @param int action GLFW action one of GLFW_PRESS, GLFW_RELEASE, GLFW_REPEAT + * @param int mods GLFW mods enum + */ + virtual void + handle_key_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, + [[maybe_unused]] int scancode, [[maybe_unused]] int action, + [[maybe_unused]] int mods + ) {} + + /** + * @brief Handle text input + * + * @param GLFWwindow* window window to listen on + * @param unsigned int codepoint unicode 32 character. + */ + + virtual void + handle_text_input_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] unsigned int codepoint + ) {} + + /** + * @brief Handle mouse movement events. + * + * @param GLFWwindow* window window to listen on + * @param double xpos x position in window coordinates + * @param double ypos y position in window coordinates. + */ + virtual void + handle_mouse_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xpos, + [[maybe_unused]] double ypos + ) {} + + /** + * @brief Handle mouse enter window events + * + * @param GLFWwindow* window window to listen on + * @param int button + * @param int action + * @param int mods + */ + virtual void + handle_mouse_button_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, + [[maybe_unused]] int action, [[maybe_unused]] int mods + ) {} + + /** + * @brief Handle mouse scroll events + * + * @param GLFWwindow* window window to listen on + * @param double xoffset x offset + * @param double yoffset y offset (usually 0) + */ + virtual void + handle_mouse_scroll_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xoffset, + [[maybe_unused]] double yoffset + ) {} + + /** + * @brief Handle joystick event + * + * @param int jid joystick id + * @param int event + */ + virtual void + handle_joystick_input([[maybe_unused]] int jid, [[maybe_unused]] int event) {} + + /** + * @brief Handle file drop event + * + * @param GLFWwindow* window window to listen on + * @param int count number of files passed + * @param const char** paths file paths + */ + virtual void + handle_file_drop_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int count, + [[maybe_unused]] const char** paths + ) {} + + /** + * @brief Handle all pooled inputs + * + * @param GLFWwindow* window window + */ + virtual void + handle_pooled_inputs([[maybe_unused]] GLFWwindow* window) {} + + /** + * @brief Setup so this objects handles inputs correctly + * + * @param GLFWwindow* window window + */ + virtual void + setup([[maybe_unused]] GLFWwindow* window) {} + + /** + * @brief Cleanup to original state + * + * @param GLFWwindow* window window + */ + virtual void + cleanup([[maybe_unused]] GLFWwindow* window) {} +}; + +class UI_Text : public virtual Frame { + private: + std::string text_; +}; + +class Button : public virtual Frame {}; + +} // namespace the_buttons + +} // namespace gui diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp new file mode 100644 index 00000000..c5087e86 --- /dev/null +++ b/src/gui/the_buttons/user_interface.cpp @@ -0,0 +1,47 @@ + + +#include "user_interface.hpp" + +#include "../render/graphics_shaders/program_handler.hpp" +#include "../render/graphics_shaders/shader_program.hpp" +#include "../render/structures/uniform_types.hpp" +#include "manifest/object_handler.hpp" + +namespace gui { +namespace the_buttons { + +UserInterface::UserInterface(shader::ShaderHandler& shader_handler) { + shader::Program& window_render_program = shader_handler.load_program( + "Windows", files::get_resources_path() / "shaders" / "background" / "Sky.vert", + files::get_resources_path() / "shaders" / "Red.frag" + ); + + // Overwrites anything that was there before + std::function render_setup = []() { + // Draw over everything + glDisable(GL_CULL_FACE); + // The sky has no depth + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + }; + + // uniforms + // stars_program.set_uniform(matrix_view_projection_uniform, "MVP"); + + // windows + window_pipeline_ = std::make_shared( + window_render_program, render_setup + ); +} + +void +UserInterface::update(screen_size_t width, screen_size_t height) { + FrameBufferHandler::instance().bind_fbo(0 // the screen + ); + + glClear(GL_DEPTH_BUFFER_BIT); + + window_pipeline_->render(width, height, 0); +} +} // namespace the_buttons +} // namespace gui diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp new file mode 100644 index 00000000..924575e9 --- /dev/null +++ b/src/gui/the_buttons/user_interface.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "../render/graphics_shaders/shader_program.hpp" +#include "frame.hpp" +#include "gui/render/structures/uniform_types.hpp" +#include "widget.hpp" + +#include +#include + +namespace gui { +namespace the_buttons { + +class UserInterface { + private: + // uniform + + // widget renderer + std::shared_ptr window_pipeline_; + + std::list> frames_; + + public: + UserInterface(shader::ShaderHandler& shader_handler); + + void update(screen_size_t width, screen_size_t height); + + inline void + add(std::shared_ptr frame) { + auto pos = frames_.begin(); + frames_.insert(pos, frame); + window_pipeline_->data.push_back(frame.get()); + } +}; + +} // namespace the_buttons +} // namespace gui \ No newline at end of file diff --git a/src/gui/the_buttons/widget.hpp b/src/gui/the_buttons/widget.hpp new file mode 100644 index 00000000..338adaa4 --- /dev/null +++ b/src/gui/the_buttons/widget.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "frame.hpp" +#include "gui/render/structures/window_texture.hpp" + +namespace gui { +namespace the_buttons { +class Widget : public virtual Frame, public virtual gpu_data::ScreenData {}; +} // namespace the_buttons +} // namespace gui \ No newline at end of file diff --git a/src/gui/ui/imgui_gui.cpp b/src/gui/ui/imgui_gui.cpp index 5ce2dc92..a8ab7ade 100644 --- a/src/gui/ui/imgui_gui.cpp +++ b/src/gui/ui/imgui_gui.cpp @@ -11,6 +11,7 @@ #include "../handler.hpp" #include "../scene/controls.hpp" #include "../scene/scene.hpp" +#include "../the_buttons/user_interface.hpp" #include "gui/scene/input.hpp" #include "imgui_style.hpp" #include "imgui_windows.hpp" @@ -18,6 +19,7 @@ #include "manifest/object_handler.hpp" #include "opengl_setup.hpp" #include "scene_setup.hpp" +#include "user_interface_setup.hpp" #include "util/mesh.hpp" #include "world/climate.hpp" #include "world/world.hpp" @@ -100,6 +102,9 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { Scene main_scene(mode->width, mode->height, shadow_map_size, controller); setup(main_scene, shader_handler, world, climate); + the_buttons::UserInterface main_interface(shader_handler); + setup(main_interface); + //! Main loop while (!glfwWindowShouldClose(window)) { @@ -136,6 +141,9 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { // "render" scene to the screen main_scene.copy_to_window(window_width, window_height); + // render interface to screen + main_interface.update(window_width, window_height); + // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp new file mode 100644 index 00000000..5697cc69 --- /dev/null +++ b/src/gui/ui/user_interface_setup.cpp @@ -0,0 +1,22 @@ +#include "user_interface_setup.hpp" + +#include "../the_buttons/bordered_window.hpp" +#include "../the_buttons/user_interface.hpp" + +namespace gui { + +void +setup(the_buttons::UserInterface& user_interface) { + std::shared_ptr a_window = + std::make_shared( + std::make_shared() + ); + + user_interface.add(a_window); + + // window_pipeline->data.push_back(scene.a_window.get()); + + return; +} + +} // namespace gui diff --git a/src/gui/ui/user_interface_setup.hpp b/src/gui/ui/user_interface_setup.hpp new file mode 100644 index 00000000..b88f1d77 --- /dev/null +++ b/src/gui/ui/user_interface_setup.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../the_buttons/user_interface.hpp" + +namespace gui { + +void setup(the_buttons::UserInterface& user_interface); + +} From c99359f4f0946feabe38d71a025f6274f4eff15c Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 30 Nov 2025 07:11:49 -0500 Subject: [PATCH 03/56] widget data and shader --- resources/shaders/overlay/FramedWindow.frag | 12 +++ resources/shaders/overlay/Widget.vert | 15 ++++ .../render/gpu_data/vertex_buffer_object.hpp | 26 ++++-- .../render/graphics_shaders/render_types.hpp | 8 ++ .../graphics_shaders/shader_program.cpp | 30 ++++++- .../graphics_shaders/shader_program.hpp | 20 ++++- src/gui/render/structures/window_texture.cpp | 40 +++++++++ src/gui/render/structures/window_texture.hpp | 86 +++++++++++++++++-- src/gui/the_buttons/bordered_window.cpp | 4 +- src/gui/the_buttons/bordered_window.hpp | 51 ++++++++++- src/gui/the_buttons/frame.hpp | 14 +-- src/gui/the_buttons/user_interface.cpp | 25 ++++-- src/gui/the_buttons/user_interface.hpp | 8 +- src/gui/the_buttons/widget.hpp | 10 --- 14 files changed, 303 insertions(+), 46 deletions(-) create mode 100644 resources/shaders/overlay/FramedWindow.frag create mode 100644 resources/shaders/overlay/Widget.vert create mode 100644 src/gui/render/structures/window_texture.cpp delete mode 100644 src/gui/the_buttons/widget.hpp diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag new file mode 100644 index 00000000..4224a830 --- /dev/null +++ b/resources/shaders/overlay/FramedWindow.frag @@ -0,0 +1,12 @@ +#version 450 core + +// Ouput data +layout(location = 0) out vec3 color; + +in vec2 UV; + +void +main(){ + + color = vec3(UV/50, 0.9); +} diff --git a/resources/shaders/overlay/Widget.vert b/resources/shaders/overlay/Widget.vert new file mode 100644 index 00000000..a01e75ce --- /dev/null +++ b/resources/shaders/overlay/Widget.vert @@ -0,0 +1,15 @@ +#version 450 core + +// Input vertex data, different for all executions of this shader. +layout(location = 0) in vec3 pos; +layout(location = 1) in vec2 vertex_position_screenspace; + +// Output data ; will be interpolated for each fragment. +out vec2 UV; + +void +main() { + gl_Position = vec4(pos, 1); + UV = vertex_position_screenspace; +} + diff --git a/src/gui/render/gpu_data/vertex_buffer_object.hpp b/src/gui/render/gpu_data/vertex_buffer_object.hpp index d401b38f..89dfbc02 100644 --- a/src/gui/render/gpu_data/vertex_buffer_object.hpp +++ b/src/gui/render/gpu_data/vertex_buffer_object.hpp @@ -398,16 +398,28 @@ VertexBufferObject::private_insert_( // size_t size_ = alloc_size_; + // rewriting entire array if (start == 0 && end == size_) { // Tested - bind(); + if (alloc_size_ >= data_size) { + bind(); - alloc_size_ = data_size; + glBufferSubData( + static_cast(Buffer), start, alloc_size_ * element_size, + data_begin + ); + size_ = data_size; - glBufferData( - static_cast(Buffer), alloc_size_ * element_size, data_begin, - GL_DYNAMIC_DRAW - ); - size_ = alloc_size_; + } else { + bind(); + + alloc_size_ = data_size; + + glBufferData( + static_cast(Buffer), alloc_size_ * element_size, data_begin, + GL_DYNAMIC_DRAW + ); + size_ = alloc_size_; + } } else if (start + data_size + (size_ - end) > alloc_size_) { // Tested // the size of the new array is large than the allocated size diff --git a/src/gui/render/graphics_shaders/render_types.hpp b/src/gui/render/graphics_shaders/render_types.hpp index 09d0c7ac..8cdae56a 100644 --- a/src/gui/render/graphics_shaders/render_types.hpp +++ b/src/gui/render/graphics_shaders/render_types.hpp @@ -43,6 +43,14 @@ class FrameBuffer { render(screen_size_t width, screen_size_t height, GLuint frame_buffer) = 0; }; +class ScreenSection { + public: + virtual void render( + screen_size_t x_start, screen_size_t y_start, screen_size_t width, + screen_size_t height, GLuint frame_buffer, gpu_data::GPUData* data + ) = 0; +}; + // blume /** diff --git a/src/gui/render/graphics_shaders/shader_program.cpp b/src/gui/render/graphics_shaders/shader_program.cpp index 7ab7778b..e217d968 100644 --- a/src/gui/render/graphics_shaders/shader_program.cpp +++ b/src/gui/render/graphics_shaders/shader_program.cpp @@ -31,13 +31,16 @@ namespace gui { namespace shader { void -Render_Base::render(screen_size_t width, screen_size_t height, GLuint framebuffer_ID) { +Render_Base::render( + screen_size_t width, screen_size_t height, GLuint framebuffer_ID, + screen_size_t x_start, screen_size_t y_start +) { // Render to the screen gui::FrameBufferHandler::instance().bind_fbo(framebuffer_ID); // Render on the whole framebuffer, complete // from the lower left corner to the upper right - glViewport(0, 0, width, height); + glViewport(x_start, y_start, width, height); opengl_program_.use_program(); @@ -46,6 +49,29 @@ Render_Base::render(screen_size_t width, screen_size_t height, GLuint framebuffe opengl_program_.bind_uniforms(); } +void +ShaderProgram_Windows::render( + screen_size_t x_start, screen_size_t y_start, screen_size_t width, + screen_size_t height, GLuint framebuffer_ID, gpu_data::GPUData* data +) { + Render_Base::render(width, height, framebuffer_ID, x_start, y_start); + + if (!data->do_render()) { + return; + } + + data->bind(); + + // Draw the triangles ! + glDrawArrays( + GL_TRIANGLE_STRIP, // mode + 0, // start + data->get_num_vertices() // number of vertices + ); + + data->release(); +} + void ShaderProgram_Standard::render( screen_size_t width, screen_size_t height, GLuint framebuffer_ID diff --git a/src/gui/render/graphics_shaders/shader_program.hpp b/src/gui/render/graphics_shaders/shader_program.hpp index ef5f8cde..6ca61a40 100644 --- a/src/gui/render/graphics_shaders/shader_program.hpp +++ b/src/gui/render/graphics_shaders/shader_program.hpp @@ -125,12 +125,30 @@ class Render_Base { } void virtual render( - screen_size_t width, screen_size_t height, GLuint framebuffer_ID + screen_size_t width, screen_size_t height, GLuint framebuffer_ID, + screen_size_t x_start = 0, screen_size_t y_start = 0 ); inline virtual ~Render_Base() {} }; +class ShaderProgram_Windows : + public virtual Render_Base, + public virtual render_to::ScreenSection { + public: + inline ShaderProgram_Windows( + shader::Program& shader_program, const std::function setup_commands + ) : + Render_Base(shader_program, setup_commands) {} + + inline virtual ~ShaderProgram_Windows() {} + + void virtual render( + screen_size_t x_start, screen_size_t y_start, screen_size_t width, + screen_size_t height, GLuint framebuffer_ID, gpu_data::GPUData* data + ) override; +}; + /** * @brief No elements No instancing */ diff --git a/src/gui/render/structures/window_texture.cpp b/src/gui/render/structures/window_texture.cpp new file mode 100644 index 00000000..c617cbb5 --- /dev/null +++ b/src/gui/render/structures/window_texture.cpp @@ -0,0 +1,40 @@ +#include "window_texture.hpp" + +#include "logging.hpp" + +#include + +#include + +namespace gui { + +namespace render { + +WindowTexture::WindowTexture() : + // clang-format off + gl_positions_{ + glm::vec3(-1, -1, 0), + glm::vec3(-1, 1, 0), + glm::vec3(1, -1, 0), + glm::vec3(1, 1, 0) + }, + screen_positions_{ + glm::vec2(-1, -1), + glm::vec2(-1, 1), + glm::vec2(1, -1), + glm::vec2(0, 0)}, + // clang-format on + num_vertices_(4) { + LOG_DEBUG(logging::main_logger, "Initializing a WindowTexture"); + GlobalContext& context = GlobalContext::instance(); + context.push_opengl_task([this]() { + vertex_array_object_.bind(); + gl_positions_.attach_to_vertex_attribute(0); + screen_positions_.attach_to_vertex_attribute(1); + vertex_array_object_.release(); + }); +} + +} // namespace render + +} // namespace gui diff --git a/src/gui/render/structures/window_texture.hpp b/src/gui/render/structures/window_texture.hpp index 2dcafd33..f5d95029 100644 --- a/src/gui/render/structures/window_texture.hpp +++ b/src/gui/render/structures/window_texture.hpp @@ -1,6 +1,9 @@ #pragma once +#include "gui/render/gpu_data/data_types.hpp" #include "gui/render/gpu_data/texture.hpp" +#include "gui/render/gpu_data/vertex_array_object.hpp" +#include "gui/render/gpu_data/vertex_buffer_object.hpp" #include "screen_data.hpp" #include @@ -8,16 +11,87 @@ namespace gui { namespace render { -class WindowTexture : public virtual gpu_data::ScreenData { +// gpu_data::Texture2D texture; + +// std::array sub_texture_locations; + +class WindowTexture : public virtual gpu_data::GPUData { private: - // gpu_data::Texture2D texture; + // & to two things above + gpu_data::VertexArrayObject vertex_array_object_; - std::array sub_texture_locations; + gpu_data::VertexBufferObject gl_positions_; + gpu_data::VertexBufferObject screen_positions_; + unsigned int num_vertices_; public: - inline WindowTexture(){}; // std::filesystem::path file); - inline virtual ~WindowTexture(){}; + /** + * @brief Deleted copy constructor + */ + WindowTexture(const WindowTexture& obj) = delete; + + /** + * @brief Deleted copy operator + */ + WindowTexture& operator=(const WindowTexture& obj) = delete; + + /** + * @brief Default move constructor + */ + WindowTexture(WindowTexture&& obj) = default; + + /** + * @brief Default move constructor + */ + WindowTexture& operator=(WindowTexture&& obj) = default; + + /** + * @brief Construct a new Screen Data object, default constructor + * + */ + WindowTexture(); + + inline virtual ~WindowTexture() {} + + /** + * @brief Get the number of vertices + * + * @return unsigned int 4 (it is a rectangle) + */ + inline unsigned int + get_num_vertices() const { + return num_vertices_; + } + + inline virtual void + bind() const { + vertex_array_object_.bind(); + }; + + inline virtual void + release() const { + vertex_array_object_.release(); + } + + inline virtual bool + do_render() const { + return true; + }; + + inline void + update_position(std::array positions) { + screen_size_t x_diff = positions[2] - positions[0]; + screen_size_t y_diff = positions[3] - positions[1]; + + std::vector vertex_data( + {glm::vec2(x_diff, y_diff), glm::vec2(x_diff, 0), glm::vec2(0, y_diff), + glm::vec2(0, 0)} + ); + + screen_positions_.update(vertex_data); + } }; } // namespace render -} // namespace gui \ No newline at end of file + +} // namespace gui diff --git a/src/gui/the_buttons/bordered_window.cpp b/src/gui/the_buttons/bordered_window.cpp index ef1e5dd1..3971f51e 100644 --- a/src/gui/the_buttons/bordered_window.cpp +++ b/src/gui/the_buttons/bordered_window.cpp @@ -5,7 +5,9 @@ namespace gui { namespace the_buttons { BorderedWindow::BorderedWindow(std::shared_ptr data) : - data_(data) {} + data_(data) { + data_->update_position(get_bounding_box()); +} } // namespace the_buttons } // namespace gui \ No newline at end of file diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp index c4b52759..cda5d114 100644 --- a/src/gui/the_buttons/bordered_window.hpp +++ b/src/gui/the_buttons/bordered_window.hpp @@ -1,8 +1,8 @@ #pragma once +#include "frame.hpp" #include "gui/render/structures/screen_data.hpp" #include "gui/render/structures/window_texture.hpp" -#include "widget.hpp" #include @@ -10,13 +10,60 @@ namespace gui { namespace the_buttons { -class BorderedWindow : public virtual Widget { +class BorderedWindow : public virtual Frame { private: std::shared_ptr data_; public: + BorderedWindow() = delete; + /** + * @brief Deleted copy constructor + */ + BorderedWindow(const BorderedWindow& obj) = delete; + + /** + * @brief Deleted copy operator + */ + BorderedWindow& operator=(const BorderedWindow& obj) = delete; + + /** + * @brief Default move constructor + */ + BorderedWindow(BorderedWindow&& obj) = default; + + /** + * @brief Default move constructor + */ + BorderedWindow& operator=(BorderedWindow&& obj) = default; + BorderedWindow(std::shared_ptr data); + inline virtual ~BorderedWindow(){}; + + inline unsigned int + get_num_vertices() const { + return data_->get_num_vertices(); + } + + inline virtual void + bind() const { + data_->bind(); + }; + + inline virtual void + release() const { + data_->release(); + } + + inline virtual bool + do_render() const { + return data_->do_render(); + }; + + inline virtual std::array + get_bounding_box() const { + return {70, 70, 120, 120}; + } }; } // namespace the_buttons diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index ecaaf1e1..163ae689 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -1,5 +1,6 @@ #pragma once +#include "../render/gpu_data/data_types.hpp" #include "gui/scene/input.hpp" #include "types.hpp" @@ -12,7 +13,7 @@ namespace gui { namespace the_buttons { -class Frame : public virtual scene::Inputs { +class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { private: screen_size_t x_position; screen_size_t y_position; @@ -38,6 +39,7 @@ class Frame : public virtual scene::Inputs { void on_select(); void on_end_select(); + virtual std::array get_bounding_box() const = 0; /** * @brief Handle key input including mouse keys @@ -154,12 +156,12 @@ class Frame : public virtual scene::Inputs { cleanup([[maybe_unused]] GLFWwindow* window) {} }; -class UI_Text : public virtual Frame { - private: - std::string text_; -}; +// class UI_Text : public virtual Frame { +// private: +// std::string text_; +// }; -class Button : public virtual Frame {}; +// class Button : public virtual Frame {}; } // namespace the_buttons diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index c5087e86..e1fc58c0 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -12,8 +12,8 @@ namespace the_buttons { UserInterface::UserInterface(shader::ShaderHandler& shader_handler) { shader::Program& window_render_program = shader_handler.load_program( - "Windows", files::get_resources_path() / "shaders" / "background" / "Sky.vert", - files::get_resources_path() / "shaders" / "Red.frag" + "Windows", files::get_resources_path() / "shaders" / "overlay" / "Widget.vert", + files::get_resources_path() / "shaders" / "overlay" / "FramedWindow.frag" ); // Overwrites anything that was there before @@ -29,19 +29,32 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler) { // stars_program.set_uniform(matrix_view_projection_uniform, "MVP"); // windows - window_pipeline_ = std::make_shared( + window_pipeline_ = std::make_shared( window_render_program, render_setup ); } void UserInterface::update(screen_size_t width, screen_size_t height) { - FrameBufferHandler::instance().bind_fbo(0 // the screen - ); + // cascade update frames using width and height + + FrameBufferHandler::instance().bind_fbo(0); // the screen glClear(GL_DEPTH_BUFFER_BIT); - window_pipeline_->render(width, height, 0); + for (const auto& frame : frames_) { + if (!frame->do_render()) { + continue; + } + // frame->update_position(); + const auto bounding_box = frame->get_bounding_box(); + window_pipeline_->render( + bounding_box[0], bounding_box[1], bounding_box[2], bounding_box[3], 0, + frame.get() + ); + } } + } // namespace the_buttons + } // namespace gui diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 924575e9..58ce645a 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -3,7 +3,6 @@ #include "../render/graphics_shaders/shader_program.hpp" #include "frame.hpp" #include "gui/render/structures/uniform_types.hpp" -#include "widget.hpp" #include #include @@ -16,9 +15,9 @@ class UserInterface { // uniform // widget renderer - std::shared_ptr window_pipeline_; + std::shared_ptr window_pipeline_; - std::list> frames_; + std::list> frames_; public: UserInterface(shader::ShaderHandler& shader_handler); @@ -26,10 +25,9 @@ class UserInterface { void update(screen_size_t width, screen_size_t height); inline void - add(std::shared_ptr frame) { + add(std::shared_ptr frame) { auto pos = frames_.begin(); frames_.insert(pos, frame); - window_pipeline_->data.push_back(frame.get()); } }; diff --git a/src/gui/the_buttons/widget.hpp b/src/gui/the_buttons/widget.hpp deleted file mode 100644 index 338adaa4..00000000 --- a/src/gui/the_buttons/widget.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "frame.hpp" -#include "gui/render/structures/window_texture.hpp" - -namespace gui { -namespace the_buttons { -class Widget : public virtual Frame, public virtual gpu_data::ScreenData {}; -} // namespace the_buttons -} // namespace gui \ No newline at end of file From d47a3e45a3b7dd2b0c621269b6e4dcc8156afeb7 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 30 Nov 2025 08:56:49 -0500 Subject: [PATCH 04/56] Frame borders --- resources/shaders/overlay/FramedWindow.frag | 34 +++++++++++++++++-- .../graphics_shaders/shader_program.cpp | 3 +- src/gui/render/structures/uniform_types.hpp | 26 ++++++++++++++ src/gui/the_buttons/user_interface.cpp | 7 +++- src/gui/the_buttons/user_interface.hpp | 2 ++ 5 files changed, 67 insertions(+), 5 deletions(-) diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag index 4224a830..fad29703 100644 --- a/resources/shaders/overlay/FramedWindow.frag +++ b/resources/shaders/overlay/FramedWindow.frag @@ -3,10 +3,40 @@ // Ouput data layout(location = 0) out vec3 color; -in vec2 UV; +in vec2 UV; // in pixels +uniform ivec2 frame_size; void main(){ - color = vec3(UV/50, 0.9); + ivec2 pixel_position = ivec2(int(UV.x), int(UV.y)); + + int border_size = 10; + + if (pixel_position.y < border_size && pixel_position.x < border_size) { + color = vec3(0.8, 0.0, 0.4); + } + else if (pixel_position.y < border_size && frame_size.x - pixel_position.x - 1 < border_size) { + color = vec3(0.0, 0.5, 0.0); + } + else if ((frame_size.y - pixel_position.y - 1 < border_size) && pixel_position.x < border_size) { + color = vec3(0.4, 0.8, 0.0); + } + else if ((frame_size.y - pixel_position.y - 1 < border_size) && (frame_size.x - pixel_position.x - 1 < border_size)) { + color = vec3(0.5, 0.0, 0.0); + } + else if (pixel_position.x < border_size) { + color = vec3(0.0, 0.0, 0.5); + } + else if (pixel_position.y < border_size) { + color = vec3(0.5, 0.0, 0.5); + } + else if ((frame_size.x - pixel_position.x - 1) < border_size) { + color = vec3(0.0, 0.4, 0.8); + } + else if ((frame_size.y - pixel_position.y - 1) < border_size) { + color = vec3(0.5, 0.8, 0.5); + } else { + color = vec3(pixel_position, 0.8); + } } diff --git a/src/gui/render/graphics_shaders/shader_program.cpp b/src/gui/render/graphics_shaders/shader_program.cpp index e217d968..b53305c8 100644 --- a/src/gui/render/graphics_shaders/shader_program.cpp +++ b/src/gui/render/graphics_shaders/shader_program.cpp @@ -54,11 +54,10 @@ ShaderProgram_Windows::render( screen_size_t x_start, screen_size_t y_start, screen_size_t width, screen_size_t height, GLuint framebuffer_ID, gpu_data::GPUData* data ) { - Render_Base::render(width, height, framebuffer_ID, x_start, y_start); - if (!data->do_render()) { return; } + Render_Base::render(width, height, framebuffer_ID, x_start, y_start); data->bind(); diff --git a/src/gui/render/structures/uniform_types.hpp b/src/gui/render/structures/uniform_types.hpp index 7eb6dfc0..32c2a1b1 100644 --- a/src/gui/render/structures/uniform_types.hpp +++ b/src/gui/render/structures/uniform_types.hpp @@ -327,6 +327,32 @@ class StarRotationUniform : public shader::UniformExecutor { } }; +class FrameSizeUniform : public shader::UniformExecutor { + private: + glm::ivec2 frame_size_; + + public: + FrameSizeUniform() : + UniformExecutor(gpu_data::GPUArayType::INT_VEC2), frame_size_(0, 0) {} + + inline void + set_frame_size(glm::ivec2 frame_size) { + frame_size_ = frame_size; + } + + inline virtual ~FrameSizeUniform() {} + + inline virtual void + bind(GLint uniform_ID) const override { + LOG_BACKTRACE( + logging::opengl_logger, "Uniform {}, value {}, {} being initialized.", + uniform_ID, frame_size_.x, frame_size_.y + ); + + glUniform2i(uniform_ID, frame_size_.x, frame_size_.y); + } +}; + } // namespace render } // namespace gui diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index e1fc58c0..220f6fe2 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -10,7 +10,8 @@ namespace gui { namespace the_buttons { -UserInterface::UserInterface(shader::ShaderHandler& shader_handler) { +UserInterface::UserInterface(shader::ShaderHandler& shader_handler) : + frame_size_uniform_(std::make_shared()) { shader::Program& window_render_program = shader_handler.load_program( "Windows", files::get_resources_path() / "shaders" / "overlay" / "Widget.vert", files::get_resources_path() / "shaders" / "overlay" / "FramedWindow.frag" @@ -27,6 +28,7 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler) { // uniforms // stars_program.set_uniform(matrix_view_projection_uniform, "MVP"); + window_render_program.set_uniform(frame_size_uniform_, "frame_size"); // windows window_pipeline_ = std::make_shared( @@ -48,6 +50,9 @@ UserInterface::update(screen_size_t width, screen_size_t height) { } // frame->update_position(); const auto bounding_box = frame->get_bounding_box(); + frame_size_uniform_->set_frame_size(glm::ivec2( + bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1] + )); window_pipeline_->render( bounding_box[0], bounding_box[1], bounding_box[2], bounding_box[3], 0, frame.get() diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 58ce645a..38e3687d 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -1,6 +1,7 @@ #pragma once #include "../render/graphics_shaders/shader_program.hpp" +#include "../render/structures/uniform_types.hpp" #include "frame.hpp" #include "gui/render/structures/uniform_types.hpp" @@ -13,6 +14,7 @@ namespace the_buttons { class UserInterface { private: // uniform + std::shared_ptr frame_size_uniform_; // widget renderer std::shared_ptr window_pipeline_; From 6dd719438174cc994968e0f2cb5e658bdc85f3b7 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Mon, 1 Dec 2025 12:53:18 -0500 Subject: [PATCH 05/56] Read and write byte image --- resources/shaders/overlay/FramedWindow.frag | 1 + resources/textures/GenericBorder.png | Bin 0 -> 157 bytes src/gui/render/structures/uniform_types.hpp | 50 ++++++ src/gui/render/structures/window_texture.cpp | 6 +- src/gui/render/structures/window_texture.hpp | 6 +- src/gui/the_buttons/user_interface.cpp | 29 +++- src/gui/the_buttons/user_interface.hpp | 13 +- src/gui/ui/imgui_gui.cpp | 2 +- src/gui/ui/user_interface_setup.cpp | 14 +- src/main.cpp | 31 ++++ src/util/image.cpp | 18 +++ src/util/image.hpp | 126 +++++++++++++++- src/util/png_image.cpp | 151 +++++++++++++++++++ src/util/png_image.hpp | 141 +++++++++++++++++ 14 files changed, 576 insertions(+), 12 deletions(-) create mode 100644 resources/textures/GenericBorder.png diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag index fad29703..1ded3140 100644 --- a/resources/shaders/overlay/FramedWindow.frag +++ b/resources/shaders/overlay/FramedWindow.frag @@ -5,6 +5,7 @@ layout(location = 0) out vec3 color; in vec2 UV; // in pixels uniform ivec2 frame_size; +uniform sampler2D window_texture; void main(){ diff --git a/resources/textures/GenericBorder.png b/resources/textures/GenericBorder.png new file mode 100644 index 0000000000000000000000000000000000000000..ab539552a2a14443d9e05b39bc90c0e7e3b87512 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhDV{ElAre!QQyiGh#h3hT-*{Cx z%~0vIVN$S2okLsV(!;`RCB8i;xDNB5SP;!}eaSq7?unc?O>!6_=WyPvs(J9NY0H0~ zA3m<;b2)Fu?qKkl$7x$pz$n81$VfJF&X)o=wjW6X3^yeWg}CIO)&lKg@O1TaS?83{ F1OQ)lG#LN@ literal 0 HcmV?d00001 diff --git a/src/gui/render/structures/uniform_types.hpp b/src/gui/render/structures/uniform_types.hpp index 32c2a1b1..0e67637f 100644 --- a/src/gui/render/structures/uniform_types.hpp +++ b/src/gui/render/structures/uniform_types.hpp @@ -353,6 +353,56 @@ class FrameSizeUniform : public shader::UniformExecutor { } }; +class UIScaleUniform : public shader::UniformExecutor { + private: + uint8_t ui_scale_; + + public: + UIScaleUniform(uint8_t scale) : + UniformExecutor(gpu_data::GPUArayType::UNSIGNED_BYTE), ui_scale_(scale) {} + + inline void + set_ui_scale(uint8_t ui_scale) { + ui_scale_ = ui_scale; + } + + inline virtual ~UIScaleUniform() {} + + inline virtual void + bind(GLint uniform_ID) const override { + LOG_BACKTRACE( + logging::opengl_logger, "Uniform {}, value {} being initialized.", + uniform_ID, ui_scale_ + ); + + glUniform1i(uniform_ID, ui_scale_); + } +}; + +class TextureRegionsUniform : public shader::UniformExecutor { + private: + std::array texture_location_; + + public: + TextureRegionsUniform() : UniformExecutor(gpu_data::GPUArayType::UNSIGNED_BYTE) {} + + inline void + set_texture_regions(std::array texture_location) { + texture_location_ = texture_location; + } + + inline virtual ~TextureRegionsUniform() {} + + inline virtual void + bind(GLint uniform_ID) const override { + LOG_BACKTRACE( + logging::opengl_logger, "Uniform {} being initialized.", uniform_ID + ); + + glUniform1iv(uniform_ID, 36, texture_location_.data()); + } +}; + } // namespace render } // namespace gui diff --git a/src/gui/render/structures/window_texture.cpp b/src/gui/render/structures/window_texture.cpp index c617cbb5..2f7f16e3 100644 --- a/src/gui/render/structures/window_texture.cpp +++ b/src/gui/render/structures/window_texture.cpp @@ -1,6 +1,8 @@ #include "window_texture.hpp" #include "logging.hpp" +#include "util/files.hpp" +#include "util/png_image.hpp" #include @@ -10,7 +12,7 @@ namespace gui { namespace render { -WindowTexture::WindowTexture() : +WindowTexture::WindowTexture(std::shared_ptr image) : // clang-format off gl_positions_{ glm::vec3(-1, -1, 0), @@ -24,7 +26,7 @@ WindowTexture::WindowTexture() : glm::vec2(1, -1), glm::vec2(0, 0)}, // clang-format on - num_vertices_(4) { + num_vertices_(4), border_texture_(image) { LOG_DEBUG(logging::main_logger, "Initializing a WindowTexture"); GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { diff --git a/src/gui/render/structures/window_texture.hpp b/src/gui/render/structures/window_texture.hpp index f5d95029..03bbd7a1 100644 --- a/src/gui/render/structures/window_texture.hpp +++ b/src/gui/render/structures/window_texture.hpp @@ -5,6 +5,7 @@ #include "gui/render/gpu_data/vertex_array_object.hpp" #include "gui/render/gpu_data/vertex_buffer_object.hpp" #include "screen_data.hpp" +#include "util/image.hpp" #include @@ -24,6 +25,8 @@ class WindowTexture : public virtual gpu_data::GPUData { gpu_data::VertexBufferObject screen_positions_; unsigned int num_vertices_; + gpu_data::Texture2D border_texture_; + public: /** * @brief Deleted copy constructor @@ -49,7 +52,7 @@ class WindowTexture : public virtual gpu_data::GPUData { * @brief Construct a new Screen Data object, default constructor * */ - WindowTexture(); + WindowTexture(std::shared_ptr image); inline virtual ~WindowTexture() {} @@ -66,6 +69,7 @@ class WindowTexture : public virtual gpu_data::GPUData { inline virtual void bind() const { vertex_array_object_.bind(); + border_texture_.bind(0); }; inline virtual void diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 220f6fe2..44afb379 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -10,13 +10,30 @@ namespace gui { namespace the_buttons { -UserInterface::UserInterface(shader::ShaderHandler& shader_handler) : - frame_size_uniform_(std::make_shared()) { +UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_scale) : + frame_size_uniform_(std::make_shared()), + ui_scale_uniform_(std::make_shared(ui_scale)), + frame_texture_uniform_( + std::make_shared(gpu_data::GPUArayType::SAMPLER_2D, 0) + ), + texture_regions_(std::make_shared()) { shader::Program& window_render_program = shader_handler.load_program( "Windows", files::get_resources_path() / "shaders" / "overlay" / "Widget.vert", files::get_resources_path() / "shaders" / "overlay" / "FramedWindow.frag" ); + // auto image_result = image::read_image(files::get_resources_path() / "textures" / + // "GenericBorder.png"); if (!image_result.has_value()) { + // LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); + // return; + // } + // std::shared_ptr image = image_result.value(); + + // gpu_data::Texture2D border_texture(image, gui::gpu_data::TextureSettings{}, + // false); + + // frame_texture_uniform_ = std::make_shared<>(); + // Overwrites anything that was there before std::function render_setup = []() { // Draw over everything @@ -29,6 +46,9 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler) : // uniforms // stars_program.set_uniform(matrix_view_projection_uniform, "MVP"); window_render_program.set_uniform(frame_size_uniform_, "frame_size"); + window_render_program.set_uniform(ui_scale_uniform_, "ui_scale"); + window_render_program.set_uniform(frame_texture_uniform_, "texture"); + window_render_program.set_uniform(texture_regions_, "texture_locations"); // windows window_pipeline_ = std::make_shared( @@ -49,6 +69,11 @@ UserInterface::update(screen_size_t width, screen_size_t height) { continue; } // frame->update_position(); + + texture_regions_->set_texture_regions({0, 0, 5, 5, 0, 5, 5, 1, 0, 6, 5, 1, + 5, 0, 1, 5, 5, 5, 1, 1, 6, 5, 5, 1, + 6, 0, 5, 5, 6, 5, 5, 1, 6, 6, 5, 5}); + const auto bounding_box = frame->get_bounding_box(); frame_size_uniform_->set_frame_size(glm::ivec2( bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1] diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 38e3687d..ce579fc5 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -15,6 +15,9 @@ class UserInterface { private: // uniform std::shared_ptr frame_size_uniform_; + std::shared_ptr ui_scale_uniform_; + std::shared_ptr frame_texture_uniform_; + std::shared_ptr texture_regions_; // widget renderer std::shared_ptr window_pipeline_; @@ -22,10 +25,15 @@ class UserInterface { std::list> frames_; public: - UserInterface(shader::ShaderHandler& shader_handler); + UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_scale); void update(screen_size_t width, screen_size_t height); + inline void + set_ui_scale(uint8_t ui_scale) { + ui_scale_uniform_->set_ui_scale(ui_scale); + } + inline void add(std::shared_ptr frame) { auto pos = frames_.begin(); @@ -34,4 +42,5 @@ class UserInterface { }; } // namespace the_buttons -} // namespace gui \ No newline at end of file + +} // namespace gui diff --git a/src/gui/ui/imgui_gui.cpp b/src/gui/ui/imgui_gui.cpp index a8ab7ade..d508375a 100644 --- a/src/gui/ui/imgui_gui.cpp +++ b/src/gui/ui/imgui_gui.cpp @@ -102,7 +102,7 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { Scene main_scene(mode->width, mode->height, shadow_map_size, controller); setup(main_scene, shader_handler, world, climate); - the_buttons::UserInterface main_interface(shader_handler); + the_buttons::UserInterface main_interface(shader_handler, 8); setup(main_interface); //! Main loop diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index 5697cc69..ab4b30a5 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -2,14 +2,26 @@ #include "../the_buttons/bordered_window.hpp" #include "../the_buttons/user_interface.hpp" +#include "gui/render/gpu_data/texture.hpp" +#include "util/files.hpp" +#include "util/png_image.hpp" namespace gui { void setup(the_buttons::UserInterface& user_interface) { + auto image_result = image::read_image( + files::get_resources_path() / "textures" / "GenericBorder.png" + ); + if (!image_result.has_value()) { + LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); + return; + } + std::shared_ptr image = image_result.value(); + std::shared_ptr a_window = std::make_shared( - std::make_shared() + std::make_shared(image) ); user_interface.add(a_window); diff --git a/src/main.cpp b/src/main.cpp index f50a1181..7dce841b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -202,6 +202,35 @@ image_test(const argh::parser& cmdl) { return 0; } +int +color_image_text() { + auto image_result = image::read_image( + files::get_resources_path() / "textures" / "GenericBorder.png" + ); + if (!image_result.has_value()) { + LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); + return 1; + } + std::shared_ptr image = image_result.value(); + + auto FPAimage = + std::dynamic_pointer_cast(image); + + auto result = image::write_image( + *FPAimage.get(), + files::get_resources_path() / "textures" / "GenericBorder_out_test.png" + ); + + if (!result == image::write_result_t::WR_OK) { + LOG_ERROR( + logging::file_io_logger, "Image write failed with result {}.", int(result) + ); + return 1; + } + + return 0; +} + // reimplement int ChunkDataTest() { @@ -774,6 +803,8 @@ tests(const argh::parser& cmdl) { return ChunkDataTest(); } else if (run_function == "imageTest") { return image_test(cmdl); + } else if (run_function == "ColorImageTest") { + return color_image_text(); } else if (run_function == "LoadManifest") { manifest::ObjectHandler object_handler; return object_handler.load_all_manifests(); diff --git a/src/util/image.cpp b/src/util/image.cpp index 66eab253..2f631788 100644 --- a/src/util/image.cpp +++ b/src/util/image.cpp @@ -98,6 +98,24 @@ HALFFloatPolychromeAlphaImage::get_color(size_t i, size_t j) const { } #endif +png_byte +ByteMonochromeImage::get_color(size_t i, size_t j) const { + assert(i < width_ && j < height_ && "Position must be within image."); + return read_data_byte(data_, i * height_ + j)[0]; +} + +std::array +BytePolychromeImage::get_color(size_t i, size_t j) const { + assert(i < width_ && j < height_ && "Position must be within image."); + return read_data_byte(data_, i * height_ + j); +} + +std::array +BytePolychromeAlphaImage::get_color(size_t i, size_t j) const { + assert(i < width_ && j < height_ && "Position must be within image."); + return read_data_byte(data_, i * height_ + j); +} + } // namespace image } // namespace util \ No newline at end of file diff --git a/src/util/image.hpp b/src/util/image.hpp index 4fe4cbb4..d2bba3bc 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -17,9 +17,11 @@ struct FloatPolychromeAlphaImage_data_t { screen_size_t height; }; +// t represents the underlying type of the data structure; template std::array read_data(std::shared_ptr data, size_t offset) { + // assert(sizeof(T) == data_size_) size_t bit_offset = offset * sizeof(T) * datum_number; char* data_ptr = &data[bit_offset]; T* pixel_data = reinterpret_cast(data_ptr); @@ -44,6 +46,21 @@ read_data_float(std::shared_ptr data, size_t offset) { return out; } +template +std::array +read_data_byte(std::shared_ptr data, size_t offset) { + // assert(sizeof(T) == data_size_) + size_t bit_offset = offset * sizeof(T) * datum_number; + char* data_ptr = &data[bit_offset]; + T* pixel_data = reinterpret_cast(data_ptr); + std::array out; + for (size_t i = 0; i < datum_number; i++) { + // normalize data to size of png_byte + out[i] = pixel_data[i]; + } + return out; +} + class Image { // some data protected: @@ -108,7 +125,9 @@ class FloatMonochromeImage : public virtual MonochromeImage { FloatMonochromeImage( std::shared_ptr data, size_t width, size_t height, size_t data_size ) : - Image(data, width, height, data_size) {} + Image(data, width, height, data_size) { + assert(data_size == sizeof(float) && "data size must match expected size"); + } inline virtual size_t get_width() const { @@ -132,7 +151,9 @@ class FloatPolychromeImage : public virtual PolychromeImage { FloatPolychromeImage( std::shared_ptr data, size_t width, size_t height, size_t data_size ) : - Image(data, width, height, data_size) {} + Image(data, width, height, data_size) { + assert(data_size == sizeof(float) && "data size must match expected size"); + } inline virtual size_t get_width() const { @@ -163,7 +184,9 @@ class FloatPolychromeAlphaImage : public virtual PolychromeAlphaImage { FloatPolychromeAlphaImage( std::shared_ptr data, size_t width, size_t height, size_t data_size ) : - Image(data, width, height, data_size) {} + Image(data, width, height, data_size) { + assert(data_size == sizeof(float) && "data size must match expected size"); + } FloatPolychromeAlphaImage(std::vector> data) : FloatPolychromeAlphaImage(pad_color_data(data)) {} @@ -199,6 +222,103 @@ class HALFFloatPolychromeAlphaImage : public virtual PolychromeAlphaImage { }; #endif +// BYTE // 8 bit color channels 24 or 32 bit image +class ByteMonochromeImage : public virtual MonochromeImage { + public: + virtual png_byte get_color(size_t i, size_t j) const override; + + // virtual png_byte get_data(size_t i, size_t j) const; + + ByteMonochromeImage( + std::shared_ptr data, size_t width, size_t height, size_t data_size + ) : + Image(data, width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + + inline virtual size_t + get_width() const { + return width_; + } + + inline virtual size_t + get_height() const { + return height_; + } + + inline virtual ~ByteMonochromeImage() {} +}; + +class BytePolychromeImage : public virtual PolychromeImage { + public: + virtual std::array get_color(size_t i, size_t j) const override; + + // virtual std::array get_data(size_t i, size_t j) const; + // if needed make inline get color + BytePolychromeImage( + std::shared_ptr data, size_t width, size_t height, size_t data_size + ) : + Image(data, width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + + inline virtual size_t + get_width() const { + return width_; + } + + inline virtual size_t + get_height() const { + return height_; + } + + inline virtual ~BytePolychromeImage() {} +}; + +// TODO +// Everything commented out is a todo +class BytePolychromeAlphaImage : public virtual PolychromeAlphaImage { + private: + // static BytePolychromeAlphaImage_data_t + // pad_color_data(const std::vector>& vector_data); + + // BytePolychromeAlphaImage(BytePolychromeAlphaImage_data_t data) : + // Image(data.data, data.width, data.height, sizeof(ColorByte)) {} + + public: + virtual std::array get_color(size_t i, size_t j) const override; + + // virtual std::array get_data(size_t i, size_t j) const; + + BytePolychromeAlphaImage( + std::shared_ptr data, size_t width, size_t height, size_t data_size + ) : + Image(data, width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + + // BytePolychromeAlphaImage(std::vector> data) : + // BytePolychromeAlphaImage(pad_color_data(data)) {} + + inline virtual size_t + get_width() const { + return width_; + } + + inline virtual size_t + get_height() const { + return height_; + } + + inline virtual ~BytePolychromeAlphaImage() {} +}; + } // namespace image } // namespace util diff --git a/src/util/png_image.cpp b/src/util/png_image.cpp index 5f123e04..d4b3f389 100644 --- a/src/util/png_image.cpp +++ b/src/util/png_image.cpp @@ -1,6 +1,12 @@ #include "png_image.hpp" +#include "../exceptions.hpp" #include "../logging.hpp" +#include "image.hpp" + +#include + +#include namespace image { @@ -46,4 +52,149 @@ test_function() { #endif +[[nodiscard]] std::expected, int> +read_image(std::filesystem::path path) { + path = std::filesystem::absolute(path); + LOG_BACKTRACE(logging::file_io_logger, "Reading image from {}.", path.string()); + + // Read the tiles from the path specified, and save + // std::ifstream file(path, std::ios::in | std::ios::binary); + if (!std::filesystem::exists(path)) { + LOG_ERROR( + logging::file_io_logger, + "Could not open {}. Are you in the right directory?", path.string() + ); + throw exc::file_not_found_error(path); + } + + std::FILE* file = fopen(path.c_str(), "rb"); + + png_uint_32 width; + png_uint_32 height; + int bit_depth; + int color_type; + int interlace_method; + int compression_method; + int filter_method; + + unsigned char signal[8]; + + fread(signal, 1, 8, file); + + // file.read(reinterpret_cast(signal), 8); + + if (!png_check_sig(signal, 8)) { + LOG_ERROR(logging::file_io_logger, "Failed due to: Bad Signal"); + return std::unexpected(1); + } + + auto png_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) { + LOG_ERROR(logging::file_io_logger, "Failed due to: Out of Memory"); + return std::unexpected(4); + } + + auto info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == nullptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + LOG_ERROR(logging::file_io_logger, "Failed due to: Out of Memory"); + return std::unexpected(4); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + return std::unexpected(2); + } + + png_init_io(png_ptr, file); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + + png_get_IHDR( + png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, + &compression_method, &filter_method + ); + + if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) { + LOG_WARNING(logging::file_io_logger, "Color type not RGBA"); + } + + /* I don't really care about a background color; + if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { + LOG_ERROR(logging::file_io_logger, "Failed due to: Out of Memory"); + return std::unexpected(1); + }*/ + + // png_bytep [height]; + std::shared_ptr row_pointers(new png_bytep[height]); + + png_uint_32 row_bytes = png_get_rowbytes(png_ptr, info_ptr); + std::shared_ptr data(new char[row_bytes * height]); + // data.reserve(row_bytes * height); + + for (unsigned int i = 0; i < height; i++) { + row_pointers[i] = reinterpret_cast(data.get() + i * row_bytes); + } + + png_read_image(png_ptr, row_pointers.get()); + + png_read_end(png_ptr, nullptr); + + fclose(file); + + // todo do things for bit depth + auto image = + std::make_shared(data, width, height, 1); + +#if DEBUG() + for (unsigned int i = 0; i < image->get_width(); i++) { + for (unsigned int j = 0; j < image->get_height(); j++) { + auto raw_image_color0 = row_pointers[i][j * 4]; + auto raw_image_color1 = row_pointers[i][j * 4 + 1]; + auto raw_image_color2 = row_pointers[i][j * 4 + 2]; + auto raw_image_color3 = row_pointers[i][j * 4 + 3]; + + auto data_color0 = + reinterpret_cast(data.get())[i * row_bytes + j * 4]; + auto data_color1 = + reinterpret_cast(data.get())[i * row_bytes + j * 4 + 1]; + auto data_color2 = + reinterpret_cast(data.get())[i * row_bytes + j * 4 + 2]; + auto data_color3 = + reinterpret_cast(data.get())[i * row_bytes + j * 4 + 3]; + if (raw_image_color0 != data_color0 || raw_image_color1 != data_color1 + || raw_image_color2 != data_color2 || raw_image_color3 != data_color3) { + LOG_WARNING(logging::file_io_logger, "Pixel incorrect at {}{}", i, j); + LOG_WARNING( + logging::file_io_logger, "[{},{},{},{}]", data_color0, data_color1, + data_color2, data_color3 + ); + LOG_WARNING( + logging::file_io_logger, "[{},{},{},{}]", raw_image_color0, + raw_image_color1, raw_image_color2, raw_image_color3 + ); + } + + auto color = image->get_color(i, j); + + if (raw_image_color0 != color[0] || raw_image_color1 != color[1] + || raw_image_color2 != color[2] || raw_image_color3 != color[3]) { + LOG_WARNING(logging::file_io_logger, "Pixel incorrect at {}{}", i, j); + LOG_WARNING( + logging::file_io_logger, "[{},{},{},{}]", color[0], color[1], + color[2], color[3] + ); + LOG_WARNING( + logging::file_io_logger, "[{},{},{},{}]", raw_image_color0, + raw_image_color1, raw_image_color2, raw_image_color3 + ); + } + } + } +#endif + + return image; +} + } // namespace image diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 556dfc97..da519821 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -28,9 +28,16 @@ #include #include +#include #include #include +namespace util { +namespace image { +class Image; +} +} // namespace util + namespace image { enum write_result_t { @@ -56,6 +63,13 @@ concept ImageColor = requires(T const img, size_t i, size_t j) { { img.get_color(i, j) } -> std::same_as>; }; +template +concept ImageRGBA = requires(T const img, size_t i, size_t j) { + { img.get_height() } -> std::convertible_to; + { img.get_width() } -> std::convertible_to; + { img.get_color(i, j) } -> std::same_as>; +}; + template [[nodiscard]] write_result_t write_image(T image, const std::filesystem::path& path) { @@ -322,6 +336,130 @@ write_image(T image, const std::filesystem::path& path) { return status; } +template +[[nodiscard]] write_result_t +write_image(T image, const std::filesystem::path& path) { + // Keep track of if we succeeded or not + write_result_t status = WR_OK; + + // Get image information + size_t WIDTH = image.get_width(); + size_t HEIGHT = image.get_height(); + + char meta_lang[] = "en"; + char meta_key[] = "An Image"; + char meta_text[] = "Some text"; + + // Create png variables + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; + + // Open the file for writing + auto path_str = path.string(); // need to keep this from being free'd + std::FILE* file = fopen(path_str.c_str(), "wb"); + + if (!file) { + status = WR_FOPEN_FAILED; + goto fopen_failed; + } + + // Create our write struct + // TODO these nullptr should be function pointers + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) { + status = WR_CREATE_WRITE_STRUCT_FAILED; + goto png_create_write_struct_failed; + } + + // Create our info struct for this png image + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + status = WR_CREATE_INFO_STRUCT_FAILED; + goto png_create_info_struct_failed; + } + + // Set jump buffer for callbacks + if (setjmp(png_jmpbuf(png_ptr))) { + status = WR_SETJMP_PNG_JMPBUF_FAILED; + goto setjmp_png_jmpbuf_failed; + } + + // Set up IO for our file + png_init_io(png_ptr, file); + + // set information about our image + png_set_IHDR( + png_ptr, info_ptr, WIDTH, HEIGHT, 8, PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT + ); + + // Set metadata about the PNG file + png_text meta_data; + memset(&meta_data, 0, sizeof(meta_data)); // clear struct + + meta_data.compression = PNG_TEXT_COMPRESSION_NONE; // no compression + meta_data.lang_key = meta_lang; + meta_data.key = meta_key; + meta_data.text = meta_text; + + png_set_text(png_ptr, info_ptr, &meta_data, 1); + png_write_info(png_ptr, info_ptr); + + // multiple colors are written in the same row + // not sure how I want to implement this in a template safe way + // https://stackoverflow.com/questions/48757099/write-an-image-row-by-row-with-libpng-using-c + + /* + * write rows of image + */ + size_t i, j; + png_bytep row; + + // allocate data for row + row = new (std::nothrow) png_byte[4 * WIDTH]; + if (!row) { + status = WR_ROW_MALLOC_FAILED; + goto row_malloc_failed; + } + + // write row data + for (i = 0; i < HEIGHT; i++) { + // set row data + for (j = 0; j < WIDTH; j++) { + const std::array pixel_color = image.get_color(i, j); + row[4 * j] = pixel_color[0]; + row[4 * j + 1] = pixel_color[1]; + row[4 * j + 2] = pixel_color[2]; + row[4 * j + 3] = pixel_color[3]; + } + + // write the row + png_write_row(png_ptr, row); + } + + /* + * Cleanups + */ + // Free our row data + delete[] row; + +row_malloc_failed: + // Finish our write + png_write_end(png_ptr, info_ptr); + +setjmp_png_jmpbuf_failed: +png_create_info_struct_failed: + // Free our write struct + png_destroy_write_struct(&png_ptr, &info_ptr); + +png_create_write_struct_failed: + // Close our file + fclose(file); + +fopen_failed: + return status; +} + class ColorImageTest { public: ColorImageTest(){}; @@ -346,4 +484,7 @@ class ColorImageTest { // #endif +[[nodiscard]] std::expected, int> +read_image(std::filesystem::path path); + } // namespace image From f0e211c558ac4744bcd7c5e1893070058a790304 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 2 Dec 2025 21:12:06 -0500 Subject: [PATCH 06/56] read m int texture --- resources/shaders/overlay/FramedWindow.frag | 18 +++++++++++++++--- src/gui/render/gl_enums.hpp | 12 ++++++++++-- src/gui/render/gpu_data/texture.cpp | 5 ++++- src/gui/render/structures/window_texture.cpp | 11 ++++++++++- src/gui/the_buttons/user_interface.cpp | 9 +++++---- 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag index 1ded3140..b3853695 100644 --- a/resources/shaders/overlay/FramedWindow.frag +++ b/resources/shaders/overlay/FramedWindow.frag @@ -5,7 +5,9 @@ layout(location = 0) out vec3 color; in vec2 UV; // in pixels uniform ivec2 frame_size; -uniform sampler2D window_texture; +uniform usampler2D window_texture; + +// uniform void main(){ @@ -14,7 +16,17 @@ main(){ int border_size = 10; - if (pixel_position.y < border_size && pixel_position.x < border_size) { + //color = texture(window_texture, vec2(float(pixel_position.x) / float(frame_size.x), float(pixel_position.y) / float(frame_size.y) ) ).rgb; + + uvec3 color_int = texelFetch(window_texture, ivec2(3, 3), 0).rgb; + + //uvec3 color_int = texture(window_texture, vec2(0.5, 0.5)).rgb; + + color = vec3(float(color_int.r)/255.0, 0, 0);//texelFetch(window_texture, ivec2(3, 3), 0).rgb; + + + +/* if (pixel_position.y < border_size && pixel_position.x < border_size) { color = vec3(0.8, 0.0, 0.4); } else if (pixel_position.y < border_size && frame_size.x - pixel_position.x - 1 < border_size) { @@ -39,5 +51,5 @@ main(){ color = vec3(0.5, 0.8, 0.5); } else { color = vec3(pixel_position, 0.8); - } + }*/ } diff --git a/src/gui/render/gl_enums.hpp b/src/gui/render/gl_enums.hpp index cdb3fdea..b8dc7e80 100644 --- a/src/gui/render/gl_enums.hpp +++ b/src/gui/render/gl_enums.hpp @@ -150,7 +150,9 @@ enum class GPUArayType : GLenum { enum class GPUPixelType : GLenum { FLOAT = GL_FLOAT, // float (32) HALF_FLOAT = GL_HALF_FLOAT, // float16 - NONE = 0, // render buffers have no internal type + UNSIGNED_BYTE = GL_UNSIGNED_BYTE, + NONE = 0, // render buffers have no internal type + }; enum class GPUPixelStorageFormat : GLenum { @@ -161,7 +163,12 @@ enum class GPUPixelStorageFormat : GLenum { DEPTH_32 = GL_DEPTH_COMPONENT32, RGB = GL_RGB, RGB8 = GL_RGB8, - RGBA = GL_RGBA + RGBA = GL_RGBA, + RGBA8 = GL_RGBA8, + + RGBA8I = GL_RGBA8I, + RGBA8UI = GL_RGBA8UI, + // RGBA8I = GL_RGBA8I }; enum class GPUPixelReadFormat : GLenum { @@ -176,6 +183,7 @@ enum class GPUPixelReadFormat : GLenum { RGBA = GL_RGBA, BGRA = GL_BGRA, + RGBA_INTEGER = GL_RGBA_INTEGER, }; /** diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index 5cc75365..f590ede6 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -166,7 +166,10 @@ Texture2D::load_data(std::shared_ptr image) { static_cast(settings_.read_format), static_cast(settings_.type), image->data() ); - glGenerateMipmap(GL_TEXTURE_2D); + if (settings_.type == GPUPixelType::FLOAT + || settings_.type == GPUPixelType::HALF_FLOAT) { + glGenerateMipmap(GL_TEXTURE_2D); + } } } // namespace gpu_data diff --git a/src/gui/render/structures/window_texture.cpp b/src/gui/render/structures/window_texture.cpp index 2f7f16e3..e12c4b88 100644 --- a/src/gui/render/structures/window_texture.cpp +++ b/src/gui/render/structures/window_texture.cpp @@ -26,7 +26,16 @@ WindowTexture::WindowTexture(std::shared_ptr image) : glm::vec2(1, -1), glm::vec2(0, 0)}, // clang-format on - num_vertices_(4), border_texture_(image) { + num_vertices_(4), + border_texture_( + image, + gui::gpu_data::TextureSettings{ + .internal_format = gui::gpu_data::GPUPixelStorageFormat::RGBA8UI, + .read_format = gui::gpu_data::GPUPixelReadFormat::RGBA_INTEGER, + .type = gui::gpu_data::GPUPixelType::UNSIGNED_BYTE, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST} + ) { LOG_DEBUG(logging::main_logger, "Initializing a WindowTexture"); GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 44afb379..c8121221 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -8,14 +8,15 @@ #include "manifest/object_handler.hpp" namespace gui { + namespace the_buttons { UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_scale) : frame_size_uniform_(std::make_shared()), ui_scale_uniform_(std::make_shared(ui_scale)), - frame_texture_uniform_( - std::make_shared(gpu_data::GPUArayType::SAMPLER_2D, 0) - ), + frame_texture_uniform_(std::make_shared( + gpu_data::GPUArayType::UNSIGNED_INT_SAMPLER_2D, 0 + )), texture_regions_(std::make_shared()) { shader::Program& window_render_program = shader_handler.load_program( "Windows", files::get_resources_path() / "shaders" / "overlay" / "Widget.vert", @@ -47,7 +48,7 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s // stars_program.set_uniform(matrix_view_projection_uniform, "MVP"); window_render_program.set_uniform(frame_size_uniform_, "frame_size"); window_render_program.set_uniform(ui_scale_uniform_, "ui_scale"); - window_render_program.set_uniform(frame_texture_uniform_, "texture"); + window_render_program.set_uniform(frame_texture_uniform_, "window_texture"); window_render_program.set_uniform(texture_regions_, "texture_locations"); // windows From c47d578c18bf7ce7907a561927bedf88a6c91902 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 6 Dec 2025 09:48:45 -0500 Subject: [PATCH 07/56] correct frame render --- resources/shaders/overlay/FramedWindow.frag | 109 +++++++++++++++----- src/gui/render/structures/uniform_types.hpp | 6 +- src/gui/the_buttons/bordered_window.hpp | 2 +- src/gui/the_buttons/user_interface.cpp | 2 +- src/gui/ui/imgui_gui.cpp | 2 +- 5 files changed, 90 insertions(+), 31 deletions(-) diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag index b3853695..96980880 100644 --- a/resources/shaders/overlay/FramedWindow.frag +++ b/resources/shaders/overlay/FramedWindow.frag @@ -4,52 +4,111 @@ layout(location = 0) out vec3 color; in vec2 UV; // in pixels -uniform ivec2 frame_size; +uniform ivec2 frame_size; // error uniform usampler2D window_texture; +//uniform int texture_locations[36]; // error +uniform int ui_scale; // uniform void main(){ + int border_size = 5; + + ivec2 position_1 = ivec2(0,0); + ivec2 position_2 = ivec2(5,0); + ivec2 position_3 = ivec2(6,0); + ivec2 position_4 = ivec2(0,5); + ivec2 position_5 = ivec2(5,5); + ivec2 position_6 = ivec2(6,5); + ivec2 position_7 = ivec2(0,6); + ivec2 position_8 = ivec2(5,6); + ivec2 position_9 = ivec2(6,6); + + int width_2 = 1; + int height_4 = 1; + int width_5 = 1; + int height_5 = 1; + int height_6 = 1; + int width_8 = 1; + ivec2 pixel_position = ivec2(int(UV.x), int(UV.y)); + ivec2 ui_position = pixel_position / ui_scale; + ivec2 frame_size_px = frame_size / ui_scale; - int border_size = 10; + ivec2 texture_offset; - //color = texture(window_texture, vec2(float(pixel_position.x) / float(frame_size.x), float(pixel_position.y) / float(frame_size.y) ) ).rgb; +// ivec2 texture_position = ivec2(texture_locations[3], texture_locations[2]); - uvec3 color_int = texelFetch(window_texture, ivec2(3, 3), 0).rgb; + if (ui_position.y < border_size && ui_position.x < border_size) { // 1 - //uvec3 color_int = texture(window_texture, vec2(0.5, 0.5)).rgb; + ivec2 local_position = ivec2(ui_position.x, ui_position.y); - color = vec3(float(color_int.r)/255.0, 0, 0);//texelFetch(window_texture, ivec2(3, 3), 0).rgb; + texture_offset = local_position + position_1; + } + else if (ui_position.y < border_size && frame_size_px.x - ui_position.x - 1 < border_size) { // 3 + ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size, ui_position.y); -/* if (pixel_position.y < border_size && pixel_position.x < border_size) { - color = vec3(0.8, 0.0, 0.4); + texture_offset = local_position + position_3; } - else if (pixel_position.y < border_size && frame_size.x - pixel_position.x - 1 < border_size) { - color = vec3(0.0, 0.5, 0.0); + else if ((frame_size_px.y - ui_position.y - 1 < border_size) && ui_position.x < border_size) { // 7 + ivec2 local_position = ivec2(ui_position.x, ui_position.y - frame_size_px.y + border_size); + + texture_offset = local_position + position_7; } - else if ((frame_size.y - pixel_position.y - 1 < border_size) && pixel_position.x < border_size) { - color = vec3(0.4, 0.8, 0.0); + else if ((frame_size_px.y - ui_position.y - 1 < border_size) && (frame_size_px.x - ui_position.x - 1 < border_size)) { // 9 + ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size, ui_position.y - frame_size_px.y + border_size); + + texture_offset = local_position + position_9; } - else if ((frame_size.y - pixel_position.y - 1 < border_size) && (frame_size.x - pixel_position.x - 1 < border_size)) { - color = vec3(0.5, 0.0, 0.0); + else if (ui_position.x < border_size) { // 4 + ivec2 local_position = ivec2(ui_position.x, ui_position.y - border_size); + local_position.y = local_position.y % height_4; + + texture_offset = local_position + position_4; } - else if (pixel_position.x < border_size) { - color = vec3(0.0, 0.0, 0.5); + else if (ui_position.y < border_size) { // 2 + ivec2 local_position = ivec2(ui_position.x, ui_position.y); + local_position.x = local_position.x % width_2; + + texture_offset = local_position + position_2; + } + else if ((frame_size_px.x - ui_position.x) <= border_size) { // 6 + + ivec2 local_position = ivec2(border_size - frame_size_px.x + ui_position.x, ui_position.y - border_size); + local_position.y = local_position.y % height_6; + + texture_offset = local_position + position_6; } - else if (pixel_position.y < border_size) { - color = vec3(0.5, 0.0, 0.5); + else if ((frame_size_px.y - ui_position.y) <= border_size) { // 8 idk + + ivec2 local_position = ivec2(ui_position.x - border_size, frame_size_px.y - ui_position.y-1); + local_position.x = local_position.x % width_8; + + texture_offset = local_position + position_2; + } else { // 5 + texture_offset = position_5; } - else if ((frame_size.x - pixel_position.x - 1) < border_size) { - color = vec3(0.0, 0.4, 0.8); + + uvec4 color_int = texelFetch(window_texture, texture_offset, 0); + if (color_int.a == 0) { + discard; } - else if ((frame_size.y - pixel_position.y - 1) < border_size) { - color = vec3(0.5, 0.8, 0.5); - } else { - color = vec3(pixel_position, 0.8); - }*/ + + color = vec3(color_int.rgb)/255.0; +// uvec4 color_int = texelFetch(window_texture, texture_position, 0); + +// if (color_int.a == 0) { +// discard; +// } + +// vec3 color_float = vec3(color_int.rgba); + + //uvec3 color_int = texture(window_texture, vec2(0.5, 0.5)).rgb; + +// color = color_float / 255;//texelFetch(window_texture, ivec2(3, 3), 0).rgb; + } diff --git a/src/gui/render/structures/uniform_types.hpp b/src/gui/render/structures/uniform_types.hpp index 0e67637f..a8df3aea 100644 --- a/src/gui/render/structures/uniform_types.hpp +++ b/src/gui/render/structures/uniform_types.hpp @@ -359,7 +359,7 @@ class UIScaleUniform : public shader::UniformExecutor { public: UIScaleUniform(uint8_t scale) : - UniformExecutor(gpu_data::GPUArayType::UNSIGNED_BYTE), ui_scale_(scale) {} + UniformExecutor(gpu_data::GPUArayType::INT), ui_scale_(scale) {} inline void set_ui_scale(uint8_t ui_scale) { @@ -375,7 +375,7 @@ class UIScaleUniform : public shader::UniformExecutor { uniform_ID, ui_scale_ ); - glUniform1i(uniform_ID, ui_scale_); + glUniform1i(uniform_ID, int(ui_scale_)); } }; @@ -384,7 +384,7 @@ class TextureRegionsUniform : public shader::UniformExecutor { std::array texture_location_; public: - TextureRegionsUniform() : UniformExecutor(gpu_data::GPUArayType::UNSIGNED_BYTE) {} + TextureRegionsUniform() : UniformExecutor(gpu_data::GPUArayType::INT) {} inline void set_texture_regions(std::array texture_location) { diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp index cda5d114..c7830a10 100644 --- a/src/gui/the_buttons/bordered_window.hpp +++ b/src/gui/the_buttons/bordered_window.hpp @@ -62,7 +62,7 @@ class BorderedWindow : public virtual Frame { inline virtual std::array get_bounding_box() const { - return {70, 70, 120, 120}; + return {70, 70, 230, 230}; } }; diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index c8121221..71ae1bfb 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -80,7 +80,7 @@ UserInterface::update(screen_size_t width, screen_size_t height) { bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1] )); window_pipeline_->render( - bounding_box[0], bounding_box[1], bounding_box[2], bounding_box[3], 0, + bounding_box[0], bounding_box[1], bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, frame.get() ); } diff --git a/src/gui/ui/imgui_gui.cpp b/src/gui/ui/imgui_gui.cpp index d508375a..498768a5 100644 --- a/src/gui/ui/imgui_gui.cpp +++ b/src/gui/ui/imgui_gui.cpp @@ -102,7 +102,7 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { Scene main_scene(mode->width, mode->height, shadow_map_size, controller); setup(main_scene, shader_handler, world, climate); - the_buttons::UserInterface main_interface(shader_handler, 8); + the_buttons::UserInterface main_interface(shader_handler, 4); setup(main_interface); //! Main loop From a714584b3bb8bdfb69a06d74ed4ab761b9a42a2e Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 10 Dec 2025 12:31:30 -0500 Subject: [PATCH 08/56] splash screen --- src/graphics_main.cpp | 106 ++++++++++++++++++++++++++++++---- src/gui/the_buttons/README.md | 20 +++++++ src/gui/ui/gui_entry.hpp | 9 +++ 3 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 src/gui/the_buttons/README.md create mode 100644 src/gui/ui/gui_entry.hpp diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index ef57b8a6..21e30e00 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -9,6 +9,9 @@ #include "types.hpp" #include "world/climate.hpp" #include "world/world.hpp" +#include "gui/render/structures/screen_data.hpp" +#include "chrono" + #include #include @@ -22,12 +25,21 @@ struct Options { std::optional save_file; };*/ +struct background_result { + int result; + std::unique_ptr world; + std::unique_ptr climate; +}; + + int graphics_main(const argh::parser& cmdl) { // add window width and height? screen_size_t window_width = 1280; screen_size_t window_height = 800; + + screen_size_t display_w, display_h; // init graphics std::optional opt_window = @@ -43,8 +55,32 @@ graphics_main(const argh::parser& cmdl) { glGenVertexArrays(1, &VertexArrayID); gui::VertexBufferHandler::instance().bind_vertex_buffer(VertexArrayID); - std::string run_function = cmdl(1).str(); + // Start Splash screen + gui::shader::ShaderHandler temp_handler; + gui::shader::Program& splash_screen_program = temp_handler.load_program("Splash Screen", + files::get_resources_path() / "shaders" / "Passthrough.vert", + files::get_resources_path() / "shaders" / "Green.frag"); + + std::function splash_screen_setup = []() { + // Draw over everything + glDisable(GL_CULL_FACE); + // The sky has no depth + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + }; + + auto splash_screen_pipeline = std::make_shared(splash_screen_program, splash_screen_setup); + + // TODO allow to do all these without differed + // TODO assert in at the lowest level that opengl things are run on the main thread + auto screen_data = std::make_shared(); + splash_screen_pipeline->data.push_back(screen_data.get()); + + + + // background task { + // Think about this later // need to read biomes from manifest // then in background need to mesh things @@ -52,14 +88,13 @@ graphics_main(const argh::parser& cmdl) { // the main thread loads meshes onto gpu and renders to screen // Read manifest // util::load_manifest(); + + GlobalContext& global_context = GlobalContext::instance(); - manifest::ObjectHandler object_handler; - object_handler.load_all_manifests(); - - // generate options either from command line inputs - // or from gui - // struct Options + // don't forget ot load ScreenData onto gpu + global_context.run_opengl_queue(); + std::string run_function = cmdl(1).str(); size_t seed; cmdl("seed", SEED) >> seed; size_t size; @@ -67,10 +102,61 @@ graphics_main(const argh::parser& cmdl) { std::string biome_name; cmdl("biome-name", BIOME_BASE_NAME) >> biome_name; - world::World world(&object_handler, biome_name, size, size, seed); - world.generate_plants(); - world::Climate climate; + manifest::ObjectHandler object_handler; + auto load_manifests_future = global_context.submit_task([&object_handler, biome_name, size, seed](){ + + background_result result; + + int manifest_result = object_handler.load_all_manifests(); + + result.result = manifest_result; + + if (result.result == 1) { + return result; + } + + result.world = std::make_unique(&object_handler, biome_name, size, size, seed); + result.world->generate_plants(); + result.climate = std::make_unique(); + + return result; + }); + + + + + // generate options either from command line inputs + // or from gui + // struct Options + + //} + + // can't cancel a task after it has been started run. + + while (load_manifests_future.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { + glfwGetFramebufferSize(window, &display_w, &display_h); + + //gui::FrameBufferHandler::instance().bind_fbo(0); + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + //glViewport(0, 0, display_w, display_h); + + splash_screen_pipeline->render(display_w, display_h, 0); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + auto future_value = load_manifests_future.get(); + + if (future_value.result == 1) { + LOG_ERROR(logging::main_logger, "Error Loading. Exiting."); + return 1; + } + + world::World& world = *future_value.world; + world::Climate& climate = *future_value.climate; // if need gui start gui bool imgui_debug = cmdl[{"-g", "--imgui"}]; diff --git a/src/gui/the_buttons/README.md b/src/gui/the_buttons/README.md new file mode 100644 index 00000000..2c9d7bab --- /dev/null +++ b/src/gui/the_buttons/README.md @@ -0,0 +1,20 @@ +# Click + +Check between scene and ui + +if scene forward to scene, + +if ui forward to ui + +might want to run deselect + +# UI framework + +Splash screen / loading screen + +Intro screen + - New Game + - Load Game + - Settings + - Pedia / License / Copyright + diff --git a/src/gui/ui/gui_entry.hpp b/src/gui/ui/gui_entry.hpp new file mode 100644 index 00000000..989e551e --- /dev/null +++ b/src/gui/ui/gui_entry.hpp @@ -0,0 +1,9 @@ +namespace gui { + +namespace ui { + + + int main_gui_entry(); +} + +} From 64dc5adea037b0e6f2743b9bf73f30315af94bfa Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 10 Dec 2025 14:21:34 -0500 Subject: [PATCH 09/56] write graphics main function --- src/graphics_main.cpp | 130 ++++++++++++++++--------- src/graphics_main.hpp | 40 ++++++++ src/gui/the_buttons/user_interface.cpp | 4 +- src/gui/ui/gui_entry.hpp | 5 +- 4 files changed, 126 insertions(+), 53 deletions(-) diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index 21e30e00..226c3916 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -1,7 +1,9 @@ #include "graphics_main.hpp" +#include "chrono" #include "config.h" #include "gui/handler.hpp" +#include "gui/render/structures/screen_data.hpp" #include "gui/ui/imgui_gui.hpp" #include "gui/ui/opengl_gui.hpp" #include "gui/ui/opengl_setup.hpp" @@ -9,9 +11,6 @@ #include "types.hpp" #include "world/climate.hpp" #include "world/world.hpp" -#include "gui/render/structures/screen_data.hpp" -#include "chrono" - #include #include @@ -31,7 +30,6 @@ struct background_result { std::unique_ptr climate; }; - int graphics_main(const argh::parser& cmdl) { // add window width and height? @@ -57,9 +55,10 @@ graphics_main(const argh::parser& cmdl) { // Start Splash screen gui::shader::ShaderHandler temp_handler; - gui::shader::Program& splash_screen_program = temp_handler.load_program("Splash Screen", - files::get_resources_path() / "shaders" / "Passthrough.vert", - files::get_resources_path() / "shaders" / "Green.frag"); + gui::shader::Program& splash_screen_program = temp_handler.load_program( + "Splash Screen", files::get_resources_path() / "shaders" / "Passthrough.vert", + files::get_resources_path() / "shaders" / "Green.frag" + ); std::function splash_screen_setup = []() { // Draw over everything @@ -69,7 +68,9 @@ graphics_main(const argh::parser& cmdl) { glDepthMask(GL_FALSE); }; - auto splash_screen_pipeline = std::make_shared(splash_screen_program, splash_screen_setup); + auto splash_screen_pipeline = std::make_shared( + splash_screen_program, splash_screen_setup + ); // TODO allow to do all these without differed // TODO assert in at the lowest level that opengl things are run on the main thread @@ -77,10 +78,8 @@ graphics_main(const argh::parser& cmdl) { splash_screen_pipeline->data.push_back(screen_data.get()); - - // background task { - + // Think about this later // need to read biomes from manifest // then in background need to mesh things @@ -88,13 +87,12 @@ graphics_main(const argh::parser& cmdl) { // the main thread loads meshes onto gpu and renders to screen // Read manifest // util::load_manifest(); - + GlobalContext& global_context = GlobalContext::instance(); // don't forget ot load ScreenData onto gpu global_context.run_opengl_queue(); - std::string run_function = cmdl(1).str(); size_t seed; cmdl("seed", SEED) >> seed; size_t size; @@ -102,58 +100,57 @@ graphics_main(const argh::parser& cmdl) { std::string biome_name; cmdl("biome-name", BIOME_BASE_NAME) >> biome_name; - manifest::ObjectHandler object_handler; - auto load_manifests_future = global_context.submit_task([&object_handler, biome_name, size, seed](){ - - background_result result; - - int manifest_result = object_handler.load_all_manifests(); + auto load_manifests_future = + global_context.submit_task([&object_handler, biome_name, size, seed]() { + background_result result; - result.result = manifest_result; - - if (result.result == 1) { - return result; - } + int manifest_result = object_handler.load_all_manifests(); - result.world = std::make_unique(&object_handler, biome_name, size, size, seed); - result.world->generate_plants(); - result.climate = std::make_unique(); + result.result = manifest_result; - return result; - }); - + if (result.result == 1) { + return result; + } + result.world = std::make_unique( + &object_handler, biome_name, size, size, seed + ); + result.world->generate_plants(); + result.climate = std::make_unique(); + return result; + }); // generate options either from command line inputs // or from gui // struct Options - + //} - // can't cancel a task after it has been started run. - - while (load_manifests_future.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { + // can't cancel a task after it has been started run. + + while (load_manifests_future.wait_for(std::chrono::seconds(0)) + != std::future_status::ready) { glfwGetFramebufferSize(window, &display_w, &display_h); - - //gui::FrameBufferHandler::instance().bind_fbo(0); - //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //glViewport(0, 0, display_w, display_h); - + + // gui::FrameBufferHandler::instance().bind_fbo(0); + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // glViewport(0, 0, display_w, display_h); + splash_screen_pipeline->render(display_w, display_h, 0); - + glfwSwapBuffers(window); glfwPollEvents(); - } - + } + auto future_value = load_manifests_future.get(); if (future_value.result == 1) { - LOG_ERROR(logging::main_logger, "Error Loading. Exiting."); - return 1; - } + LOG_ERROR(logging::main_logger, "Error Loading. Exiting."); + return 1; + } world::World& world = *future_value.world; world::Climate& climate = *future_value.climate; @@ -174,7 +171,44 @@ graphics_main(const argh::parser& cmdl) { int graphics_main() { - LOG_CRITICAL(logging::main_logger, "NOT IMPLEMENTED"); + LOG_WARNING(logging::main_logger, "Only kinda implemented"); + + // global context and logging are already initalized. + + // read commands from file + // Things like screen size + // full screen + // all graphics/audio settings + // not that bad, make a settings header and define structures in there. + + intro_scene::result result = intro_scene::IntroPage(); + + while (true) { + switch (result.index()) { + case 0: // intro page + result = intro_window(); + break; + case 1: // new world with settings + { + auto settings = std::get(result); + result = graphics_main(settings); + } + break; + case 2: // from save with file path + { + auto path = std::get(result); + result = graphics_main(path); + } + break; + case 3: // exiting + return std::get(result).status; + default: + LOG_WARNING( + logging::main_logger, "NOT IMPLEMENTED/Something went wrong" + ); + break; + } + } return 1; -} \ No newline at end of file +} diff --git a/src/graphics_main.hpp b/src/graphics_main.hpp index f691382a..1f9d11aa 100644 --- a/src/graphics_main.hpp +++ b/src/graphics_main.hpp @@ -23,6 +23,8 @@ #include +#include + /** * @brief Start Graphics window * @@ -36,3 +38,41 @@ int graphics_main(const argh::parser& cmdl); * @warning NOT IMPLEMENTED */ int graphics_main(); + +namespace intro_scene { + +enum return_to { + EXIT, + INTRO_SCENE, + NEW_GAME, + LOAD_GAME, +}; + +struct Exit { + int status = 0; +}; + +struct IntroPage {}; + +struct NewGame { + std::string biome; + int seed; + // map location; + // starting something + // difficulty etc + // int difficulty; +}; + +struct LoadGame { + std::filesystem::path game_file_path; +}; + +using result = std::variant; + +} // namespace intro_scene + +intro_scene::result intro_window(); + +intro_scene::result graphics_main(intro_scene::NewGame); + +intro_scene::result graphics_main(intro_scene::LoadGame); diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 71ae1bfb..4df86b67 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -80,8 +80,8 @@ UserInterface::update(screen_size_t width, screen_size_t height) { bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1] )); window_pipeline_->render( - bounding_box[0], bounding_box[1], bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, - frame.get() + bounding_box[0], bounding_box[1], bounding_box[2] - bounding_box[0], + bounding_box[3] - bounding_box[1], 0, frame.get() ); } } diff --git a/src/gui/ui/gui_entry.hpp b/src/gui/ui/gui_entry.hpp index 989e551e..52c99f8a 100644 --- a/src/gui/ui/gui_entry.hpp +++ b/src/gui/ui/gui_entry.hpp @@ -2,8 +2,7 @@ namespace gui { namespace ui { - - int main_gui_entry(); +int main_gui_entry(); } -} +} // namespace gui From 3f3a771ea0dbcaec898f2ac9d737d976db4c4798 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 10 Dec 2025 15:48:04 -0500 Subject: [PATCH 10/56] switch around graphics entrypoint --- src/graphics_main.cpp | 230 ++++++++++++++++++++++++++------------ src/graphics_main.hpp | 25 +++-- src/gui/scene/input.cpp | 4 + src/gui/scene/input.hpp | 3 + src/gui/ui/imgui_gui.cpp | 1 + src/gui/ui/opengl_gui.cpp | 1 + 6 files changed, 180 insertions(+), 84 deletions(-) diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index 226c3916..2c682928 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -30,8 +30,69 @@ struct background_result { std::unique_ptr climate; }; +// read settings from command line int graphics_main(const argh::parser& cmdl) { + size_t seed; + cmdl("seed", SEED) >> seed; + size_t size; + cmdl("size", STRESS_TEST_SIZE) >> size; + std::string biome_name; + cmdl("biome-name", BIOME_BASE_NAME) >> biome_name; + bool imgui_debug = cmdl[{"-g", "--imgui"}]; + + intro_scene::result new_game_settings = intro_scene::NewGame{ + .biome = biome_name, .seed = seed, .size = size, .DearIMGUI = imgui_debug}; + + return graphics_main(new_game_settings); +} + +int +graphics_main(intro_scene::result result) { + LOG_WARNING(logging::main_logger, "Only kinda implemented"); + + // global context and logging are already initalized. + + // read commands from file + // Things like screen size + // full screen + // all graphics/audio settings + // not that bad, make a settings header and define structures in there. + + // intro_scene::result result = intro_scene::IntroPage(); + + while (true) { + switch (result.index()) { + case 0: // exiting + return std::get(result).status; + case 1: // intro page + result = intro_window(); + break; + case 2: // new world with settings + { + // auto settings = std::get(result); + result = start_game(result); + } + break; + case 3: // from save with file path + { + // auto path = std::get(result); + result = start_game(result); + } + break; + default: + LOG_WARNING( + logging::main_logger, "NOT IMPLEMENTED/Something went wrong" + ); + break; + } + } + + return 1; +} + +intro_scene::result +start_game(intro_scene::result result) { // add window width and height? screen_size_t window_width = 1280; @@ -44,7 +105,7 @@ graphics_main(const argh::parser& cmdl) { gui::setup_opengl(window_width, window_height); if (!opt_window) { LOG_CRITICAL(logging::opengl_logger, "No Window, Exiting."); - return 1; + return intro_scene::Exit(1); } GLFWwindow* window = opt_window.value(); gui::setup_opengl_logging(); @@ -79,48 +140,46 @@ graphics_main(const argh::parser& cmdl) { splash_screen_pipeline->data.push_back(screen_data.get()); // background task { - - // Think about this later - // need to read biomes from manifest - // then in background need to mesh things - // then send those things back to main thread - // the main thread loads meshes onto gpu and renders to screen - // Read manifest - // util::load_manifest(); - GlobalContext& global_context = GlobalContext::instance(); - // don't forget ot load ScreenData onto gpu global_context.run_opengl_queue(); + manifest::ObjectHandler object_handler; - size_t seed; - cmdl("seed", SEED) >> seed; - size_t size; - cmdl("size", STRESS_TEST_SIZE) >> size; - std::string biome_name; - cmdl("biome-name", BIOME_BASE_NAME) >> biome_name; + std::future load_manifests_future; + bool imgui_debug; - manifest::ObjectHandler object_handler; - auto load_manifests_future = - global_context.submit_task([&object_handler, biome_name, size, seed]() { - background_result result; + if (result.index() == 2) { // new game + std::string biome_name = std::get(result).biome; + size_t size = std::get(result).size; + size_t seed = std::get(result).seed; + imgui_debug = std::get(result).DearIMGUI; - int manifest_result = object_handler.load_all_manifests(); + load_manifests_future = + global_context.submit_task([&object_handler, biome_name, size, seed]() { + background_result result; - result.result = manifest_result; + int manifest_result = object_handler.load_all_manifests(); - if (result.result == 1) { - return result; - } + result.result = manifest_result; - result.world = std::make_unique( - &object_handler, biome_name, size, size, seed - ); - result.world->generate_plants(); - result.climate = std::make_unique(); + if (result.result == 1) { + return result; + } - return result; - }); + result.world = std::make_unique( + &object_handler, biome_name, size, size, seed + ); + result.world->generate_plants(); + result.climate = std::make_unique(); + + return result; + }); + + } else if (result.index() == 2) { // load game + LOG_ERROR(logging::main_logger, "Loading World Not Implemented (yet*)"); + return intro_scene::IntroPage(); + // not implemented + } // generate options either from command line inputs // or from gui @@ -149,66 +208,89 @@ graphics_main(const argh::parser& cmdl) { if (future_value.result == 1) { LOG_ERROR(logging::main_logger, "Error Loading. Exiting."); - return 1; + return intro_scene::Exit(1); } world::World& world = *future_value.world; world::Climate& climate = *future_value.climate; // if need gui start gui - bool imgui_debug = cmdl[{"-g", "--imgui"}]; if (imgui_debug) { - return gui::imgui_entry(window, world, climate); + int gui_result = gui::imgui_entry(window, world, climate); + return intro_scene::Exit(gui_result); } else { // if don't then strate to opengl - return gui::opengl_entry(window, world, climate); + int gui_result = gui::opengl_entry(window, world, climate); + return intro_scene::Exit(gui_result); } glDeleteVertexArrays(1, &VertexArrayID); - return 0; + return intro_scene::Exit(0); } -int -graphics_main() { - LOG_WARNING(logging::main_logger, "Only kinda implemented"); +intro_scene::result +intro_window() { + screen_size_t window_width = 1280; + screen_size_t window_height = 800; - // global context and logging are already initalized. + screen_size_t display_w, display_h; + // init graphics - // read commands from file - // Things like screen size - // full screen - // all graphics/audio settings - // not that bad, make a settings header and define structures in there. + std::optional opt_window = + gui::setup_opengl(window_width, window_height); + if (!opt_window) { + LOG_CRITICAL(logging::opengl_logger, "No Window, Exiting."); + return intro_scene::Exit(1); + } + GLFWwindow* window = opt_window.value(); + gui::setup_opengl_logging(); - intro_scene::result result = intro_scene::IntroPage(); + GLuint VertexArrayID; + glGenVertexArrays(1, &VertexArrayID); + gui::VertexBufferHandler::instance().bind_vertex_buffer(VertexArrayID); - while (true) { - switch (result.index()) { - case 0: // intro page - result = intro_window(); - break; - case 1: // new world with settings - { - auto settings = std::get(result); - result = graphics_main(settings); - } - break; - case 2: // from save with file path - { - auto path = std::get(result); - result = graphics_main(path); - } - break; - case 3: // exiting - return std::get(result).status; - default: - LOG_WARNING( - logging::main_logger, "NOT IMPLEMENTED/Something went wrong" - ); - break; - } + // Start Splash screen + gui::shader::ShaderHandler temp_handler; + gui::shader::Program& splash_screen_program = temp_handler.load_program( + "Splash Screen", files::get_resources_path() / "shaders" / "Passthrough.vert", + files::get_resources_path() / "shaders" / "Blue.frag" + ); + + std::function splash_screen_setup = []() { + // Draw over everything + glDisable(GL_CULL_FACE); + // The sky has no depth + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + }; + + auto splash_screen_pipeline = std::make_shared( + splash_screen_program, splash_screen_setup + ); + + auto screen_data = std::make_shared(); + + splash_screen_pipeline->data.push_back(screen_data.get()); + + // background task { + GlobalContext& global_context = GlobalContext::instance(); + // don't forget ot load ScreenData onto gpu + global_context.run_opengl_queue(); + + while (!glfwWindowShouldClose(window)) { + glfwGetFramebufferSize(window, &display_w, &display_h); + + // gui::FrameBufferHandler::instance().bind_fbo(0); + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // glViewport(0, 0, display_w, display_h); + + splash_screen_pipeline->render(display_w, display_h, 0); + + glfwSwapBuffers(window); + glfwPollEvents(); } - return 1; + return intro_scene::Exit(0); } diff --git a/src/graphics_main.hpp b/src/graphics_main.hpp index 1f9d11aa..4d032725 100644 --- a/src/graphics_main.hpp +++ b/src/graphics_main.hpp @@ -23,6 +23,7 @@ #include +#include #include /** @@ -32,13 +33,6 @@ */ int graphics_main(const argh::parser& cmdl); -/** - * @brief Start Graphics window - * - * @warning NOT IMPLEMENTED - */ -int graphics_main(); - namespace intro_scene { enum return_to { @@ -56,15 +50,18 @@ struct IntroPage {}; struct NewGame { std::string biome; - int seed; + size_t seed; + size_t size; // map location; // starting something // difficulty etc // int difficulty; + bool DearIMGUI; }; struct LoadGame { std::filesystem::path game_file_path; + bool DearIMGUI; }; using result = std::variant; @@ -73,6 +70,14 @@ using result = std::variant; intro_scene::result intro_window(); -intro_scene::result graphics_main(intro_scene::NewGame); +// should this be templated who knows? +intro_scene::result start_game(intro_scene::result); + +// intro_scene::result graphics_main(intro_scene::LoadGame); -intro_scene::result graphics_main(intro_scene::LoadGame); +/** + * @brief Start Graphics window + * + * + */ +int graphics_main(intro_scene::result result = intro_scene::IntroPage()); diff --git a/src/gui/scene/input.cpp b/src/gui/scene/input.cpp index 60133bc7..2e379d54 100644 --- a/src/gui/scene/input.cpp +++ b/src/gui/scene/input.cpp @@ -10,6 +10,7 @@ namespace scene { GLFWwindow* InputHandler::window_ = nullptr; std::shared_ptr InputHandler::forward_inputs_ = nullptr; bool InputHandler::escape_pressed_ = false; +bool InputHandler::imgui_active = false; void InputHandler::set_window(GLFWwindow* window) { @@ -45,6 +46,9 @@ InputHandler::forward_inputs_to(std::shared_ptr forward_to) { bool InputHandler::imgui_capture() { + if (!imgui_active) { + return false; + } ImGuiIO& io = ImGui::GetIO(); return (io.WantCaptureKeyboard || io.WantCaptureMouse || io.WantTextInput); } diff --git a/src/gui/scene/input.hpp b/src/gui/scene/input.hpp index 0ba77c43..78c08755 100644 --- a/src/gui/scene/input.hpp +++ b/src/gui/scene/input.hpp @@ -165,6 +165,9 @@ class Inputs { class InputHandler { // somehow the plan was to only let GlobalContext set the window + public: + static bool imgui_active; + protected: // so realistically we would have a unordered map that maps the window // but im not making multiple windows diff --git a/src/gui/ui/imgui_gui.cpp b/src/gui/ui/imgui_gui.cpp index 498768a5..d940bc21 100644 --- a/src/gui/ui/imgui_gui.cpp +++ b/src/gui/ui/imgui_gui.cpp @@ -84,6 +84,7 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { : gui::scene::KeyMapping(); std::shared_ptr controller = std::make_shared(key_mapping); + scene::InputHandler::imgui_active = true; scene::InputHandler::set_window(window); scene::InputHandler::forward_inputs_to(static_pointer_cast(controller )); diff --git a/src/gui/ui/opengl_gui.cpp b/src/gui/ui/opengl_gui.cpp index c59f7686..673c1807 100644 --- a/src/gui/ui/opengl_gui.cpp +++ b/src/gui/ui/opengl_gui.cpp @@ -47,6 +47,7 @@ opengl_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { : gui::scene::KeyMapping(); std::shared_ptr controller = std::make_shared(key_mapping); + scene::InputHandler::imgui_active = false; scene::InputHandler::set_window(window); scene::InputHandler::forward_inputs_to(controller); From 3957aee0294a2fb5ac217c904fe3d175d4c656a5 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 12 Dec 2025 23:18:38 -0500 Subject: [PATCH 11/56] refactoring --- src/exceptions.hpp | 5 ++- src/graphics_main.cpp | 89 ++++++++++++--------------------------- src/graphics_main.hpp | 7 ++- src/gui/ui/opengl_gui.cpp | 3 -- 4 files changed, 35 insertions(+), 69 deletions(-) diff --git a/src/exceptions.hpp b/src/exceptions.hpp index 7e9993df..6976bc28 100644 --- a/src/exceptions.hpp +++ b/src/exceptions.hpp @@ -8,13 +8,14 @@ namespace exc { class file_not_found_error : public std::runtime_error { - constexpr static std::string ERROR_PREFIX_ = "Could not open "; + constexpr static std::string_view ERROR_PREFIX_ = "Could not open "; std::filesystem::path path_; public: file_not_found_error(std::filesystem::path path) : - runtime_error(ERROR_PREFIX_ + path.string()), path_(std::move(path)) {} + runtime_error(std::move(std::string(ERROR_PREFIX_) + path.string())), + path_(std::move(path)) {} file_not_found_error(const file_not_found_error& other) noexcept = default; diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index 2c682928..4296858c 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -42,7 +42,8 @@ graphics_main(const argh::parser& cmdl) { bool imgui_debug = cmdl[{"-g", "--imgui"}]; intro_scene::result new_game_settings = intro_scene::NewGame{ - .biome = biome_name, .seed = seed, .size = size, .DearIMGUI = imgui_debug}; + .biome = biome_name, .seed = seed, .size = size, .DearIMGUI = imgui_debug + }; return graphics_main(new_game_settings); } @@ -59,6 +60,23 @@ graphics_main(intro_scene::result result) { // all graphics/audio settings // not that bad, make a settings header and define structures in there. + screen_size_t window_width = 1280; + screen_size_t window_height = 800; + // init graphics + + std::optional opt_window = + gui::setup_opengl(window_width, window_height); + if (!opt_window) { + LOG_CRITICAL(logging::opengl_logger, "No Window, Exiting."); + return 1; + } + // TODO stream line this part and make sure to clean things up correctly + GLFWwindow* window = opt_window.value(); + gui::setup_opengl_logging(); + + GLuint VertexArrayID; + glGenVertexArrays(1, &VertexArrayID); + gui::VertexBufferHandler::instance().bind_vertex_buffer(VertexArrayID); // intro_scene::result result = intro_scene::IntroPage(); while (true) { @@ -66,18 +84,18 @@ graphics_main(intro_scene::result result) { case 0: // exiting return std::get(result).status; case 1: // intro page - result = intro_window(); + result = intro_window(window); break; case 2: // new world with settings { // auto settings = std::get(result); - result = start_game(result); + result = start_game(result, window); } break; case 3: // from save with file path { // auto path = std::get(result); - result = start_game(result); + result = start_game(result, window); } break; default: @@ -88,31 +106,15 @@ graphics_main(intro_scene::result result) { } } + glDeleteVertexArrays(1, &VertexArrayID); return 1; } intro_scene::result -start_game(intro_scene::result result) { +start_game(intro_scene::result result, GLFWwindow* window) { // add window width and height? - screen_size_t window_width = 1280; - screen_size_t window_height = 800; - screen_size_t display_w, display_h; - // init graphics - - std::optional opt_window = - gui::setup_opengl(window_width, window_height); - if (!opt_window) { - LOG_CRITICAL(logging::opengl_logger, "No Window, Exiting."); - return intro_scene::Exit(1); - } - GLFWwindow* window = opt_window.value(); - gui::setup_opengl_logging(); - - GLuint VertexArrayID; - glGenVertexArrays(1, &VertexArrayID); - gui::VertexBufferHandler::instance().bind_vertex_buffer(VertexArrayID); // Start Splash screen gui::shader::ShaderHandler temp_handler; @@ -124,7 +126,6 @@ start_game(intro_scene::result result) { std::function splash_screen_setup = []() { // Draw over everything glDisable(GL_CULL_FACE); - // The sky has no depth glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); }; @@ -139,7 +140,7 @@ start_game(intro_scene::result result) { splash_screen_pipeline->data.push_back(screen_data.get()); - // background task { + // background task GlobalContext& global_context = GlobalContext::instance(); // don't forget ot load ScreenData onto gpu global_context.run_opengl_queue(); @@ -181,23 +182,12 @@ start_game(intro_scene::result result) { // not implemented } - // generate options either from command line inputs - // or from gui - // struct Options - - //} - // can't cancel a task after it has been started run. while (load_manifests_future.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { glfwGetFramebufferSize(window, &display_w, &display_h); - // gui::FrameBufferHandler::instance().bind_fbo(0); - // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // glViewport(0, 0, display_w, display_h); - splash_screen_pipeline->render(display_w, display_h, 0); glfwSwapBuffers(window); @@ -224,31 +214,13 @@ start_game(intro_scene::result result) { return intro_scene::Exit(gui_result); } - glDeleteVertexArrays(1, &VertexArrayID); - return intro_scene::Exit(0); } +// TODO move to separate file intro_scene::result -intro_window() { - screen_size_t window_width = 1280; - screen_size_t window_height = 800; - +intro_window(GLFWwindow* window) { screen_size_t display_w, display_h; - // init graphics - - std::optional opt_window = - gui::setup_opengl(window_width, window_height); - if (!opt_window) { - LOG_CRITICAL(logging::opengl_logger, "No Window, Exiting."); - return intro_scene::Exit(1); - } - GLFWwindow* window = opt_window.value(); - gui::setup_opengl_logging(); - - GLuint VertexArrayID; - glGenVertexArrays(1, &VertexArrayID); - gui::VertexBufferHandler::instance().bind_vertex_buffer(VertexArrayID); // Start Splash screen gui::shader::ShaderHandler temp_handler; @@ -260,7 +232,6 @@ intro_window() { std::function splash_screen_setup = []() { // Draw over everything glDisable(GL_CULL_FACE); - // The sky has no depth glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); }; @@ -273,7 +244,6 @@ intro_window() { splash_screen_pipeline->data.push_back(screen_data.get()); - // background task { GlobalContext& global_context = GlobalContext::instance(); // don't forget ot load ScreenData onto gpu global_context.run_opengl_queue(); @@ -281,11 +251,6 @@ intro_window() { while (!glfwWindowShouldClose(window)) { glfwGetFramebufferSize(window, &display_w, &display_h); - // gui::FrameBufferHandler::instance().bind_fbo(0); - // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // glViewport(0, 0, display_w, display_h); - splash_screen_pipeline->render(display_w, display_h, 0); glfwSwapBuffers(window); diff --git a/src/graphics_main.hpp b/src/graphics_main.hpp index 4d032725..eb110b23 100644 --- a/src/graphics_main.hpp +++ b/src/graphics_main.hpp @@ -23,6 +23,9 @@ #include +#include +#include + #include #include @@ -68,10 +71,10 @@ using result = std::variant; } // namespace intro_scene -intro_scene::result intro_window(); +intro_scene::result intro_window(GLFWwindow* window); // should this be templated who knows? -intro_scene::result start_game(intro_scene::result); +intro_scene::result start_game(intro_scene::result, GLFWwindow* window); // intro_scene::result graphics_main(intro_scene::LoadGame); diff --git a/src/gui/ui/opengl_gui.cpp b/src/gui/ui/opengl_gui.cpp index 673c1807..9a7e8708 100644 --- a/src/gui/ui/opengl_gui.cpp +++ b/src/gui/ui/opengl_gui.cpp @@ -1,6 +1,5 @@ #include "opengl_gui.hpp" -#include "../gui_logging.hpp" #include "../handler.hpp" #include "../render/graphics_shaders/program_handler.hpp" #include "../scene/controls.hpp" @@ -10,7 +9,6 @@ #include "opengl_setup.hpp" #include "scene_setup.hpp" #include "util/files.hpp" -#include "util/mesh.hpp" #include "world/climate.hpp" #include "world/world.hpp" @@ -20,7 +18,6 @@ #include #include -#include namespace gui { From cb14f29df1e31e78de89f77164ca13aa9138fd0b Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 13 Dec 2025 11:49:21 -0500 Subject: [PATCH 12/56] frame searching --- src/graphics_main.cpp | 3 +- .../render/graphics_shaders/render_types.hpp | 2 +- .../graphics_shaders/shader_program.cpp | 2 +- .../graphics_shaders/shader_program.hpp | 2 +- src/gui/the_buttons/frame.hpp | 31 ++- src/gui/the_buttons/user_interface.cpp | 184 ++++++++++++++++-- src/gui/the_buttons/user_interface.hpp | 113 ++++++++++- 7 files changed, 314 insertions(+), 23 deletions(-) diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index 4296858c..89c1d630 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -42,8 +42,7 @@ graphics_main(const argh::parser& cmdl) { bool imgui_debug = cmdl[{"-g", "--imgui"}]; intro_scene::result new_game_settings = intro_scene::NewGame{ - .biome = biome_name, .seed = seed, .size = size, .DearIMGUI = imgui_debug - }; + .biome = biome_name, .seed = seed, .size = size, .DearIMGUI = imgui_debug}; return graphics_main(new_game_settings); } diff --git a/src/gui/render/graphics_shaders/render_types.hpp b/src/gui/render/graphics_shaders/render_types.hpp index 8cdae56a..3cb286f8 100644 --- a/src/gui/render/graphics_shaders/render_types.hpp +++ b/src/gui/render/graphics_shaders/render_types.hpp @@ -47,7 +47,7 @@ class ScreenSection { public: virtual void render( screen_size_t x_start, screen_size_t y_start, screen_size_t width, - screen_size_t height, GLuint frame_buffer, gpu_data::GPUData* data + screen_size_t height, GLuint frame_buffer, const gpu_data::GPUData* data ) = 0; }; diff --git a/src/gui/render/graphics_shaders/shader_program.cpp b/src/gui/render/graphics_shaders/shader_program.cpp index b53305c8..03c993b2 100644 --- a/src/gui/render/graphics_shaders/shader_program.cpp +++ b/src/gui/render/graphics_shaders/shader_program.cpp @@ -52,7 +52,7 @@ Render_Base::render( void ShaderProgram_Windows::render( screen_size_t x_start, screen_size_t y_start, screen_size_t width, - screen_size_t height, GLuint framebuffer_ID, gpu_data::GPUData* data + screen_size_t height, GLuint framebuffer_ID, const gpu_data::GPUData* data ) { if (!data->do_render()) { return; diff --git a/src/gui/render/graphics_shaders/shader_program.hpp b/src/gui/render/graphics_shaders/shader_program.hpp index 6ca61a40..277bdf50 100644 --- a/src/gui/render/graphics_shaders/shader_program.hpp +++ b/src/gui/render/graphics_shaders/shader_program.hpp @@ -145,7 +145,7 @@ class ShaderProgram_Windows : void virtual render( screen_size_t x_start, screen_size_t y_start, screen_size_t width, - screen_size_t height, GLuint framebuffer_ID, gpu_data::GPUData* data + screen_size_t height, GLuint framebuffer_ID, const gpu_data::GPUData* data ) override; }; diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index 163ae689..542fdb6f 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -21,19 +21,28 @@ class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { Frame* parent; std::unordered_set children; + bool fixed_; // fixed position in render queue /* data */ void exterior_changed(); // need to change exterior for parent. bool is_selected; public: - Frame(/* args */){}; + Frame(/* args */) : parent(nullptr){}; inline virtual ~Frame(){}; // kill children bool is_interior(screen_size_t x, screen_size_t y) const; + + const std::shared_ptr get_frame_at_position(screen_size_t x, screen_size_t y) const; + bool check_children(); + inline bool + is_fixed() const { + return fixed_; + } + bool is_visible(); void on_select(); @@ -41,6 +50,26 @@ class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { void on_end_select(); virtual std::array get_bounding_box() const = 0; + [[nodiscard]] inline screen_size_t + get_x_position() const { + return x_position; + } + + [[nodiscard]] inline screen_size_t + get_y_position() const { + return y_position; + } + + [[nodiscard]] inline const auto + begin() const { + return children.begin(); + } + + [[nodiscard]] inline const auto + end() const { + return children.end(); + } + /** * @brief Handle key input including mouse keys * diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 4df86b67..15386e59 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -66,26 +66,178 @@ UserInterface::update(screen_size_t width, screen_size_t height) { glClear(GL_DEPTH_BUFFER_BIT); for (const auto& frame : frames_) { - if (!frame->do_render()) { - continue; - } - // frame->update_position(); - - texture_regions_->set_texture_regions({0, 0, 5, 5, 0, 5, 5, 1, 0, 6, 5, 1, - 5, 0, 1, 5, 5, 5, 1, 1, 6, 5, 5, 1, - 6, 0, 5, 5, 6, 5, 5, 1, 6, 6, 5, 5}); - - const auto bounding_box = frame->get_bounding_box(); - frame_size_uniform_->set_frame_size(glm::ivec2( - bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1] - )); - window_pipeline_->render( - bounding_box[0], bounding_box[1], bounding_box[2] - bounding_box[0], - bounding_box[3] - bounding_box[1], 0, frame.get() + render_frame(*frame, 0, 0); + } +} + +void +UserInterface::render_frame( + const Frame& frame, screen_size_t x_frame_position, screen_size_t y_frame_position +) const { + if (!frame.do_render()) { + return; + } + + texture_regions_->set_texture_regions({0, 0, 5, 5, 0, 5, 5, 1, 0, 6, 5, 1, + 5, 0, 1, 5, 5, 5, 1, 1, 6, 5, 5, 1, + 6, 0, 5, 5, 6, 5, 5, 1, 6, 6, 5, 5}); + + const auto bounding_box = frame.get_bounding_box(); + // add offset + frame_size_uniform_->set_frame_size( + glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) + ); + window_pipeline_->render( + bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, + bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, + static_cast(&frame) + ); + + for (const auto& frame_child : frame) { + render_frame( + *frame_child, frame_child->get_x_position() + x_frame_position, + frame_child->get_y_position() + y_frame_position ); } } +std::pair, const std::shared_ptr> +UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) + const { + // iterate from back to front + auto frame_outer = frames_.end(); + do { + frame_outer--; + if ((*frame_outer)->is_interior(mouse_position_x, mouse_position_y)) { + break; + } + } while (frame_outer != frames_.begin()); + + auto x_offset = (*frame_outer)->get_x_position(); + auto y_offset = (*frame_outer)->get_y_position(); + + const std::shared_ptr frame_inner = (*frame_outer)->get_frame_at_position(mouse_position_x - x_offset, mouse_position_y - y_offset); + + const std::shared_ptr new_frame_outer = *frame_outer; + + return std::make_pair, const std::shared_ptr>( + std::move(new_frame_outer), + std::move(frame_inner) + ); +} + +void +UserInterface::reselect_frame(GLFWwindow* window) { + // forward to + double xpos; + double ypos; + glfwGetCursorPos(window, &xpos, &ypos); + auto selected_frames = get_frame(screen_size_t(xpos), screen_size_t(ypos)); + + if (selected_frames.first) { + // move to back + if (!selected_frames.first->is_fixed()) { + frames_.remove(selected_frames.first); + frames_.push_back(selected_frames.first); + } + } + + if (selected_frames.second) { + selected_frame_ = selected_frames.second; + } else { + selected_frame_ = nullptr; + } +} + +void +UserInterface::handle_key_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, + [[maybe_unused]] int scancode, [[maybe_unused]] int action, + [[maybe_unused]] int mods +) { + if (selected_frame_) { + selected_frame_->handle_key_event_input(window, key, scancode, action, mods); + } +} + +void +UserInterface::handle_text_input_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] unsigned int codepoint +) { + if (selected_frame_) { + selected_frame_->handle_text_input_input(window, codepoint); + } +} + +void +UserInterface::handle_mouse_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xpos, + [[maybe_unused]] double ypos +) { + if (selected_frame_) { + selected_frame_->handle_mouse_event_input(window, xpos, ypos); + } +} + +void +UserInterface::handle_mouse_enter_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int entered +) {} // don't bother + +void +UserInterface::handle_mouse_button_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, + [[maybe_unused]] int action, [[maybe_unused]] int mods +) { + reselect_frame(window); + if (selected_frame_) { + handle_mouse_button_input(window, button, action, mods); + } +} + +void +UserInterface::handle_mouse_scroll_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xoffset, + [[maybe_unused]] double yoffset +) { + // possibly forward + if (selected_frame_) { + selected_frame_->handle_mouse_scroll_input(window, xoffset, yoffset); + } + // forward to top + // selected position then forward +} + +void +UserInterface::handle_joystick_input( + [[maybe_unused]] int jid, [[maybe_unused]] int event +) {} + +void +UserInterface::handle_file_drop_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int count, + [[maybe_unused]] const char** paths +) { + // drop onto mouse position + reselect_frame(window); + if (selected_frame_) { + selected_frame_->handle_file_drop_input(window, count, paths); + } +} + +void +UserInterface::handle_pooled_inputs([[maybe_unused]] GLFWwindow* window) { + if (selected_frame_) { + selected_frame_->handle_pooled_inputs(window); + } +} + +void +UserInterface::setup([[maybe_unused]] GLFWwindow* window) {} + +void +UserInterface::cleanup([[maybe_unused]] GLFWwindow* window) {} + } // namespace the_buttons } // namespace gui diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index ce579fc5..3d05de96 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -11,7 +11,7 @@ namespace gui { namespace the_buttons { -class UserInterface { +class UserInterface : public virtual scene::Inputs { private: // uniform std::shared_ptr frame_size_uniform_; @@ -24,6 +24,13 @@ class UserInterface { std::list> frames_; + std::shared_ptr selected_frame_; // widget? + + [[nodiscard]] std::pair, const std::shared_ptr> + get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const; + + void reselect_frame(GLFWwindow* window); + public: UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_scale); @@ -39,6 +46,110 @@ class UserInterface { auto pos = frames_.begin(); frames_.insert(pos, frame); } + + void render_frame( + const Frame& frame, screen_size_t x_frame_position, + screen_size_t y_frame_position + ) const; + + /** + * @brief Handle key input including mouse keys + * + * @param GLFWwindow* window window event came from + * @param int key GLFW key enum + * @param int scancode GLFW scancode enum + * @param int action GLFW action one of GLFW_PRESS, GLFW_RELEASE, GLFW_REPEAT + * @param int mods GLFW mods enum + */ + virtual void handle_key_event_input( + GLFWwindow* window, int key, int scancode, int action, int mods + ); + + /** + * @brief Handle text input + * + * @param GLFWwindow* window window to listen on + * @param unsigned int codepoint unicode 32 character. + */ + + virtual void handle_text_input_input(GLFWwindow* window, unsigned int codepoint); + + /** + * @brief Handle mouse movement events. + * + * @param GLFWwindow* window window to listen on + * @param double xpos x position in window coordinates + * @param double ypos y position in window coordinates. + */ + virtual void handle_mouse_event_input(GLFWwindow* window, double xpos, double ypos); + + /** + * @brief Handle mouse enter window events + * + * @param GLFWwindow* window window to listen on + * @param int entered 1 if the curser entered the window, 0 if it exited. + */ + virtual void handle_mouse_enter_input(GLFWwindow* window, int entered); + + /** + * @brief Handle mouse enter window events + * + * @param GLFWwindow* window window to listen on + * @param int button + * @param int action + * @param int mods + */ + virtual void + handle_mouse_button_input(GLFWwindow* window, int button, int action, int mods); + + /** + * @brief Handle mouse scroll events + * + * @param GLFWwindow* window window to listen on + * @param double xoffset x offset + * @param double yoffset y offset (usually 0) + */ + virtual void + handle_mouse_scroll_input(GLFWwindow* window, double xoffset, double yoffset); + + /** + * @brief Handle joystick event + * + * @param int jid joystick id + * @param int event + */ + virtual void handle_joystick_input(int jid, int event); + + /** + * @brief Handle file drop event + * + * @param GLFWwindow* window window to listen on + * @param int count number of files passed + * @param const char** paths file paths + */ + virtual void + handle_file_drop_input(GLFWwindow* window, int count, const char** paths); + + /** + * @brief Handle all pooled inputs + * + * @param GLFWwindow* window window + */ + virtual void handle_pooled_inputs(GLFWwindow* window); + + /** + * @brief Setup so this objects handles inputs correctly + * + * @param GLFWwindow* window window + */ + virtual void setup(GLFWwindow* window); + + /** + * @brief Cleanup to original state + * + * @param GLFWwindow* window window + */ + virtual void cleanup(GLFWwindow* window); }; } // namespace the_buttons From ff7338dd3bf4679a3eb07b01f83ca9fdd6651216 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 14 Dec 2025 13:14:37 -0500 Subject: [PATCH 13/56] click position --- resources/textures/GenericBorder_2.png | Bin 0 -> 221 bytes src/gui/the_buttons/bordered_window.cpp | 12 +++- src/gui/the_buttons/bordered_window.hpp | 8 ++- src/gui/the_buttons/frame.cpp | 77 ++++++++++++++++++++++++ src/gui/the_buttons/frame.hpp | 50 ++++++++++----- src/gui/the_buttons/user_interface.cpp | 27 +++++---- src/gui/the_buttons/user_interface.hpp | 11 +++- src/gui/ui/user_interface_setup.cpp | 5 +- 8 files changed, 155 insertions(+), 35 deletions(-) create mode 100644 resources/textures/GenericBorder_2.png create mode 100644 src/gui/the_buttons/frame.cpp diff --git a/resources/textures/GenericBorder_2.png b/resources/textures/GenericBorder_2.png new file mode 100644 index 0000000000000000000000000000000000000000..13a59cf6f0467f98470a2e1294be35683fe17926 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fOFUg1Lo9leQw}h#d6M!kS@<|> zpKaBl4!vVdX9Hw21B1?_CL|>M=+Cp@YWH!LlmLQtHnqKviY%D#UeNZB7fw~!B{$+ENmtd!yJdS&(prz RE&;li!PC{xWt~$(698ByR2BdL literal 0 HcmV?d00001 diff --git a/src/gui/the_buttons/bordered_window.cpp b/src/gui/the_buttons/bordered_window.cpp index 3971f51e..21360373 100644 --- a/src/gui/the_buttons/bordered_window.cpp +++ b/src/gui/the_buttons/bordered_window.cpp @@ -4,10 +4,18 @@ namespace gui { namespace the_buttons { -BorderedWindow::BorderedWindow(std::shared_ptr data) : +BorderedWindow::BorderedWindow( + std::shared_ptr data, glm::ivec2 position, + glm::ivec2 frame_size +) : + Frame( + position, frame_size, + {position, glm::ivec2(position.x + frame_size.x, position.y), + position + frame_size, glm::ivec2(position.x, position.y + frame_size.y)} + ), data_(data) { data_->update_position(get_bounding_box()); } } // namespace the_buttons -} // namespace gui \ No newline at end of file +} // namespace gui diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp index c7830a10..99c6f460 100644 --- a/src/gui/the_buttons/bordered_window.hpp +++ b/src/gui/the_buttons/bordered_window.hpp @@ -1,7 +1,6 @@ #pragma once #include "frame.hpp" -#include "gui/render/structures/screen_data.hpp" #include "gui/render/structures/window_texture.hpp" #include @@ -36,7 +35,10 @@ class BorderedWindow : public virtual Frame { */ BorderedWindow& operator=(BorderedWindow&& obj) = default; - BorderedWindow(std::shared_ptr data); + BorderedWindow( + std::shared_ptr data, glm::ivec2 position, + glm::ivec2 size + ); inline virtual ~BorderedWindow(){}; @@ -62,7 +64,7 @@ class BorderedWindow : public virtual Frame { inline virtual std::array get_bounding_box() const { - return {70, 70, 230, 230}; + return {position_.x, position_.y, frame_size_.x, frame_size_.y}; } }; diff --git a/src/gui/the_buttons/frame.cpp b/src/gui/the_buttons/frame.cpp new file mode 100644 index 00000000..dc90d2a6 --- /dev/null +++ b/src/gui/the_buttons/frame.cpp @@ -0,0 +1,77 @@ +#include "frame.hpp" + +#include "logging.hpp" +#include "types.hpp" + +#include + +#include + +namespace gui { + +namespace the_buttons { + +std::weak_ptr +Frame::get_child_at_position(screen_size_t x, screen_size_t y) const { + for (const auto& child : children) { + if (child->is_interior(x, y)) { + if (child->has_children()) { + return child->get_child_at_position(x - position_.x, y - position_.y); + } else { + return child; + } + } + } + + LOG_WARNING(logging::main_logger, "Faailed to find frame."); + return {}; +} + +bool +Frame::is_interior(screen_size_t x, screen_size_t y) const { + const auto bounding_box = get_bounding_box(); + if (x < bounding_box[0] || y < bounding_box[1] + || x > bounding_box[0] + bounding_box[2] + || y > bounding_box[1] + bounding_box[3]) { + return false; + } + + //clang-format off + /* + * (previous_position) + * * + * * (current position) + * x + * (x, y) + * |----|--------------| + * w1 w2 + * + * w2 * previous_position.y + w1 * current_position.y + * y_line = ------------------------------------------------------ + * w1 + w2 + * + * If there are an odd number of lines above the position then it is on the + * interior. + */ + //clang-format on + + bool interior_flag = false; + glm::ivec2 previous_position = exterior_points_.back(); + + for (const auto& current_position : exterior_points_) { + int x_weight_1 = std::abs(previous_position.x - x); + int x_weight_2 = std::abs(current_position.x - x); + + if (y * (x_weight_1 + x_weight_2) + > previous_position.y * x_weight_2 + current_position.y * x_weight_1) { + interior_flag = !interior_flag; + } + + previous_position = current_position; + } + + return interior_flag; +} + +} // namespace the_buttons +} // namespace gui diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index 542fdb6f..ecdc72fb 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -4,9 +4,8 @@ #include "gui/scene/input.hpp" #include "types.hpp" -#include +#include #include -#include #include namespace gui { @@ -14,30 +13,51 @@ namespace gui { namespace the_buttons { class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { - private: - screen_size_t x_position; - screen_size_t y_position; - std::vector> exterior_points; + protected: + glm::ivec2 position_; + glm::ivec2 frame_size_; + std::vector exterior_points_; - Frame* parent; - std::unordered_set children; + Frame* parent_; bool fixed_; // fixed position in render queue - /* data */ + std::unordered_set> children; void exterior_changed(); // need to change exterior for parent. bool is_selected; public: - Frame(/* args */) : parent(nullptr){}; + Frame( + glm::ivec2 position, glm::ivec2 frame_size, + std::vector exterior_points, Frame* parent = nullptr, + bool fixed = false + ) : + position_(position), + frame_size_(frame_size), exterior_points_(exterior_points), parent_(parent), + fixed_(fixed){}; + inline virtual ~Frame(){}; // kill children bool is_interior(screen_size_t x, screen_size_t y) const; + std::weak_ptr + get_child_at_position(screen_size_t x, screen_size_t y) const; - const std::shared_ptr get_frame_at_position(screen_size_t x, screen_size_t y) const; + [[nodiscard]] inline bool + has_children() const { + return !children.empty(); + } bool check_children(); + // private: + //bool add_child(std::shared_ptr child_frame); + + // might want to make it such that after a child has been added + // nothing else can be added to it. + // This will prevent circular references. + // do this be checking if parent is set. + // could also do the opposite and require that initialized with parent. + inline bool is_fixed() const { return fixed_; @@ -52,20 +72,20 @@ class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { [[nodiscard]] inline screen_size_t get_x_position() const { - return x_position; + return position_.x; } [[nodiscard]] inline screen_size_t get_y_position() const { - return y_position; + return position_.y; } - [[nodiscard]] inline const auto + [[nodiscard]] inline auto begin() const { return children.begin(); } - [[nodiscard]] inline const auto + [[nodiscard]] inline auto end() const { return children.end(); } diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 15386e59..a309f57d 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -101,7 +101,7 @@ UserInterface::render_frame( } } -std::pair, const std::shared_ptr> +std::pair, std::weak_ptr> UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const { // iterate from back to front @@ -116,13 +116,16 @@ UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_pos auto x_offset = (*frame_outer)->get_x_position(); auto y_offset = (*frame_outer)->get_y_position(); - const std::shared_ptr frame_inner = (*frame_outer)->get_frame_at_position(mouse_position_x - x_offset, mouse_position_y - y_offset); + std::weak_ptr frame_inner = + (*frame_outer) + ->get_child_at_position( + mouse_position_x - x_offset, mouse_position_y - y_offset + ); - const std::shared_ptr new_frame_outer = *frame_outer; + std::weak_ptr new_frame_outer = *frame_outer; - return std::make_pair, const std::shared_ptr>( - std::move(new_frame_outer), - std::move(frame_inner) + return std::make_pair, std::weak_ptr>( + std::move(new_frame_outer), std::move(frame_inner) ); } @@ -134,16 +137,16 @@ UserInterface::reselect_frame(GLFWwindow* window) { glfwGetCursorPos(window, &xpos, &ypos); auto selected_frames = get_frame(screen_size_t(xpos), screen_size_t(ypos)); - if (selected_frames.first) { + if (std::shared_ptr outer_frame = selected_frames.first.lock()) { // move to back - if (!selected_frames.first->is_fixed()) { - frames_.remove(selected_frames.first); - frames_.push_back(selected_frames.first); + if (!outer_frame->is_fixed()) { + frames_.remove(outer_frame); + frames_.push_back(outer_frame); } } - if (selected_frames.second) { - selected_frame_ = selected_frames.second; + if (std::shared_ptr inner_frame = selected_frames.second.lock()) { + selected_frame_ = inner_frame; } else { selected_frame_ = nullptr; } diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 3d05de96..fecb45dc 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -26,9 +26,18 @@ class UserInterface : public virtual scene::Inputs { std::shared_ptr selected_frame_; // widget? - [[nodiscard]] std::pair, const std::shared_ptr> + [[nodiscard]] std::pair, std::weak_ptr> get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const; + [[nodiscard]] inline std::pair, std::weak_ptr> + get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) { + auto got_frames = get_frame(mouse_position_x, mouse_position_y); + return std::make_pair, std::weak_ptr>( + std::const_pointer_cast(got_frames.first.lock()), + std::const_pointer_cast(got_frames.second.lock()) + ); + } + void reselect_frame(GLFWwindow* window); public: diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index ab4b30a5..05447b19 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -2,7 +2,6 @@ #include "../the_buttons/bordered_window.hpp" #include "../the_buttons/user_interface.hpp" -#include "gui/render/gpu_data/texture.hpp" #include "util/files.hpp" #include "util/png_image.hpp" @@ -21,7 +20,9 @@ setup(the_buttons::UserInterface& user_interface) { std::shared_ptr a_window = std::make_shared( - std::make_shared(image) + std::make_shared(image), + + glm::ivec2(70, 70), glm::ivec2(230, 230) ); user_interface.add(a_window); From c9946a0cbb80b5410193d65207720a0452d08c4e Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 14 Dec 2025 14:59:36 -0500 Subject: [PATCH 14/56] two windows, and I can click them --- src/graphics_main.cpp | 20 ++++++++++++++++++++ src/gui/the_buttons/frame.hpp | 2 +- src/gui/the_buttons/user_interface.cpp | 13 +++++++++---- src/gui/the_buttons/user_interface.hpp | 2 +- src/gui/ui/imgui_gui.cpp | 5 +++-- src/gui/ui/user_interface_setup.cpp | 10 ++++++++++ 6 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index 89c1d630..0ad30d81 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -4,9 +4,12 @@ #include "config.h" #include "gui/handler.hpp" #include "gui/render/structures/screen_data.hpp" +#include "gui/scene/input.hpp" +#include "gui/the_buttons/user_interface.hpp" #include "gui/ui/imgui_gui.hpp" #include "gui/ui/opengl_gui.hpp" #include "gui/ui/opengl_setup.hpp" +#include "gui/ui/user_interface_setup.hpp" #include "logging.hpp" #include "types.hpp" #include "world/climate.hpp" @@ -16,6 +19,8 @@ #include #include +#include + // create structure to pass game start data either from command line or from gui /* struct Options { @@ -245,6 +250,19 @@ intro_window(GLFWwindow* window) { GlobalContext& global_context = GlobalContext::instance(); // don't forget ot load ScreenData onto gpu + + // gui::the_buttons::UserInterface main_interface(temp_handler, 4); + // gui::setup(main_interface); + + auto main_interface = + std::make_shared(temp_handler, 4); + gui::setup(*main_interface); + + gui::scene::InputHandler::imgui_active = false; + gui::scene::InputHandler::set_window(window); + gui::scene::InputHandler::forward_inputs_to( + std::static_pointer_cast(main_interface) + ); global_context.run_opengl_queue(); while (!glfwWindowShouldClose(window)) { @@ -252,6 +270,8 @@ intro_window(GLFWwindow* window) { splash_screen_pipeline->render(display_w, display_h, 0); + main_interface->update(display_w, display_h); + glfwSwapBuffers(window); glfwPollEvents(); } diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index ecdc72fb..7e1538dc 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -50,7 +50,7 @@ class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { bool check_children(); // private: - //bool add_child(std::shared_ptr child_frame); + // bool add_child(std::shared_ptr child_frame); // might want to make it such that after a child has been added // nothing else can be added to it. diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index a309f57d..181ae4b7 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -39,7 +39,6 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s std::function render_setup = []() { // Draw over everything glDisable(GL_CULL_FACE); - // The sky has no depth glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); }; @@ -116,13 +115,17 @@ UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_pos auto x_offset = (*frame_outer)->get_x_position(); auto y_offset = (*frame_outer)->get_y_position(); + std::weak_ptr new_frame_outer = *frame_outer; std::weak_ptr frame_inner = (*frame_outer) ->get_child_at_position( mouse_position_x - x_offset, mouse_position_y - y_offset ); - std::weak_ptr new_frame_outer = *frame_outer; + // if there are no children then set to parent. + if (frame_inner.expired()) { + frame_inner = new_frame_outer; + } return std::make_pair, std::weak_ptr>( std::move(new_frame_outer), std::move(frame_inner) @@ -192,9 +195,11 @@ UserInterface::handle_mouse_button_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, [[maybe_unused]] int action, [[maybe_unused]] int mods ) { - reselect_frame(window); + if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS){ + reselect_frame(window); + } if (selected_frame_) { - handle_mouse_button_input(window, button, action, mods); + selected_frame_->handle_mouse_button_input(window, button, action, mods); } } diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index fecb45dc..2a15a7e5 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -31,7 +31,7 @@ class UserInterface : public virtual scene::Inputs { [[nodiscard]] inline std::pair, std::weak_ptr> get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) { - auto got_frames = get_frame(mouse_position_x, mouse_position_y); + auto got_frames = const_cast(this)->get_frame(mouse_position_x, mouse_position_y); return std::make_pair, std::weak_ptr>( std::const_pointer_cast(got_frames.first.lock()), std::const_pointer_cast(got_frames.second.lock()) diff --git a/src/gui/ui/imgui_gui.cpp b/src/gui/ui/imgui_gui.cpp index d940bc21..b1951bb5 100644 --- a/src/gui/ui/imgui_gui.cpp +++ b/src/gui/ui/imgui_gui.cpp @@ -86,8 +86,9 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { std::make_shared(key_mapping); scene::InputHandler::imgui_active = true; scene::InputHandler::set_window(window); - scene::InputHandler::forward_inputs_to(static_pointer_cast(controller - )); + scene::InputHandler::forward_inputs_to( + std::static_pointer_cast(controller) + ); // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index 05447b19..2f089706 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -25,7 +25,17 @@ setup(the_buttons::UserInterface& user_interface) { glm::ivec2(70, 70), glm::ivec2(230, 230) ); + std::shared_ptr a_second_window = + std::make_shared( + std::make_shared(image), + + glm::ivec2(200, 200), glm::ivec2(400, 600) + ); + + user_interface.add(a_window); + user_interface.add(a_second_window); + // window_pipeline->data.push_back(scene.a_window.get()); From 95b0ab779aacdee8c23a9e691309e17d057d8388 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 14 Dec 2025 22:03:34 -0500 Subject: [PATCH 15/56] fix bugs with clicking position --- src/gui/the_buttons/frame.cpp | 6 +++--- src/gui/the_buttons/user_interface.cpp | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/gui/the_buttons/frame.cpp b/src/gui/the_buttons/frame.cpp index dc90d2a6..bbd1ee4e 100644 --- a/src/gui/the_buttons/frame.cpp +++ b/src/gui/the_buttons/frame.cpp @@ -23,7 +23,7 @@ Frame::get_child_at_position(screen_size_t x, screen_size_t y) const { } } - LOG_WARNING(logging::main_logger, "Faailed to find frame."); + LOG_WARNING(logging::main_logger, "Failed to find frame."); return {}; } @@ -31,8 +31,8 @@ bool Frame::is_interior(screen_size_t x, screen_size_t y) const { const auto bounding_box = get_bounding_box(); if (x < bounding_box[0] || y < bounding_box[1] - || x > bounding_box[0] + bounding_box[2] - || y > bounding_box[1] + bounding_box[3]) { + || x > bounding_box[2] + || y > bounding_box[3]) { return false; } diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 181ae4b7..9a3fe73c 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -105,13 +105,20 @@ UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_pos const { // iterate from back to front auto frame_outer = frames_.end(); + // might be able to do this with control flow + bool found_frame_at_mouse_position = false; do { frame_outer--; if ((*frame_outer)->is_interior(mouse_position_x, mouse_position_y)) { + found_frame_at_mouse_position = true; break; } } while (frame_outer != frames_.begin()); + if (!found_frame_at_mouse_position) { + return {}; + } + auto x_offset = (*frame_outer)->get_x_position(); auto y_offset = (*frame_outer)->get_y_position(); @@ -138,11 +145,15 @@ UserInterface::reselect_frame(GLFWwindow* window) { double xpos; double ypos; glfwGetCursorPos(window, &xpos, &ypos); - auto selected_frames = get_frame(screen_size_t(xpos), screen_size_t(ypos)); + + screen_size_t height; + glfwGetFramebufferSize(window, nullptr, &height); + + auto selected_frames = get_frame(screen_size_t(floor(xpos)), screen_size_t(height - floor(ypos))); if (std::shared_ptr outer_frame = selected_frames.first.lock()) { // move to back - if (!outer_frame->is_fixed()) { + if (outer_frame != frames_.back() && !outer_frame->is_fixed()) { frames_.remove(outer_frame); frames_.push_back(outer_frame); } From cebf178b9349722053ad3cb6b9c46da7d1ec1699 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Mon, 15 Dec 2025 13:04:07 -0500 Subject: [PATCH 16/56] fix uniforms in fragment shader --- resources/shaders/overlay/FramedWindow.frag | 78 ++++++++++-------- .../graphics_shaders/program_handler.cpp | 9 ++- src/gui/render/structures/uniform_types.hpp | 80 ++++++++++++++++++- src/gui/the_buttons/user_interface.cpp | 17 +++- src/gui/the_buttons/user_interface.hpp | 3 + 5 files changed, 143 insertions(+), 44 deletions(-) diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag index 96980880..020686db 100644 --- a/resources/shaders/overlay/FramedWindow.frag +++ b/resources/shaders/overlay/FramedWindow.frag @@ -10,28 +10,36 @@ uniform usampler2D window_texture; uniform int ui_scale; // uniform +uniform ivec4 border_size; // done +uniform ivec4 side_lengths; +uniform ivec2 inner_pattern_size; +uniform ivec2 positions[9]; // doesn't work +// need four border sizes +// need for side lengths +// need size if inner pattern +// need 9 positions void main(){ - int border_size = 5; - - ivec2 position_1 = ivec2(0,0); - ivec2 position_2 = ivec2(5,0); - ivec2 position_3 = ivec2(6,0); - ivec2 position_4 = ivec2(0,5); - ivec2 position_5 = ivec2(5,5); - ivec2 position_6 = ivec2(6,5); - ivec2 position_7 = ivec2(0,6); - ivec2 position_8 = ivec2(5,6); - ivec2 position_9 = ivec2(6,6); - - int width_2 = 1; - int height_4 = 1; - int width_5 = 1; - int height_5 = 1; - int height_6 = 1; - int width_8 = 1; + //int border_size = 5; + + ivec2 position_1 = positions[0]; + ivec2 position_2 = positions[1]; + ivec2 position_3 = positions[2]; + ivec2 position_4 = positions[3]; + ivec2 position_5 = positions[4]; + ivec2 position_6 = positions[5]; + ivec2 position_7 = positions[6]; + ivec2 position_8 = positions[7]; + ivec2 position_9 = positions[8]; + + int width_2 = side_lengths[0]; + int height_4 = side_lengths[1]; + int width_5 = inner_pattern_size[0]; + int height_5 = inner_pattern_size[1]; + int height_6 = side_lengths[2]; + int width_8 = side_lengths[3]; ivec2 pixel_position = ivec2(int(UV.x), int(UV.y)); ivec2 ui_position = pixel_position / ui_scale; @@ -41,56 +49,60 @@ main(){ // ivec2 texture_position = ivec2(texture_locations[3], texture_locations[2]); - if (ui_position.y < border_size && ui_position.x < border_size) { // 1 + if (ui_position.y < border_size[1] && ui_position.x < border_size[0]) { // 1 ivec2 local_position = ivec2(ui_position.x, ui_position.y); texture_offset = local_position + position_1; } - else if (ui_position.y < border_size && frame_size_px.x - ui_position.x - 1 < border_size) { // 3 + else if (ui_position.y < border_size[1] && frame_size_px.x - ui_position.x - 1 < border_size[2]) { // 3 - ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size, ui_position.y); + ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size[2], ui_position.y); texture_offset = local_position + position_3; } - else if ((frame_size_px.y - ui_position.y - 1 < border_size) && ui_position.x < border_size) { // 7 - ivec2 local_position = ivec2(ui_position.x, ui_position.y - frame_size_px.y + border_size); + else if ((frame_size_px.y - ui_position.y - 1 < border_size[3]) && ui_position.x < border_size[0]) { // 7 + ivec2 local_position = ivec2(ui_position.x, ui_position.y - frame_size_px.y + border_size[3]); texture_offset = local_position + position_7; } - else if ((frame_size_px.y - ui_position.y - 1 < border_size) && (frame_size_px.x - ui_position.x - 1 < border_size)) { // 9 - ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size, ui_position.y - frame_size_px.y + border_size); + else if ((frame_size_px.y - ui_position.y - 1 < border_size[3]) && (frame_size_px.x - ui_position.x - 1 < border_size[2])) { // 9 + ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size[2], ui_position.y - frame_size_px.y + border_size[3]); texture_offset = local_position + position_9; } - else if (ui_position.x < border_size) { // 4 - ivec2 local_position = ivec2(ui_position.x, ui_position.y - border_size); + else if (ui_position.x < border_size[0]) { // 4 + ivec2 local_position = ivec2(ui_position.x, ui_position.y - border_size[1]); local_position.y = local_position.y % height_4; texture_offset = local_position + position_4; } - else if (ui_position.y < border_size) { // 2 + else if (ui_position.y < border_size[1]) { // 2 ivec2 local_position = ivec2(ui_position.x, ui_position.y); local_position.x = local_position.x % width_2; texture_offset = local_position + position_2; } - else if ((frame_size_px.x - ui_position.x) <= border_size) { // 6 + else if ((frame_size_px.x - ui_position.x) <= border_size[3]) { // 6 - ivec2 local_position = ivec2(border_size - frame_size_px.x + ui_position.x, ui_position.y - border_size); + ivec2 local_position = ivec2(border_size[2] - frame_size_px.x + ui_position.x, ui_position.y - border_size); local_position.y = local_position.y % height_6; texture_offset = local_position + position_6; } - else if ((frame_size_px.y - ui_position.y) <= border_size) { // 8 idk + else if ((frame_size_px.y - ui_position.y) <= border_size[3]) { // 8 idk - ivec2 local_position = ivec2(ui_position.x - border_size, frame_size_px.y - ui_position.y-1); + ivec2 local_position = ivec2(ui_position.x - border_size[2], frame_size_px.y - ui_position.y-1); local_position.x = local_position.x % width_8; texture_offset = local_position + position_2; } else { // 5 - texture_offset = position_5; + ivec2 local_position = ivec2(ui_position.x - border_size[0], ui_position.y - border_size[1]); + local_position.x = local_position.x % width_5; + local_position.y = local_position.y % height_5; + + texture_offset = position_5 + local_position; } uvec4 color_int = texelFetch(window_texture, texture_offset, 0); diff --git a/src/gui/render/graphics_shaders/program_handler.cpp b/src/gui/render/graphics_shaders/program_handler.cpp index dcd4235b..a04667db 100644 --- a/src/gui/render/graphics_shaders/program_handler.cpp +++ b/src/gui/render/graphics_shaders/program_handler.cpp @@ -227,7 +227,7 @@ Program::attach_uniforms() { LOG_INFO( logging::opengl_logger, "Uniform found with id: {}, name: {}, and type {}", - uid, name, gpu_data::to_string(enum_type) + uid, str_name, gpu_data::to_string(enum_type) ); if (length > buf_size - 4) { @@ -239,8 +239,8 @@ Program::attach_uniforms() { } uniforms_.emplace( - std::piecewise_construct, std::forward_as_tuple(name), - std::forward_as_tuple(name, enum_type, uid) + std::piecewise_construct, std::forward_as_tuple(str_name), + std::forward_as_tuple(str_name, enum_type, uid) ); } } @@ -268,6 +268,9 @@ Program::set_uniform(std::shared_ptr uex, std::string uniform_n "program \"{}\".", uniform_name, name_ ); + // do you mean... + // min less than 5 + // https://en.wikipedia.org/wiki/Levenshtein_distance } } diff --git a/src/gui/render/structures/uniform_types.hpp b/src/gui/render/structures/uniform_types.hpp index a8df3aea..f6844f15 100644 --- a/src/gui/render/structures/uniform_types.hpp +++ b/src/gui/render/structures/uniform_types.hpp @@ -379,15 +379,87 @@ class UIScaleUniform : public shader::UniformExecutor { } }; +class FrameBorderSizeUniform : public shader::UniformExecutor { + private: + glm::ivec4 border_size_; + + public: + FrameBorderSizeUniform() : UniformExecutor(gpu_data::GPUArayType::INT_VEC4) {} + + inline void + set_border_size(glm::ivec4 border_size) { + border_size_ = border_size; + } + + inline virtual ~FrameBorderSizeUniform() {} + + inline virtual void + bind(GLint uniform_ID) const override { + LOG_BACKTRACE( + logging::opengl_logger, "Uniform {} being initialized.", uniform_ID + ); + + glUniform4iv(uniform_ID, 1, &border_size_[0]); + } +}; + +class FrameSideLengthsUniform : public shader::UniformExecutor { + private: + glm::ivec4 side_length_; + + public: + FrameSideLengthsUniform() : UniformExecutor(gpu_data::GPUArayType::INT_VEC4) {} + + inline void + set_side_lengths(glm::ivec4 side_length) { + side_length_ = side_length; + } + + inline virtual ~FrameSideLengthsUniform() {} + + inline virtual void + bind(GLint uniform_ID) const override { + LOG_BACKTRACE( + logging::opengl_logger, "Uniform {} being initialized.", uniform_ID + ); + + glUniform4iv(uniform_ID, 1, &side_length_[0]); + } +}; + +class InnerPatternSizeUniform : public shader::UniformExecutor { + private: + glm::ivec2 pattern_size_; + + public: + InnerPatternSizeUniform() : UniformExecutor(gpu_data::GPUArayType::INT_VEC2) {} + + inline void + set_inner_pattern_size(glm::ivec2 pattern_size) { + pattern_size_ = pattern_size; + } + + inline virtual ~InnerPatternSizeUniform() {} + + inline virtual void + bind(GLint uniform_ID) const override { + LOG_BACKTRACE( + logging::opengl_logger, "Uniform {} being initialized.", uniform_ID + ); + + glUniform2iv(uniform_ID, 1, &pattern_size_[0]); + } +}; + class TextureRegionsUniform : public shader::UniformExecutor { private: - std::array texture_location_; + std::array texture_location_; public: - TextureRegionsUniform() : UniformExecutor(gpu_data::GPUArayType::INT) {} + TextureRegionsUniform() : UniformExecutor(gpu_data::GPUArayType::INT_VEC2) {} inline void - set_texture_regions(std::array texture_location) { + set_texture_regions(std::array texture_location) { texture_location_ = texture_location; } @@ -399,7 +471,7 @@ class TextureRegionsUniform : public shader::UniformExecutor { logging::opengl_logger, "Uniform {} being initialized.", uniform_ID ); - glUniform1iv(uniform_ID, 36, texture_location_.data()); + glUniform2iv(uniform_ID, 9, &(*texture_location_.data())[0]); } }; diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 9a3fe73c..37e9c55d 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -17,6 +17,9 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s frame_texture_uniform_(std::make_shared( gpu_data::GPUArayType::UNSIGNED_INT_SAMPLER_2D, 0 )), + border_sizes_(std::make_shared()), + side_lengths_(std::make_shared()), + inner_pattern_size_(std::make_shared()), texture_regions_(std::make_shared()) { shader::Program& window_render_program = shader_handler.load_program( "Windows", files::get_resources_path() / "shaders" / "overlay" / "Widget.vert", @@ -48,7 +51,10 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s window_render_program.set_uniform(frame_size_uniform_, "frame_size"); window_render_program.set_uniform(ui_scale_uniform_, "ui_scale"); window_render_program.set_uniform(frame_texture_uniform_, "window_texture"); - window_render_program.set_uniform(texture_regions_, "texture_locations"); + window_render_program.set_uniform(border_sizes_, "border_size"); + window_render_program.set_uniform(side_lengths_, "side_lengths"); + window_render_program.set_uniform(inner_pattern_size_, "inner_pattern_size"); + window_render_program.set_uniform(texture_regions_, "positions[0]"); // windows window_pipeline_ = std::make_shared( @@ -77,9 +83,12 @@ UserInterface::render_frame( return; } - texture_regions_->set_texture_regions({0, 0, 5, 5, 0, 5, 5, 1, 0, 6, 5, 1, - 5, 0, 1, 5, 5, 5, 1, 1, 6, 5, 5, 1, - 6, 0, 5, 5, 6, 5, 5, 1, 6, 6, 5, 5}); + border_sizes_->set_border_size(glm::ivec4(5,5,5,5)); + side_lengths_->set_side_lengths(glm::ivec4(1,1,1,1)); + inner_pattern_size_->set_inner_pattern_size(glm::ivec2(1,1)); + texture_regions_->set_texture_regions({glm::ivec2(0, 0), glm::ivec2(5, 0), glm::ivec2(6, 0), + glm::ivec2(0, 5), glm::ivec2(5, 5), glm::ivec2(6, 5), + glm::ivec2(0, 6), glm::ivec2(5, 6), glm::ivec2(6, 6)}); const auto bounding_box = frame.get_bounding_box(); // add offset diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 2a15a7e5..a9072a70 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -17,6 +17,9 @@ class UserInterface : public virtual scene::Inputs { std::shared_ptr frame_size_uniform_; std::shared_ptr ui_scale_uniform_; std::shared_ptr frame_texture_uniform_; + std::shared_ptr border_sizes_; + std::shared_ptr side_lengths_; + std::shared_ptr inner_pattern_size_; std::shared_ptr texture_regions_; // widget renderer From 483a50e23a5eee8a52fa83855adc9d1e99f7b6cc Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 19 Dec 2025 11:02:48 -0500 Subject: [PATCH 17/56] differentiate widget and frame --- src/gui/the_buttons/README.md | 25 ++++ src/gui/the_buttons/bordered_widget.hpp | 84 +++++++++++ src/gui/the_buttons/bordered_window.cpp | 2 +- src/gui/the_buttons/bordered_window.hpp | 2 +- src/gui/the_buttons/frame.cpp | 19 ++- src/gui/the_buttons/frame.hpp | 183 ++++++++++++++++++++--- src/gui/the_buttons/frame_part.cpp | 85 +++++++++++ src/gui/the_buttons/frame_part.hpp | 188 ++++++++++++++++++++++++ src/gui/the_buttons/user_interface.cpp | 95 ++++++++---- src/gui/the_buttons/user_interface.hpp | 31 ++-- src/gui/the_buttons/widget.hpp | 139 ++++++++++++++++++ src/gui/ui/user_interface_setup.cpp | 8 +- 12 files changed, 789 insertions(+), 72 deletions(-) create mode 100644 src/gui/the_buttons/bordered_widget.hpp create mode 100644 src/gui/the_buttons/frame_part.cpp create mode 100644 src/gui/the_buttons/frame_part.hpp create mode 100644 src/gui/the_buttons/widget.hpp diff --git a/src/gui/the_buttons/README.md b/src/gui/the_buttons/README.md index 2c9d7bab..28e4fa56 100644 --- a/src/gui/the_buttons/README.md +++ b/src/gui/the_buttons/README.md @@ -18,3 +18,28 @@ Intro screen - Settings - Pedia / License / Copyright + +# Child Parent Frame Relationship + +widgets have parents, but frames don't +widget value = frame.make(args); + +could this work? +probably. + +todo: + - frame + - widget adds parent? + +make frame and widget virtual class / interface classes + +could make widow base that widget and frame inherit from. +widget adds parent things +frame adds the ability to fixed + +don't render frames? +probably a good idea. +maybe not worth it +will needless add another level of rendering and pointer dereferencing. + + diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp new file mode 100644 index 00000000..dabe57ed --- /dev/null +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "bordered_widget.hpp" +#include "frame_part.hpp" +#include "gui/render/structures/window_texture.hpp" +#include "widget.hpp" + +#include + +namespace gui { + +namespace the_buttons { + +class BorderedWidget : public virtual WidgetBase { + private: + std::shared_ptr data_; + + public: + BorderedWidget() = delete; + /** + * @brief Deleted copy constructor + */ + BorderedWidget(const BorderedWidget& obj) = delete; + + /** + * @brief Deleted copy operator + */ + BorderedWidget& operator=(const BorderedWidget& obj) = delete; + + /** + * @brief Default move constructor + */ + BorderedWidget(BorderedWidget&& obj) = default; + + /** + * @brief Default move constructor + */ + BorderedWidget& operator=(BorderedWidget&& obj) = default; + + BorderedWidget( + FrameInterface* parent, std::shared_ptr data, + glm::ivec2 position, glm::ivec2 widget_size + ) : + WidgetBase( + parent, position, widget_size, + {position, glm::ivec2(position.x + widget_size.x, position.y), + position + widget_size, glm::ivec2(position.x, position.y + widget_size.y)} + ), + // Frame( + // position, widget_size, + // {position, glm::ivec2(position.x + widget_size.x, position.y), + // position + widget_size, + // glm::ivec2(position.x, position.y + widget_size.y)}, + // false + // ) + + data_(data) {} + + inline virtual ~BorderedWidget(){}; + + inline unsigned int + get_num_vertices() const { + return data_->get_num_vertices(); + } + + inline virtual void + bind() const { + data_->bind(); + }; + + inline virtual void + release() const { + data_->release(); + } + + inline virtual bool + do_render() const { + return data_->do_render(); + }; +}; + +} // namespace the_buttons + +} // namespace gui \ No newline at end of file diff --git a/src/gui/the_buttons/bordered_window.cpp b/src/gui/the_buttons/bordered_window.cpp index 21360373..1d92c560 100644 --- a/src/gui/the_buttons/bordered_window.cpp +++ b/src/gui/the_buttons/bordered_window.cpp @@ -8,7 +8,7 @@ BorderedWindow::BorderedWindow( std::shared_ptr data, glm::ivec2 position, glm::ivec2 frame_size ) : - Frame( + FrameBase( position, frame_size, {position, glm::ivec2(position.x + frame_size.x, position.y), position + frame_size, glm::ivec2(position.x, position.y + frame_size.y)} diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp index 99c6f460..99ca51eb 100644 --- a/src/gui/the_buttons/bordered_window.hpp +++ b/src/gui/the_buttons/bordered_window.hpp @@ -9,7 +9,7 @@ namespace gui { namespace the_buttons { -class BorderedWindow : public virtual Frame { +class BorderedWindow : public virtual FrameBase { private: std::shared_ptr data_; diff --git a/src/gui/the_buttons/frame.cpp b/src/gui/the_buttons/frame.cpp index bbd1ee4e..32564d65 100644 --- a/src/gui/the_buttons/frame.cpp +++ b/src/gui/the_buttons/frame.cpp @@ -2,6 +2,8 @@ #include "logging.hpp" #include "types.hpp" +#include "user_interface.hpp" +#include "widget.hpp" #include @@ -11,8 +13,8 @@ namespace gui { namespace the_buttons { -std::weak_ptr -Frame::get_child_at_position(screen_size_t x, screen_size_t y) const { +std::weak_ptr +FrameBase::get_child_at_position(screen_size_t x, screen_size_t y) const { for (const auto& child : children) { if (child->is_interior(x, y)) { if (child->has_children()) { @@ -28,10 +30,9 @@ Frame::get_child_at_position(screen_size_t x, screen_size_t y) const { } bool -Frame::is_interior(screen_size_t x, screen_size_t y) const { +FrameBase::is_interior(screen_size_t x, screen_size_t y) const { const auto bounding_box = get_bounding_box(); - if (x < bounding_box[0] || y < bounding_box[1] - || x > bounding_box[2] + if (x < bounding_box[0] || y < bounding_box[1] || x > bounding_box[2] || y > bounding_box[3]) { return false; } @@ -73,5 +74,13 @@ Frame::is_interior(screen_size_t x, screen_size_t y) const { return interior_flag; } +void +FrameBase::render_children(const UserInterface* user_interface /* need position*/) + const { + for (const auto& child : children) { + user_interface->render_frame(child, position_.x, position_.y); + } +} + } // namespace the_buttons } // namespace gui diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index 7e1538dc..f8dfd194 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -3,6 +3,7 @@ #include "../render/gpu_data/data_types.hpp" #include "gui/scene/input.hpp" #include "types.hpp" +#include "widget.hpp" #include #include @@ -12,45 +13,160 @@ namespace gui { namespace the_buttons { -class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { +class FrameInterface : public virtual WidgetInterface { + public: + inline virtual ~FrameInterface(){}; // kill children + + virtual bool is_fixed() const = 0; + + inline virtual bool is_visible() const = 0; + + virtual void on_select() = 0; + + virtual void on_end_select() = 0; + + virtual std::array get_bounding_box() const = 0; + + /** + * @brief Handle key input including mouse keys + * + * @param GLFWwindow* window window event came from + * @param int key GLFW key enum + * @param int scancode GLFW scancode enum + * @param int action GLFW action one of GLFW_PRESS, GLFW_RELEASE, GLFW_REPEAT + * @param int mods GLFW mods enum + */ + virtual void handle_key_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, + [[maybe_unused]] int scancode, [[maybe_unused]] int action, + [[maybe_unused]] int mods + ) = 0; + + /** + * @brief Handle text input + * + * @param GLFWwindow* window window to listen on + * @param unsigned int codepoint unicode 32 character. + */ + + virtual void handle_text_input_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] unsigned int codepoint + ) = 0; + + /** + * @brief Handle mouse movement events. + * + * @param GLFWwindow* window window to listen on + * @param double xpos x position in window coordinates + * @param double ypos y position in window coordinates. + */ + virtual void handle_mouse_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xpos, + [[maybe_unused]] double ypos + ) = 0; + + /** + * @brief Handle mouse enter window events + * + * @param GLFWwindow* window window to listen on + * @param int button + * @param int action + * @param int mods + */ + virtual void handle_mouse_button_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, + [[maybe_unused]] int action, [[maybe_unused]] int mods + ) = 0; + + /** + * @brief Handle mouse scroll events + * + * @param GLFWwindow* window window to listen on + * @param double xoffset x offset + * @param double yoffset y offset (usually 0) + */ + virtual void handle_mouse_scroll_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xoffset, + [[maybe_unused]] double yoffset + ) = 0; + + /** + * @brief Handle joystick event + * + * @param int jid joystick id + * @param int event + */ + virtual void + handle_joystick_input([[maybe_unused]] int jid, [[maybe_unused]] int event) = 0; + + /** + * @brief Handle file drop event + * + * @param GLFWwindow* window window to listen on + * @param int count number of files passed + * @param const char** paths file paths + */ + virtual void handle_file_drop_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int count, + [[maybe_unused]] const char** paths + ) = 0; + + /** + * @brief Handle all pooled inputs + * + * @param GLFWwindow* window window + */ + virtual void handle_pooled_inputs([[maybe_unused]] GLFWwindow* window) = 0; + + /** + * @brief Setup so this objects handles inputs correctly + * + * @param GLFWwindow* window window + */ + virtual void setup([[maybe_unused]] GLFWwindow* window) = 0; + + /** + * @brief Cleanup to original state + * + * @param GLFWwindow* window window + */ + virtual void cleanup([[maybe_unused]] GLFWwindow* window) = 0; +}; + +class FrameBase : public virtual FrameInterface { protected: glm::ivec2 position_; glm::ivec2 frame_size_; std::vector exterior_points_; - Frame* parent_; + // Frame* parent_; bool fixed_; // fixed position in render queue - std::unordered_set> children; - void exterior_changed(); // need to change exterior for parent. + std::unordered_set> children; bool is_selected; public: - Frame( + FrameBase( glm::ivec2 position, glm::ivec2 frame_size, - std::vector exterior_points, Frame* parent = nullptr, - bool fixed = false + std::vector exterior_points, bool fixed = false ) : position_(position), - frame_size_(frame_size), exterior_points_(exterior_points), parent_(parent), - fixed_(fixed){}; + frame_size_(frame_size), exterior_points_(exterior_points), fixed_(fixed){}; - inline virtual ~Frame(){}; // kill children + inline virtual ~FrameBase(){}; // kill children bool is_interior(screen_size_t x, screen_size_t y) const; - std::weak_ptr + std::weak_ptr get_child_at_position(screen_size_t x, screen_size_t y) const; - [[nodiscard]] inline bool - has_children() const { + [[nodiscard]] inline virtual bool + has_children() const override { return !children.empty(); } - bool check_children(); - - // private: - // bool add_child(std::shared_ptr child_frame); + // prevent overlapping children. + // bool check_children_positions(); // might want to make it such that after a child has been added // nothing else can be added to it. @@ -58,17 +174,21 @@ class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { // do this be checking if parent is set. // could also do the opposite and require that initialized with parent. - inline bool - is_fixed() const { + inline virtual bool + is_fixed() const override { return fixed_; } - bool is_visible(); + inline virtual bool + is_visible() const override { + return true; + } - void on_select(); + inline virtual void on_select() override{}; - void on_end_select(); - virtual std::array get_bounding_box() const = 0; + inline virtual void on_end_select() override{}; + + virtual void render_children(const UserInterface* user_interface) const; [[nodiscard]] inline screen_size_t get_x_position() const { @@ -80,6 +200,23 @@ class Frame : public virtual scene::Inputs, public virtual gpu_data::GPUData { return position_.y; } + inline virtual std::array + get_bounding_box() const { + return {position_.x, position_.y, frame_size_.x, frame_size_.y}; + } + + template + [[nodiscard]] inline std::shared_ptr + make(Args&&... args) { + auto new_widget = children.emplace(std::make_shared(this, args...)); + if (new_widget.second) { + if (auto new_widget_ptr = std::dynamic_pointer_cast(*new_widget.first)) { + return new_widget_ptr; + } + } + return nullptr; + } + [[nodiscard]] inline auto begin() const { return children.begin(); diff --git a/src/gui/the_buttons/frame_part.cpp b/src/gui/the_buttons/frame_part.cpp new file mode 100644 index 00000000..a70e390f --- /dev/null +++ b/src/gui/the_buttons/frame_part.cpp @@ -0,0 +1,85 @@ +#include "frame_part.hpp" + +#include "user_interface.hpp" + +namespace gui { + +namespace the_buttons { + +bool +WidgetBase::is_interior(screen_size_t x, screen_size_t y) const { + const auto bounding_box = get_bounding_box(); + if (x < bounding_box[0] || y < bounding_box[1] || x > bounding_box[2] + || y > bounding_box[3]) { + return false; + } + + //clang-format off + /* + * (previous_position) + * * + * * (current position) + * x + * (x, y) + * |----|--------------| + * w1 w2 + * + * w2 * previous_position.y + w1 * current_position.y + * y_line = ------------------------------------------------------ + * w1 + w2 + * + * If there are an odd number of lines above the position then it is on the + * interior. + */ + //clang-format on + + bool interior_flag = false; + glm::ivec2 previous_position = exterior_points_.back(); + + for (const auto& current_position : exterior_points_) { + int x_weight_1 = std::abs(previous_position.x - x); + int x_weight_2 = std::abs(current_position.x - x); + + if (y * (x_weight_1 + x_weight_2) + > previous_position.y * x_weight_2 + current_position.y * x_weight_1) { + interior_flag = !interior_flag; + } + + previous_position = current_position; + } + + return interior_flag; +} + +void +WidgetBase::render_children(const UserInterface* user_interface /* need position*/) + const { + for (const auto& child : children) { + user_interface->render_frame(child, position_.x, position_.y); + } +} + +bool +WidgetBase::has_children() const { + return !children.empty(); +} + +std::weak_ptr +WidgetBase::get_child_at_position(screen_size_t x, screen_size_t y) const { + for (const auto& child : children) { + if (child->is_interior(x, y)) { + if (child->has_children()) { + return child->get_child_at_position(x - position_.x, y - position_.y); + } else { + return child; + } + } + } + + LOG_WARNING(logging::main_logger, "Failed to find frame."); + return {}; +} + +} // namespace the_buttons + +} // namespace gui diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp new file mode 100644 index 00000000..eaab9243 --- /dev/null +++ b/src/gui/the_buttons/frame_part.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include "types.hpp" +#include "widget.hpp" + +#include +#include + +namespace gui { + +namespace the_buttons { + +class WidgetBase : public virtual WidgetInterface { + protected: + WidgetInterface* parent_; + glm::ivec2 position_; + glm::ivec2 frame_size_; + std::vector exterior_points_; + + std::unordered_set> children; + void exterior_changed(); // need to change exterior for parent. + + bool is_selected; + + public: + WidgetBase( + WidgetInterface* parent, glm::ivec2 position, glm::ivec2 frame_size, + std::vector exterior_points + ) : + parent_(parent), + position_(position), frame_size_(frame_size), + exterior_points_(exterior_points){}; + + /** + * @brief Deleted copy constructor + */ + WidgetBase(const WidgetBase& obj) = delete; + + /** + * @brief Deleted copy operator + */ + WidgetBase& operator=(const WidgetBase& obj) = delete; + + /** + * @brief Default move constructor + */ + WidgetBase(WidgetBase&& obj) = default; + + /** + * @brief Default move constructor + */ + WidgetBase& operator=(WidgetBase&& obj) = default; + + template + [[nodiscard]] inline std::shared_ptr + make(Args&&... args) { + auto new_widget = children.emplace(std::make_shared(this, args...)); + if (new_widget.second) { + if (auto new_widget_ptr = std::dynamic_pointer_cast(*new_widget.first)) { + return new_widget_ptr; + } + } + return nullptr; + } + + virtual bool is_interior(screen_size_t x, screen_size_t y) const override; + + virtual void render_children(const UserInterface* user_interface) const override; + + [[nodiscard]] virtual bool has_children() const; + + virtual std::weak_ptr + get_child_at_position(screen_size_t x, screen_size_t y) const override; + + inline virtual std::array + get_bounding_box() const { + return {position_.x, position_.y, frame_size_.x, frame_size_.y}; + } + + /** + * @brief Handle key input including mouse keys + * + * @param GLFWwindow* window window event came from + * @param int key GLFW key enum + * @param int scancode GLFW scancode enum + * @param int action GLFW action one of GLFW_PRESS, GLFW_RELEASE, GLFW_REPEAT + * @param int mods GLFW mods enum + */ + virtual void handle_key_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, + [[maybe_unused]] int scancode, [[maybe_unused]] int action, + [[maybe_unused]] int mods + ){}; + + /** + * @brief Handle text input + * + * @param GLFWwindow* window window to listen on + * @param unsigned int codepoint unicode 32 character. + */ + + virtual void handle_text_input_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] unsigned int codepoint + ){}; + + /** + * @brief Handle mouse movement events. + * + * @param GLFWwindow* window window to listen on + * @param double xpos x position in window coordinates + * @param double ypos y position in window coordinates. + */ + virtual void handle_mouse_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xpos, + [[maybe_unused]] double ypos + ){}; + + /** + * @brief Handle mouse enter window events + * + * @param GLFWwindow* window window to listen on + * @param int button + * @param int action + * @param int mods + */ + virtual void handle_mouse_button_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, + [[maybe_unused]] int action, [[maybe_unused]] int mods + ){}; + + /** + * @brief Handle mouse scroll events + * + * @param GLFWwindow* window window to listen on + * @param double xoffset x offset + * @param double yoffset y offset (usually 0) + */ + virtual void handle_mouse_scroll_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xoffset, + [[maybe_unused]] double yoffset + ){}; + + /** + * @brief Handle joystick event + * + * @param int jid joystick id + * @param int event + */ + virtual void + handle_joystick_input([[maybe_unused]] int jid, [[maybe_unused]] int event){}; + + /** + * @brief Handle file drop event + * + * @param GLFWwindow* window window to listen on + * @param int count number of files passed + * @param const char** paths file paths + */ + virtual void handle_file_drop_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int count, + [[maybe_unused]] const char** paths + ){}; + + /** + * @brief Handle all pooled inputs + * + * @param GLFWwindow* window window + */ + virtual void handle_pooled_inputs([[maybe_unused]] GLFWwindow* window){}; + + /** + * @brief Setup so this objects handles inputs correctly + * + * @param GLFWwindow* window window + */ + virtual void setup([[maybe_unused]] GLFWwindow* window){}; + + /** + * @brief Cleanup to original state + * + * @param GLFWwindow* window window + */ + virtual void cleanup([[maybe_unused]] GLFWwindow* window){}; +}; + +} // namespace the_buttons + +} // namespace gui diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 37e9c55d..494e5044 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -6,6 +6,7 @@ #include "../render/graphics_shaders/shader_program.hpp" #include "../render/structures/uniform_types.hpp" #include "manifest/object_handler.hpp" +#include "widget.hpp" namespace gui { @@ -71,26 +72,35 @@ UserInterface::update(screen_size_t width, screen_size_t height) { glClear(GL_DEPTH_BUFFER_BIT); for (const auto& frame : frames_) { - render_frame(*frame, 0, 0); + render_frame(frame, 0, 0); } } +// maybe visitor pattern +// double dispatch on render frames +// render_border +// render_text +// render image +// etc void UserInterface::render_frame( - const Frame& frame, screen_size_t x_frame_position, screen_size_t y_frame_position + const std::shared_ptr frame, screen_size_t x_frame_position, + screen_size_t y_frame_position ) const { - if (!frame.do_render()) { + if (!frame->do_render()) { return; } - border_sizes_->set_border_size(glm::ivec4(5,5,5,5)); - side_lengths_->set_side_lengths(glm::ivec4(1,1,1,1)); - inner_pattern_size_->set_inner_pattern_size(glm::ivec2(1,1)); - texture_regions_->set_texture_regions({glm::ivec2(0, 0), glm::ivec2(5, 0), glm::ivec2(6, 0), - glm::ivec2(0, 5), glm::ivec2(5, 5), glm::ivec2(6, 5), - glm::ivec2(0, 6), glm::ivec2(5, 6), glm::ivec2(6, 6)}); + border_sizes_->set_border_size(glm::ivec4(5, 5, 5, 5)); + side_lengths_->set_side_lengths(glm::ivec4(1, 1, 1, 1)); + inner_pattern_size_->set_inner_pattern_size(glm::ivec2(1, 1)); + texture_regions_->set_texture_regions( + {glm::ivec2(0, 0), glm::ivec2(5, 0), glm::ivec2(6, 0), glm::ivec2(0, 5), + glm::ivec2(5, 5), glm::ivec2(6, 5), glm::ivec2(0, 6), glm::ivec2(5, 6), + glm::ivec2(6, 6)} + ); - const auto bounding_box = frame.get_bounding_box(); + const auto bounding_box = frame->get_bounding_box(); // add offset frame_size_uniform_->set_frame_size( glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) @@ -98,18 +108,41 @@ UserInterface::render_frame( window_pipeline_->render( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, - static_cast(&frame) + std::static_pointer_cast(frame).get() ); - for (const auto& frame_child : frame) { - render_frame( - *frame_child, frame_child->get_x_position() + x_frame_position, - frame_child->get_y_position() + y_frame_position - ); - } + frame->render_children(this /*add position*/); +} + +void +UserInterface::render_frame( + const std::shared_ptr widget, screen_size_t x_frame_position, + screen_size_t y_frame_position +) const { + border_sizes_->set_border_size(glm::ivec4(5, 5, 5, 5)); + side_lengths_->set_side_lengths(glm::ivec4(1, 1, 1, 1)); + inner_pattern_size_->set_inner_pattern_size(glm::ivec2(1, 1)); + texture_regions_->set_texture_regions( + {glm::ivec2(0, 0), glm::ivec2(5, 0), glm::ivec2(6, 0), glm::ivec2(0, 5), + glm::ivec2(5, 5), glm::ivec2(6, 5), glm::ivec2(0, 6), glm::ivec2(5, 6), + glm::ivec2(6, 6)} + ); + + const auto bounding_box = widget->get_bounding_box(); + // add offset + frame_size_uniform_->set_frame_size( + glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) + ); + window_pipeline_->render( + bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, + bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, + std::static_pointer_cast(widget).get() + ); + + widget->render_children(this /*add position*/); } -std::pair, std::weak_ptr> +std::pair, std::weak_ptr> UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const { // iterate from back to front @@ -128,22 +161,20 @@ UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_pos return {}; } - auto x_offset = (*frame_outer)->get_x_position(); - auto y_offset = (*frame_outer)->get_y_position(); + // auto x_offset = (*frame_outer)->get_x_position(); + // auto y_offset = (*frame_outer)->get_y_position(); - std::weak_ptr new_frame_outer = *frame_outer; - std::weak_ptr frame_inner = - (*frame_outer) - ->get_child_at_position( - mouse_position_x - x_offset, mouse_position_y - y_offset - ); + std::weak_ptr new_frame_outer = *frame_outer; + std::weak_ptr frame_inner = + (*frame_outer)->get_child_at_position(mouse_position_x, mouse_position_y); // if there are no children then set to parent. if (frame_inner.expired()) { frame_inner = new_frame_outer; } - return std::make_pair, std::weak_ptr>( + return std::make_pair< + std::weak_ptr, std::weak_ptr>( std::move(new_frame_outer), std::move(frame_inner) ); } @@ -158,9 +189,11 @@ UserInterface::reselect_frame(GLFWwindow* window) { screen_size_t height; glfwGetFramebufferSize(window, nullptr, &height); - auto selected_frames = get_frame(screen_size_t(floor(xpos)), screen_size_t(height - floor(ypos))); + auto selected_frames = + get_frame(screen_size_t(floor(xpos)), screen_size_t(height - floor(ypos))); - if (std::shared_ptr outer_frame = selected_frames.first.lock()) { + if (const std::shared_ptr outer_frame = + selected_frames.first.lock()) { // move to back if (outer_frame != frames_.back() && !outer_frame->is_fixed()) { frames_.remove(outer_frame); @@ -168,7 +201,7 @@ UserInterface::reselect_frame(GLFWwindow* window) { } } - if (std::shared_ptr inner_frame = selected_frames.second.lock()) { + if (std::shared_ptr inner_frame = selected_frames.second.lock()) { selected_frame_ = inner_frame; } else { selected_frame_ = nullptr; @@ -215,7 +248,7 @@ UserInterface::handle_mouse_button_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, [[maybe_unused]] int action, [[maybe_unused]] int mods ) { - if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS){ + if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) { reselect_frame(window); } if (selected_frame_) { diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index a9072a70..8c20c16f 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -25,19 +25,24 @@ class UserInterface : public virtual scene::Inputs { // widget renderer std::shared_ptr window_pipeline_; - std::list> frames_; + std::list> frames_; - std::shared_ptr selected_frame_; // widget? + std::shared_ptr selected_frame_; // widget? - [[nodiscard]] std::pair, std::weak_ptr> + [[nodiscard]] std::pair< + std::weak_ptr, std::weak_ptr> get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const; - [[nodiscard]] inline std::pair, std::weak_ptr> + [[nodiscard]] inline std::pair< + std::weak_ptr, std::weak_ptr> get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) { - auto got_frames = const_cast(this)->get_frame(mouse_position_x, mouse_position_y); - return std::make_pair, std::weak_ptr>( - std::const_pointer_cast(got_frames.first.lock()), - std::const_pointer_cast(got_frames.second.lock()) + auto got_frames = const_cast(this)->get_frame( + mouse_position_x, mouse_position_y + ); + return std::make_pair< + std::weak_ptr, std::weak_ptr>( + std::const_pointer_cast(got_frames.first.lock()), + std::const_pointer_cast(got_frames.second.lock()) ); } @@ -54,13 +59,19 @@ class UserInterface : public virtual scene::Inputs { } inline void - add(std::shared_ptr frame) { + add(std::shared_ptr frame) { auto pos = frames_.begin(); frames_.insert(pos, frame); } void render_frame( - const Frame& frame, screen_size_t x_frame_position, + const std::shared_ptr frame, screen_size_t x_frame_position, + screen_size_t y_frame_position + ) const; + + // one of these for each + void render_frame( + const std::shared_ptr widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; diff --git a/src/gui/the_buttons/widget.hpp b/src/gui/the_buttons/widget.hpp new file mode 100644 index 00000000..6b25cdc0 --- /dev/null +++ b/src/gui/the_buttons/widget.hpp @@ -0,0 +1,139 @@ +#pragma once + +// #include "frame.hpp" +#include "../render/gpu_data/data_types.hpp" +#include "../scene/input.hpp" + +namespace gui { + +namespace the_buttons { + +class UserInterface; + +class WidgetInterface : public virtual scene::Inputs, public virtual gpu_data::GPUData { + public: + inline virtual ~WidgetInterface(){}; // kill children + + virtual bool is_interior(screen_size_t x, screen_size_t y) const = 0; + + inline virtual void render_children(const UserInterface* user_interface) const = 0; + + virtual bool has_children() const = 0; + + virtual std::weak_ptr + get_child_at_position(screen_size_t x, screen_size_t y) const = 0; + + virtual std::array get_bounding_box() const = 0; + + /** + * @brief Handle key input including mouse keys + * + * @param GLFWwindow* window window event came from + * @param int key GLFW key enum + * @param int scancode GLFW scancode enum + * @param int action GLFW action one of GLFW_PRESS, GLFW_RELEASE, GLFW_REPEAT + * @param int mods GLFW mods enum + */ + virtual void handle_key_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, + [[maybe_unused]] int scancode, [[maybe_unused]] int action, + [[maybe_unused]] int mods + ) = 0; + + /** + * @brief Handle text input + * + * @param GLFWwindow* window window to listen on + * @param unsigned int codepoint unicode 32 character. + */ + + virtual void handle_text_input_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] unsigned int codepoint + ) = 0; + + /** + * @brief Handle mouse movement events. + * + * @param GLFWwindow* window window to listen on + * @param double xpos x position in window coordinates + * @param double ypos y position in window coordinates. + */ + virtual void handle_mouse_event_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xpos, + [[maybe_unused]] double ypos + ) = 0; + + /** + * @brief Handle mouse enter window events + * + * @param GLFWwindow* window window to listen on + * @param int button + * @param int action + * @param int mods + */ + virtual void handle_mouse_button_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, + [[maybe_unused]] int action, [[maybe_unused]] int mods + ) = 0; + + /** + * @brief Handle mouse scroll events + * + * @param GLFWwindow* window window to listen on + * @param double xoffset x offset + * @param double yoffset y offset (usually 0) + */ + virtual void handle_mouse_scroll_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xoffset, + [[maybe_unused]] double yoffset + ) = 0; + + /** + * @brief Handle joystick event + * + * @param int jid joystick id + * @param int event + */ + virtual void + handle_joystick_input([[maybe_unused]] int jid, [[maybe_unused]] int event) = 0; + + /** + * @brief Handle file drop event + * + * @param GLFWwindow* window window to listen on + * @param int count number of files passed + * @param const char** paths file paths + */ + virtual void handle_file_drop_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int count, + [[maybe_unused]] const char** paths + ) = 0; + + /** + * @brief Handle all pooled inputs + * + * @param GLFWwindow* window window + */ + virtual void handle_pooled_inputs([[maybe_unused]] GLFWwindow* window) = 0; + + /** + * @brief Setup so this objects handles inputs correctly + * + * @param GLFWwindow* window window + */ + virtual void setup([[maybe_unused]] GLFWwindow* window) = 0; + + /** + * @brief Cleanup to original state + * + * @param GLFWwindow* window window + */ + virtual void cleanup([[maybe_unused]] GLFWwindow* window) = 0; +}; + +template +concept widget_type = std::is_base_of::value; + +} // namespace the_buttons + +} // namespace gui diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index 2f089706..0148a825 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -1,5 +1,6 @@ #include "user_interface_setup.hpp" +#include "../the_buttons/bordered_widget.hpp" #include "../the_buttons/bordered_window.hpp" #include "../the_buttons/user_interface.hpp" #include "util/files.hpp" @@ -32,11 +33,16 @@ setup(the_buttons::UserInterface& user_interface) { glm::ivec2(200, 200), glm::ivec2(400, 600) ); + std::shared_ptr a_widget = + a_second_window->make( + std::make_shared(image), + + glm::ivec2(20, 20), glm::ivec2(180, 300) + ); user_interface.add(a_window); user_interface.add(a_second_window); - // window_pipeline->data.push_back(scene.a_window.get()); return; From a5c0242c805b327994e73032d63078ef3d5443fb Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 19 Dec 2025 12:38:10 -0500 Subject: [PATCH 18/56] fix widget rendering --- src/gui/the_buttons/bordered_widget.hpp | 4 +++- src/gui/the_buttons/frame.cpp | 10 +++++++--- src/gui/the_buttons/frame.hpp | 5 ++++- src/gui/the_buttons/frame_part.cpp | 10 +++++++--- src/gui/the_buttons/frame_part.hpp | 5 ++++- src/gui/the_buttons/user_interface.cpp | 4 ++-- src/gui/the_buttons/widget.hpp | 5 ++++- 7 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index dabe57ed..f8e022f2 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -54,7 +54,9 @@ class BorderedWidget : public virtual WidgetBase { // false // ) - data_(data) {} + data_(data) { + data_->update_position(get_bounding_box()); + } inline virtual ~BorderedWidget(){}; diff --git a/src/gui/the_buttons/frame.cpp b/src/gui/the_buttons/frame.cpp index 32564d65..4ba6e0be 100644 --- a/src/gui/the_buttons/frame.cpp +++ b/src/gui/the_buttons/frame.cpp @@ -75,10 +75,14 @@ FrameBase::is_interior(screen_size_t x, screen_size_t y) const { } void -FrameBase::render_children(const UserInterface* user_interface /* need position*/) - const { +FrameBase::render_children( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position +) const { for (const auto& child : children) { - user_interface->render_frame(child, position_.x, position_.y); + user_interface->render_frame( + child, x_position + position_.x, y_position + position_.y + ); } } diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index f8dfd194..0cbe442c 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -188,7 +188,10 @@ class FrameBase : public virtual FrameInterface { inline virtual void on_end_select() override{}; - virtual void render_children(const UserInterface* user_interface) const; + virtual void render_children( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position + ) const; [[nodiscard]] inline screen_size_t get_x_position() const { diff --git a/src/gui/the_buttons/frame_part.cpp b/src/gui/the_buttons/frame_part.cpp index a70e390f..5faa75d9 100644 --- a/src/gui/the_buttons/frame_part.cpp +++ b/src/gui/the_buttons/frame_part.cpp @@ -52,10 +52,14 @@ WidgetBase::is_interior(screen_size_t x, screen_size_t y) const { } void -WidgetBase::render_children(const UserInterface* user_interface /* need position*/) - const { +WidgetBase::render_children( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position +) const { for (const auto& child : children) { - user_interface->render_frame(child, position_.x, position_.y); + user_interface->render_frame( + child, x_position + position_.x, y_position + position_.y + ); } } diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index eaab9243..bf748223 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -65,7 +65,10 @@ class WidgetBase : public virtual WidgetInterface { virtual bool is_interior(screen_size_t x, screen_size_t y) const override; - virtual void render_children(const UserInterface* user_interface) const override; + virtual void render_children( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position + ) const override; [[nodiscard]] virtual bool has_children() const; diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 494e5044..257b94d1 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -111,7 +111,7 @@ UserInterface::render_frame( std::static_pointer_cast(frame).get() ); - frame->render_children(this /*add position*/); + frame->render_children(this, x_frame_position, y_frame_position); } void @@ -139,7 +139,7 @@ UserInterface::render_frame( std::static_pointer_cast(widget).get() ); - widget->render_children(this /*add position*/); + widget->render_children(this, x_frame_position, y_frame_position); } std::pair, std::weak_ptr> diff --git a/src/gui/the_buttons/widget.hpp b/src/gui/the_buttons/widget.hpp index 6b25cdc0..b468e5a3 100644 --- a/src/gui/the_buttons/widget.hpp +++ b/src/gui/the_buttons/widget.hpp @@ -16,7 +16,10 @@ class WidgetInterface : public virtual scene::Inputs, public virtual gpu_data::G virtual bool is_interior(screen_size_t x, screen_size_t y) const = 0; - inline virtual void render_children(const UserInterface* user_interface) const = 0; + inline virtual void render_children( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position + ) const = 0; virtual bool has_children() const = 0; From 28742f51e500e365f84583e09614346b749fc846 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 19 Dec 2025 18:03:26 -0500 Subject: [PATCH 19/56] change to visitor pattern --- src/gui/the_buttons/bordered_widget.hpp | 37 +++++++++++++++++++++++++ src/gui/the_buttons/bordered_window.cpp | 16 +++++++++++ src/gui/the_buttons/bordered_window.hpp | 5 ++++ src/gui/the_buttons/frame.cpp | 22 +++++++-------- src/gui/the_buttons/frame.hpp | 8 +++--- src/gui/the_buttons/frame_part.cpp | 12 -------- src/gui/the_buttons/frame_part.hpp | 8 +++--- src/gui/the_buttons/user_interface.cpp | 31 ++++++++++----------- src/gui/the_buttons/user_interface.hpp | 7 +++-- src/gui/the_buttons/widget.hpp | 7 ++++- 10 files changed, 102 insertions(+), 51 deletions(-) diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index f8e022f2..0a2e7115 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -3,6 +3,7 @@ #include "bordered_widget.hpp" #include "frame_part.hpp" #include "gui/render/structures/window_texture.hpp" +#include "types.hpp" #include "widget.hpp" #include @@ -79,6 +80,42 @@ class BorderedWidget : public virtual WidgetBase { do_render() const { return data_->do_render(); }; + + inline void + user_interface_render( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position + ) const override { + user_interface->render_frame(this, x_position, y_position); + + for (const auto& child : children) { + child->user_interface_render( + user_interface, x_position + position_.x, y_position + position_.y + ); + } + } + + [[nodiscard]] inline virtual glm::ivec4 + get_border_size() const { + return {5, 5, 5, 5}; + } + + [[nodiscard]] inline virtual glm::ivec4 + get_side_lengths() const { + return {1, 1, 1, 1}; + } + + [[nodiscard]] inline virtual glm::ivec2 + get_inner_pattern_size() const { + return {1, 1}; + } + + [[nodiscard]] inline virtual std::array + get_texture_regions() const { + return {glm::ivec2(0, 0), glm::ivec2(5, 0), glm::ivec2(6, 0), + glm::ivec2(0, 5), glm::ivec2(5, 5), glm::ivec2(6, 5), + glm::ivec2(0, 6), glm::ivec2(5, 6), glm::ivec2(6, 6)}; + } }; } // namespace the_buttons diff --git a/src/gui/the_buttons/bordered_window.cpp b/src/gui/the_buttons/bordered_window.cpp index 1d92c560..ad29dac7 100644 --- a/src/gui/the_buttons/bordered_window.cpp +++ b/src/gui/the_buttons/bordered_window.cpp @@ -1,5 +1,7 @@ #include "bordered_window.hpp" +#include "user_interface.hpp" + namespace gui { namespace the_buttons { @@ -17,5 +19,19 @@ BorderedWindow::BorderedWindow( data_->update_position(get_bounding_box()); } +void +BorderedWindow::user_interface_render( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position +) const { + user_interface->render_frame(this, x_position, y_position); + + for (const auto& child : children) { + child->user_interface_render( + user_interface, x_position + position_.x, y_position + position_.y + ); + } +} + } // namespace the_buttons } // namespace gui diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp index 99ca51eb..5cb5569f 100644 --- a/src/gui/the_buttons/bordered_window.hpp +++ b/src/gui/the_buttons/bordered_window.hpp @@ -66,6 +66,11 @@ class BorderedWindow : public virtual FrameBase { get_bounding_box() const { return {position_.x, position_.y, frame_size_.x, frame_size_.y}; } + + virtual void user_interface_render( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position + ) const override; }; } // namespace the_buttons diff --git a/src/gui/the_buttons/frame.cpp b/src/gui/the_buttons/frame.cpp index 4ba6e0be..3ae0c1e7 100644 --- a/src/gui/the_buttons/frame.cpp +++ b/src/gui/the_buttons/frame.cpp @@ -74,17 +74,17 @@ FrameBase::is_interior(screen_size_t x, screen_size_t y) const { return interior_flag; } -void -FrameBase::render_children( - const UserInterface* user_interface, screen_size_t x_position, - screen_size_t y_position -) const { - for (const auto& child : children) { - user_interface->render_frame( - child, x_position + position_.x, y_position + position_.y - ); - } -} +// void +// FrameBase::render_children( +// const UserInterface* user_interface, screen_size_t x_position, +// screen_size_t y_position +// ) const { +// for (const auto& child : children) { +// user_interface->render_frame( +// child, x_position + position_.x, y_position + position_.y +// ); +// } +// } } // namespace the_buttons } // namespace gui diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index 0cbe442c..c6ca1dc2 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -188,10 +188,10 @@ class FrameBase : public virtual FrameInterface { inline virtual void on_end_select() override{}; - virtual void render_children( - const UserInterface* user_interface, screen_size_t x_position, - screen_size_t y_position - ) const; + // virtual void render_children( + // const UserInterface* user_interface, screen_size_t x_position, + // screen_size_t y_position + // ) const; [[nodiscard]] inline screen_size_t get_x_position() const { diff --git a/src/gui/the_buttons/frame_part.cpp b/src/gui/the_buttons/frame_part.cpp index 5faa75d9..5931bef9 100644 --- a/src/gui/the_buttons/frame_part.cpp +++ b/src/gui/the_buttons/frame_part.cpp @@ -51,18 +51,6 @@ WidgetBase::is_interior(screen_size_t x, screen_size_t y) const { return interior_flag; } -void -WidgetBase::render_children( - const UserInterface* user_interface, screen_size_t x_position, - screen_size_t y_position -) const { - for (const auto& child : children) { - user_interface->render_frame( - child, x_position + position_.x, y_position + position_.y - ); - } -} - bool WidgetBase::has_children() const { return !children.empty(); diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index bf748223..b92f7803 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -65,10 +65,10 @@ class WidgetBase : public virtual WidgetInterface { virtual bool is_interior(screen_size_t x, screen_size_t y) const override; - virtual void render_children( - const UserInterface* user_interface, screen_size_t x_position, - screen_size_t y_position - ) const override; + // virtual void user_interface_render( + // const UserInterface* user_interface, screen_size_t x_position, + // screen_size_t y_position + // ) const override; [[nodiscard]] virtual bool has_children() const; diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 257b94d1..00f5257c 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -5,6 +5,8 @@ #include "../render/graphics_shaders/program_handler.hpp" #include "../render/graphics_shaders/shader_program.hpp" #include "../render/structures/uniform_types.hpp" +#include "bordered_widget.hpp" +#include "bordered_window.hpp" #include "manifest/object_handler.hpp" #include "widget.hpp" @@ -72,7 +74,7 @@ UserInterface::update(screen_size_t width, screen_size_t height) { glClear(GL_DEPTH_BUFFER_BIT); for (const auto& frame : frames_) { - render_frame(frame, 0, 0); + frame->user_interface_render(this, 0, 0); } } @@ -84,7 +86,7 @@ UserInterface::update(screen_size_t width, screen_size_t height) { // etc void UserInterface::render_frame( - const std::shared_ptr frame, screen_size_t x_frame_position, + const BorderedWindow* frame, screen_size_t x_frame_position, screen_size_t y_frame_position ) const { if (!frame->do_render()) { @@ -107,26 +109,22 @@ UserInterface::render_frame( ); window_pipeline_->render( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, - bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, - std::static_pointer_cast(frame).get() + bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, frame ); - frame->render_children(this, x_frame_position, y_frame_position); + // frame->render_children(this, x_frame_position, y_frame_position); } void UserInterface::render_frame( - const std::shared_ptr widget, screen_size_t x_frame_position, + const BorderedWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const { - border_sizes_->set_border_size(glm::ivec4(5, 5, 5, 5)); - side_lengths_->set_side_lengths(glm::ivec4(1, 1, 1, 1)); - inner_pattern_size_->set_inner_pattern_size(glm::ivec2(1, 1)); - texture_regions_->set_texture_regions( - {glm::ivec2(0, 0), glm::ivec2(5, 0), glm::ivec2(6, 0), glm::ivec2(0, 5), - glm::ivec2(5, 5), glm::ivec2(6, 5), glm::ivec2(0, 6), glm::ivec2(5, 6), - glm::ivec2(6, 6)} - ); + // TODO + border_sizes_->set_border_size(widget->get_border_size()); + side_lengths_->set_side_lengths(widget->get_side_lengths()); + inner_pattern_size_->set_inner_pattern_size(widget->get_inner_pattern_size()); + texture_regions_->set_texture_regions(widget->get_texture_regions()); const auto bounding_box = widget->get_bounding_box(); // add offset @@ -135,11 +133,10 @@ UserInterface::render_frame( ); window_pipeline_->render( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, - bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, - std::static_pointer_cast(widget).get() + bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, widget ); - widget->render_children(this, x_frame_position, y_frame_position); + // widget->render_children(this, x_frame_position, y_frame_position); } std::pair, std::weak_ptr> diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 8c20c16f..db220ab9 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -11,6 +11,9 @@ namespace gui { namespace the_buttons { +class BorderedWidget; +class BorderedWindow; + class UserInterface : public virtual scene::Inputs { private: // uniform @@ -65,13 +68,13 @@ class UserInterface : public virtual scene::Inputs { } void render_frame( - const std::shared_ptr frame, screen_size_t x_frame_position, + const BorderedWindow* frame, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; // one of these for each void render_frame( - const std::shared_ptr widget, screen_size_t x_frame_position, + const BorderedWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; diff --git a/src/gui/the_buttons/widget.hpp b/src/gui/the_buttons/widget.hpp index b468e5a3..1f8737a4 100644 --- a/src/gui/the_buttons/widget.hpp +++ b/src/gui/the_buttons/widget.hpp @@ -16,11 +16,16 @@ class WidgetInterface : public virtual scene::Inputs, public virtual gpu_data::G virtual bool is_interior(screen_size_t x, screen_size_t y) const = 0; - inline virtual void render_children( + virtual void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position ) const = 0; + // inline virtual void render_children( + // const UserInterface* user_interface, screen_size_t x_position, + // screen_size_t y_position + // ) const = 0; + virtual bool has_children() const = 0; virtual std::weak_ptr From a95b817a657025ecaf48653db6218d6f779038b3 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 21 Dec 2025 14:58:19 -0500 Subject: [PATCH 20/56] load texture from file --- resources/textures/GenericBorder.json | 9 ++ resources/textures/GenericBorder_2.json | 11 +++ src/gui/render/structures/window_texture.cpp | 16 +++- src/gui/render/structures/window_texture.hpp | 98 +++++++++++++++++++- src/gui/the_buttons/README.md | 31 ++----- src/gui/the_buttons/bordered_widget.hpp | 17 +--- src/gui/ui/user_interface_setup.cpp | 37 +++++++- 7 files changed, 176 insertions(+), 43 deletions(-) create mode 100644 resources/textures/GenericBorder.json create mode 100644 resources/textures/GenericBorder_2.json diff --git a/resources/textures/GenericBorder.json b/resources/textures/GenericBorder.json new file mode 100644 index 00000000..0b043593 --- /dev/null +++ b/resources/textures/GenericBorder.json @@ -0,0 +1,9 @@ +{ + "texture_file" : "./GenericBorder.png", +"border_size" : [5,5,5,5], +"side_lengths" : [1,1,1,1], +"inner_pattern_size" : [1,1], +"texture_regions" : [[0, 0], [5, 0], [6, 0], + [0, 5], [5, 5], [6, 5], + [0, 6], [5, 6], [6, 6]] +} \ No newline at end of file diff --git a/resources/textures/GenericBorder_2.json b/resources/textures/GenericBorder_2.json new file mode 100644 index 00000000..ba59e8fc --- /dev/null +++ b/resources/textures/GenericBorder_2.json @@ -0,0 +1,11 @@ +{ + "texture_file" : "./GenericBorder_2.png", + "border_size" : [7,7,7,7], + "side_lengths" : [10,10,10,10], + "inner_pattern_size" : [10,10], + "texture_regions" : [ + [0, 0], [6, 0], [15, 0], + [0, 6], [6, 6], [15, 6], + [0, 15], [7, 15], [15, 15] + ] +} \ No newline at end of file diff --git a/src/gui/render/structures/window_texture.cpp b/src/gui/render/structures/window_texture.cpp index e12c4b88..6630f6e7 100644 --- a/src/gui/render/structures/window_texture.cpp +++ b/src/gui/render/structures/window_texture.cpp @@ -12,7 +12,11 @@ namespace gui { namespace render { -WindowTexture::WindowTexture(std::shared_ptr image) : +WindowTexture::WindowTexture( + std::shared_ptr image, glm::ivec4 border_size, + glm::ivec4 side_lengths, glm::ivec2 inner_pattern_size, + std::array texture_regions +) : // clang-format off gl_positions_{ glm::vec3(-1, -1, 0), @@ -35,7 +39,9 @@ WindowTexture::WindowTexture(std::shared_ptr image) : .type = gui::gpu_data::GPUPixelType::UNSIGNED_BYTE, .min_filter = GL_NEAREST, .mag_filter = GL_NEAREST} - ) { + ), + border_size_(border_size), side_lengths_(side_lengths), + inner_pattern_size_(inner_pattern_size), texture_regions_(texture_regions) { LOG_DEBUG(logging::main_logger, "Initializing a WindowTexture"); GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { @@ -46,6 +52,12 @@ WindowTexture::WindowTexture(std::shared_ptr image) : }); } +WindowTexture::WindowTexture(std::shared_ptr image,const window_texture_data_t& texture_data) : + WindowTexture( + image, texture_data.border_size, + texture_data.side_lengths, texture_data.inner_pattern_size, texture_data.texture_regions + ) {} + } // namespace render } // namespace gui diff --git a/src/gui/render/structures/window_texture.hpp b/src/gui/render/structures/window_texture.hpp index 03bbd7a1..1e8af2f8 100644 --- a/src/gui/render/structures/window_texture.hpp +++ b/src/gui/render/structures/window_texture.hpp @@ -7,14 +7,70 @@ #include "screen_data.hpp" #include "util/image.hpp" +#include + +#include #include namespace gui { + namespace render { -// gpu_data::Texture2D texture; +struct window_texture_data_t { + std::filesystem::path texture_file; + glm::ivec4 border_size; + glm::ivec4 side_lengths; + glm::ivec2 inner_pattern_size; + std::array texture_regions; + + inline std::array border_size_write() { + return {border_size[0], border_size[1],border_size[2],border_size[3]}; + } + + inline void border_size_read(std::array border_size_in) { + border_size = glm::ivec4(border_size_in[0], border_size_in[1],border_size_in[2],border_size_in[3]); + } + + inline std::array side_lengths_write() { + return {side_lengths[0], side_lengths[1],side_lengths[2],side_lengths[3]}; + } -// std::array sub_texture_locations; + inline void side_lengths_read(std::array side_lengths_in) { + side_lengths = glm::ivec4(side_lengths_in[0], side_lengths_in[1],side_lengths_in[2],side_lengths_in[3]); + } + + inline std::array inner_pattern_size_write() { + return {inner_pattern_size[0], inner_pattern_size[1]}; + } + + inline void inner_pattern_size_read(std::array inner_pattern_size_in) { + inner_pattern_size = glm::ivec2(inner_pattern_size_in[0], inner_pattern_size_in[1]); + } + + inline std::array, 9> texture_regions_write() { + return {std::array({texture_regions[0].x, texture_regions[0].y}), + std::array({texture_regions[1].x, texture_regions[1].y}), + std::array({texture_regions[2].x, texture_regions[2].y}), + std::array({texture_regions[3].x, texture_regions[3].y}), + std::array({texture_regions[4].x, texture_regions[4].y}), + std::array({texture_regions[5].x, texture_regions[5].y}), + std::array({texture_regions[6].x, texture_regions[6].y}), + std::array({texture_regions[7].x, texture_regions[7].y}), + std::array({texture_regions[8].x, texture_regions[8].y})}; + } + + inline void texture_regions_read(std::array, 9> texture_regions_in) { + texture_regions = std::array({glm::ivec2(texture_regions_in[0][0], texture_regions_in[0][1]), + glm::ivec2(texture_regions_in[1][0], texture_regions_in[1][1]), + glm::ivec2(texture_regions_in[2][0], texture_regions_in[2][1]), + glm::ivec2(texture_regions_in[3][0], texture_regions_in[3][1]), + glm::ivec2(texture_regions_in[4][0], texture_regions_in[4][1]), + glm::ivec2(texture_regions_in[5][0], texture_regions_in[5][1]), + glm::ivec2(texture_regions_in[6][0], texture_regions_in[6][1]), + glm::ivec2(texture_regions_in[7][0], texture_regions_in[7][1]), + glm::ivec2(texture_regions_in[8][0], texture_regions_in[8][1])}); + } +}; class WindowTexture : public virtual gpu_data::GPUData { private: @@ -27,6 +83,11 @@ class WindowTexture : public virtual gpu_data::GPUData { gpu_data::Texture2D border_texture_; + glm::ivec4 border_size_; + glm::ivec4 side_lengths_; + glm::ivec2 inner_pattern_size_; + std::array texture_regions_; + public: /** * @brief Deleted copy constructor @@ -52,7 +113,13 @@ class WindowTexture : public virtual gpu_data::GPUData { * @brief Construct a new Screen Data object, default constructor * */ - WindowTexture(std::shared_ptr image); + WindowTexture( + std::shared_ptr image, glm::ivec4 border_size, + glm::ivec4 side_lengths, glm::ivec2 inner_pattern_size, + std::array texture_regions + ); + + WindowTexture(std::shared_ptr image, const window_texture_data_t& texture_data); inline virtual ~WindowTexture() {} @@ -66,6 +133,19 @@ class WindowTexture : public virtual gpu_data::GPUData { return num_vertices_; } + [[nodiscard]] inline auto get_border_size() const { + return border_size_; + } + [[nodiscard]] inline auto get_side_lengths() const { + return side_lengths_; + } + [[nodiscard]] inline auto get_inner_pattern_size() const { + return inner_pattern_size_; + } + [[nodiscard]] inline auto get_texture_regions() const { + return texture_regions_; + } + inline virtual void bind() const { vertex_array_object_.bind(); @@ -99,3 +179,15 @@ class WindowTexture : public virtual gpu_data::GPUData { } // namespace render } // namespace gui + +template <> +struct glz::meta { + using T = gui::render::window_texture_data_t; + + static constexpr auto value = object("texture_file", &T::texture_file, + "border_size", custom<&T::border_size_read, &T::border_size_write>, + "side_lengths", custom<&T::side_lengths_read, &T::side_lengths_write>, + "inner_pattern_size", custom<&T::inner_pattern_size_read, &T::inner_pattern_size_write>, + "texture_regions", custom<&T::texture_regions_read, &T::texture_regions_write>); +}; + diff --git a/src/gui/the_buttons/README.md b/src/gui/the_buttons/README.md index 28e4fa56..ea1c35d1 100644 --- a/src/gui/the_buttons/README.md +++ b/src/gui/the_buttons/README.md @@ -21,25 +21,14 @@ Intro screen # Child Parent Frame Relationship -widgets have parents, but frames don't -widget value = frame.make(args); - -could this work? -probably. - todo: - - frame - - widget adds parent? - -make frame and widget virtual class / interface classes - -could make widow base that widget and frame inherit from. -widget adds parent things -frame adds the ability to fixed - -don't render frames? -probably a good idea. -maybe not worth it -will needless add another level of rendering and pointer dereferencing. - - + - do all TODOs in the buttons + - need to rename "the buttons" + - need to refactor all the file names and what not + + could make widow base that widget and frame inherit from. + - want to reduce the amount of code duplications + - want to start making buttons and other things + - text rendering + + object has the frame + each interaction with the widgets get forwarded to the object. diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index 0a2e7115..99cd4f12 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -47,13 +47,6 @@ class BorderedWidget : public virtual WidgetBase { {position, glm::ivec2(position.x + widget_size.x, position.y), position + widget_size, glm::ivec2(position.x, position.y + widget_size.y)} ), - // Frame( - // position, widget_size, - // {position, glm::ivec2(position.x + widget_size.x, position.y), - // position + widget_size, - // glm::ivec2(position.x, position.y + widget_size.y)}, - // false - // ) data_(data) { data_->update_position(get_bounding_box()); @@ -97,24 +90,22 @@ class BorderedWidget : public virtual WidgetBase { [[nodiscard]] inline virtual glm::ivec4 get_border_size() const { - return {5, 5, 5, 5}; + return data_->get_border_size(); } [[nodiscard]] inline virtual glm::ivec4 get_side_lengths() const { - return {1, 1, 1, 1}; + return data_->get_side_lengths(); } [[nodiscard]] inline virtual glm::ivec2 get_inner_pattern_size() const { - return {1, 1}; + return data_->get_inner_pattern_size(); } [[nodiscard]] inline virtual std::array get_texture_regions() const { - return {glm::ivec2(0, 0), glm::ivec2(5, 0), glm::ivec2(6, 0), - glm::ivec2(0, 5), glm::ivec2(5, 5), glm::ivec2(6, 5), - glm::ivec2(0, 6), glm::ivec2(5, 6), glm::ivec2(6, 6)}; + return data_->get_texture_regions(); } }; diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index 0148a825..8555bf76 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -3,6 +3,7 @@ #include "../the_buttons/bordered_widget.hpp" #include "../the_buttons/bordered_window.hpp" #include "../the_buttons/user_interface.hpp" +#include "gui/render/structures/window_texture.hpp" #include "util/files.hpp" #include "util/png_image.hpp" @@ -10,8 +11,17 @@ namespace gui { void setup(the_buttons::UserInterface& user_interface) { + auto texture_data_1 = files::read_json_from_file( + files::get_resources_path() / "textures" / "GenericBorder.json" + ); + + if (!texture_data_1) { + LOG_ERROR(logging::file_io_logger, "Failed to load texture"); + return; + } + auto image_result = image::read_image( - files::get_resources_path() / "textures" / "GenericBorder.png" + files::get_resources_path() / "textures" / texture_data_1->texture_file ); if (!image_result.has_value()) { LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); @@ -21,21 +31,40 @@ setup(the_buttons::UserInterface& user_interface) { std::shared_ptr a_window = std::make_shared( - std::make_shared(image), + std::make_shared(image, texture_data_1.value()), glm::ivec2(70, 70), glm::ivec2(230, 230) ); std::shared_ptr a_second_window = std::make_shared( - std::make_shared(image), + std::make_shared(image, texture_data_1.value()), glm::ivec2(200, 200), glm::ivec2(400, 600) ); + auto texture_data_2 = files::read_json_from_file( + files::get_resources_path() / "textures" / "GenericBorder_2.json" + ); + + if (!texture_data_2) { + LOG_ERROR(logging::file_io_logger, "Failed to load texture"); + return; + } + + auto image_result_2 = image::read_image( + files::get_resources_path() / "textures" / texture_data_2->texture_file + ); + if (!image_result_2.has_value()) { + LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result_2.error()); + return; + } + std::shared_ptr image_2 = image_result_2.value(); + + std::shared_ptr a_widget = a_second_window->make( - std::make_shared(image), + std::make_shared(image_2, texture_data_2.value()), glm::ivec2(20, 20), glm::ivec2(180, 300) ); From 6d01690d1286699cf557f2b1da2744788803790e Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 21 Dec 2025 15:47:57 -0500 Subject: [PATCH 21/56] button widget --- resources/textures/GenericButton.json | 9 ++ resources/textures/GenericButton.png | Bin 0 -> 137 bytes src/gui/the_buttons/bordered_widget.hpp | 2 +- src/gui/the_buttons/button_widget.hpp | 133 ++++++++++++++++++++++++ src/gui/the_buttons/frame.cpp | 2 +- src/gui/the_buttons/frame_part.cpp | 2 +- src/gui/the_buttons/user_interface.cpp | 25 +++++ src/gui/the_buttons/user_interface.hpp | 8 ++ src/gui/ui/user_interface_setup.cpp | 33 ++++++ 9 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 resources/textures/GenericButton.json create mode 100644 resources/textures/GenericButton.png create mode 100644 src/gui/the_buttons/button_widget.hpp diff --git a/resources/textures/GenericButton.json b/resources/textures/GenericButton.json new file mode 100644 index 00000000..0c083444 --- /dev/null +++ b/resources/textures/GenericButton.json @@ -0,0 +1,9 @@ +{ + "texture_file" : "./GenericButton.png", +"border_size" : [5,5,5,5], +"side_lengths" : [1,1,1,1], +"inner_pattern_size" : [1,1], +"texture_regions" : [[0, 0], [5, 0], [6, 0], + [0, 5], [5, 5], [6, 5], + [0, 6], [5, 6], [6, 6]] +} \ No newline at end of file diff --git a/resources/textures/GenericButton.png b/resources/textures/GenericButton.png new file mode 100644 index 0000000000000000000000000000000000000000..4c686400ffe38f2174eac5c1dbaf2cc52da64cd1 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqh0iG_7Are!Q6BHN?4oO_fa{FJX zSylB~MmfgNCz0i|Jx{ClKcj=D1_xO-YPyK0A6mu4zF=;W+mnC;&mDK1th;xvfU~4W k=RDJ8R$+x(k}V7juIuF*76>-;1I=deboFyt=akR{02|0E{Qv*} literal 0 HcmV?d00001 diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index 99cd4f12..603bcad6 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -39,7 +39,7 @@ class BorderedWidget : public virtual WidgetBase { BorderedWidget& operator=(BorderedWidget&& obj) = default; BorderedWidget( - FrameInterface* parent, std::shared_ptr data, + WidgetInterface* parent, std::shared_ptr data, glm::ivec2 position, glm::ivec2 widget_size ) : WidgetBase( diff --git a/src/gui/the_buttons/button_widget.hpp b/src/gui/the_buttons/button_widget.hpp new file mode 100644 index 00000000..d92f2ff4 --- /dev/null +++ b/src/gui/the_buttons/button_widget.hpp @@ -0,0 +1,133 @@ +#pragma once + +#include "bordered_widget.hpp" +#include "frame_part.hpp" +#include "gui/render/structures/window_texture.hpp" +#include "types.hpp" +#include "widget.hpp" + +#include +#include + +namespace gui { + +namespace the_buttons { + +class ButtonWidget : public virtual WidgetBase { + private: + std::shared_ptr data_; + + std::function button_function_; + + public: + ButtonWidget() = delete; + /** + * @brief Deleted copy constructor + */ + ButtonWidget(const ButtonWidget& obj) = delete; + + /** + * @brief Deleted copy operator + */ + ButtonWidget& operator=(const ButtonWidget& obj) = delete; + + /** + * @brief Default move constructor + */ + ButtonWidget(ButtonWidget&& obj) = default; + + /** + * @brief Default move constructor + */ + ButtonWidget& operator=(ButtonWidget&& obj) = default; + + ButtonWidget( + WidgetInterface* parent, std::shared_ptr data, + glm::ivec2 position, glm::ivec2 widget_size, std::function button_function + ) : + WidgetBase( + parent, position, widget_size, + {position, glm::ivec2(position.x + widget_size.x, position.y), + position + widget_size, glm::ivec2(position.x, position.y + widget_size.y)} + ), + + data_(data), button_function_(button_function) { + data_->update_position(get_bounding_box()); + } + + inline virtual ~ButtonWidget(){}; + + inline unsigned int + get_num_vertices() const { + return data_->get_num_vertices(); + } + + inline virtual void + bind() const { + data_->bind(); + }; + + inline virtual void + release() const { + data_->release(); + } + + inline virtual bool + do_render() const { + return data_->do_render(); + }; + + inline void + user_interface_render( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position + ) const override { + user_interface->render_frame(this, x_position, y_position); + + for (const auto& child : children) { + child->user_interface_render( + user_interface, x_position + position_.x, y_position + position_.y + ); + } + } + + [[nodiscard]] inline virtual glm::ivec4 + get_border_size() const { + return data_->get_border_size(); + } + + [[nodiscard]] inline virtual glm::ivec4 + get_side_lengths() const { + return data_->get_side_lengths(); + } + + [[nodiscard]] inline virtual glm::ivec2 + get_inner_pattern_size() const { + return data_->get_inner_pattern_size(); + } + + [[nodiscard]] inline virtual std::array + get_texture_regions() const { + return data_->get_texture_regions(); + } + + // rn this may work, but... + // want to separate between has clickable and renderable children. + inline bool has_children() const { + return false; + } + + inline virtual void + handle_mouse_button_input( + [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, + [[maybe_unused]] int action, [[maybe_unused]] int mods + ) { + if (action == GLFW_PRESS) { + button_function_(); + } + } +}; + +} // namespace the_buttons + +} // namespace gui \ No newline at end of file diff --git a/src/gui/the_buttons/frame.cpp b/src/gui/the_buttons/frame.cpp index 3ae0c1e7..3a6c80df 100644 --- a/src/gui/the_buttons/frame.cpp +++ b/src/gui/the_buttons/frame.cpp @@ -16,7 +16,7 @@ namespace the_buttons { std::weak_ptr FrameBase::get_child_at_position(screen_size_t x, screen_size_t y) const { for (const auto& child : children) { - if (child->is_interior(x, y)) { + if (child->is_interior(x - position_.x, y - position_.y)) { if (child->has_children()) { return child->get_child_at_position(x - position_.x, y - position_.y); } else { diff --git a/src/gui/the_buttons/frame_part.cpp b/src/gui/the_buttons/frame_part.cpp index 5931bef9..2fd3328f 100644 --- a/src/gui/the_buttons/frame_part.cpp +++ b/src/gui/the_buttons/frame_part.cpp @@ -59,7 +59,7 @@ WidgetBase::has_children() const { std::weak_ptr WidgetBase::get_child_at_position(screen_size_t x, screen_size_t y) const { for (const auto& child : children) { - if (child->is_interior(x, y)) { + if (child->is_interior(x - position_.x, y - position_.y)) { if (child->has_children()) { return child->get_child_at_position(x - position_.x, y - position_.y); } else { diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 00f5257c..b3d1eebe 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -7,6 +7,7 @@ #include "../render/structures/uniform_types.hpp" #include "bordered_widget.hpp" #include "bordered_window.hpp" +#include "button_widget.hpp" #include "manifest/object_handler.hpp" #include "widget.hpp" @@ -139,6 +140,30 @@ UserInterface::render_frame( // widget->render_children(this, x_frame_position, y_frame_position); } +void +UserInterface::render_frame( + const ButtonWidget* widget, screen_size_t x_frame_position, + screen_size_t y_frame_position +) const { + // TODO + border_sizes_->set_border_size(widget->get_border_size()); + side_lengths_->set_side_lengths(widget->get_side_lengths()); + inner_pattern_size_->set_inner_pattern_size(widget->get_inner_pattern_size()); + texture_regions_->set_texture_regions(widget->get_texture_regions()); + + const auto bounding_box = widget->get_bounding_box(); + // add offset + frame_size_uniform_->set_frame_size( + glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) + ); + window_pipeline_->render( + bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, + bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, widget + ); + + // widget->render_children(this, x_frame_position, y_frame_position); +} + std::pair, std::weak_ptr> UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const { diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index db220ab9..6ee7589f 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -13,6 +13,7 @@ namespace the_buttons { class BorderedWidget; class BorderedWindow; +class ButtonWidget; class UserInterface : public virtual scene::Inputs { private: @@ -78,6 +79,13 @@ class UserInterface : public virtual scene::Inputs { screen_size_t y_frame_position ) const; + // one of these for each + void render_frame( + const ButtonWidget* widget, screen_size_t x_frame_position, + screen_size_t y_frame_position + ) const; + + /** * @brief Handle key input including mouse keys * diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index 8555bf76..d9209492 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -6,6 +6,7 @@ #include "gui/render/structures/window_texture.hpp" #include "util/files.hpp" #include "util/png_image.hpp" +#include "../the_buttons/button_widget.hpp" namespace gui { @@ -69,6 +70,38 @@ setup(the_buttons::UserInterface& user_interface) { glm::ivec2(20, 20), glm::ivec2(180, 300) ); + + + auto texture_data_3 = files::read_json_from_file( + files::get_resources_path() / "textures" / "GenericButton.json" + ); + + if (!texture_data_3) { + LOG_ERROR(logging::file_io_logger, "Failed to load texture"); + return; + } + + auto image_result_3 = image::read_image( + files::get_resources_path() / "textures" / texture_data_3->texture_file + ); + if (!image_result_3.has_value()) { + LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result_3.error()); + return; + } + std::shared_ptr image_3 = image_result_3.value(); + + + auto a_button = + a_widget->make( + std::make_shared(image_3, texture_data_3.value()), + + glm::ivec2(20, 20), glm::ivec2(140, 100), + std::function([](){ + LOG_INFO(logging::main_logger, "Button Was Pressed"); + }) + ); + + user_interface.add(a_window); user_interface.add(a_second_window); From d6a8b62e266073241f65cee60f70f9b44c046d7f Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sun, 21 Dec 2025 17:05:10 -0500 Subject: [PATCH 22/56] some fixes to framed rendering --- resources/shaders/overlay/FramedWindow.frag | 19 ++++++------------- resources/textures/GenericBorder_2.json | 2 +- src/gui/the_buttons/README.md | 5 +++++ src/gui/ui/user_interface_setup.cpp | 2 +- src/types.hpp | 4 +++- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag index 020686db..7e60ad53 100644 --- a/resources/shaders/overlay/FramedWindow.frag +++ b/resources/shaders/overlay/FramedWindow.frag @@ -4,26 +4,19 @@ layout(location = 0) out vec3 color; in vec2 UV; // in pixels -uniform ivec2 frame_size; // error +uniform ivec2 frame_size; uniform usampler2D window_texture; -//uniform int texture_locations[36]; // error uniform int ui_scale; // uniform -uniform ivec4 border_size; // done +uniform ivec4 border_size; uniform ivec4 side_lengths; uniform ivec2 inner_pattern_size; -uniform ivec2 positions[9]; // doesn't work -// need four border sizes -// need for side lengths -// need size if inner pattern -// need 9 positions +uniform ivec2 positions[9]; void main(){ - //int border_size = 5; - ivec2 position_1 = positions[0]; ivec2 position_2 = positions[1]; ivec2 position_3 = positions[2]; @@ -86,17 +79,17 @@ main(){ } else if ((frame_size_px.x - ui_position.x) <= border_size[3]) { // 6 - ivec2 local_position = ivec2(border_size[2] - frame_size_px.x + ui_position.x, ui_position.y - border_size); + ivec2 local_position = ivec2(border_size[2] - frame_size_px.x + ui_position.x, ui_position.y - border_size[3]); local_position.y = local_position.y % height_6; texture_offset = local_position + position_6; } else if ((frame_size_px.y - ui_position.y) <= border_size[3]) { // 8 idk - ivec2 local_position = ivec2(ui_position.x - border_size[2], frame_size_px.y - ui_position.y-1); + ivec2 local_position = ivec2(ui_position.x - border_size[2], ui_position.y - frame_size_px.y + border_size[3]); local_position.x = local_position.x % width_8; - texture_offset = local_position + position_2; + texture_offset = local_position + position_8; } else { // 5 ivec2 local_position = ivec2(ui_position.x - border_size[0], ui_position.y - border_size[1]); local_position.x = local_position.x % width_5; diff --git a/resources/textures/GenericBorder_2.json b/resources/textures/GenericBorder_2.json index ba59e8fc..c93be282 100644 --- a/resources/textures/GenericBorder_2.json +++ b/resources/textures/GenericBorder_2.json @@ -6,6 +6,6 @@ "texture_regions" : [ [0, 0], [6, 0], [15, 0], [0, 6], [6, 6], [15, 6], - [0, 15], [7, 15], [15, 15] + [0, 15], [6, 15], [15, 15] ] } \ No newline at end of file diff --git a/src/gui/the_buttons/README.md b/src/gui/the_buttons/README.md index ea1c35d1..f3ff3c4b 100644 --- a/src/gui/the_buttons/README.md +++ b/src/gui/the_buttons/README.md @@ -29,6 +29,11 @@ todo: - want to reduce the amount of code duplications - want to start making buttons and other things - text rendering + - mouse click enums + + in fact the top level inputs should handle keybinding + + everything else should take enums, and maybe screen coordinates + - widget needs a get global position function. + - need a seconds inputs template that uses the types I created object has the frame each interaction with the widgets get forwarded to the object. diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index d9209492..66540928 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -95,7 +95,7 @@ setup(the_buttons::UserInterface& user_interface) { a_widget->make( std::make_shared(image_3, texture_data_3.value()), - glm::ivec2(20, 20), glm::ivec2(140, 100), + glm::ivec2(20, 28), glm::ivec2(140, 80), std::function([](){ LOG_INFO(logging::main_logger, "Button Was Pressed"); }) diff --git a/src/types.hpp b/src/types.hpp index cfdb7b54..e1244b09 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -105,9 +105,11 @@ static_assert(sizeof(VoxelColorId) == sizeof(MatColorId)); // size in pixels of graphics objects using screen_size_t = int; +// screen position +using screen_position_t = glm::vec<2, screen_size_t>; // I'm so sorry, but this is needed because opengl uses ints to return from get -// window size +// window size, instead of unsigned ints template <> struct std::hash { From c19702e1117d7e53201bac2438153cbf2f2a4725 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Mon, 22 Dec 2025 14:03:17 -0500 Subject: [PATCH 23/56] refactoring --- src/gui/scene/controls.cpp | 2 +- src/gui/scene/keymapping.hpp | 59 ++++++++++++++++++ src/gui/the_buttons/README.md | 13 +++- src/gui/the_buttons/bordered_widget.hpp | 4 +- src/gui/the_buttons/button_widget.hpp | 6 +- src/gui/the_buttons/frame_part.hpp | 1 + src/gui/the_buttons/user_interface.cpp | 2 +- src/gui/ui/imgui_style.cpp | 2 +- vendor/fonts/{ => UbuntuMono}/UFL.txt | 0 .../{ => UbuntuMono}/UbuntuMono-Bold.ttf | Bin .../UbuntuMono-BoldItalic.ttf | Bin .../{ => UbuntuMono}/UbuntuMono-Italic.ttf | Bin .../{ => UbuntuMono}/UbuntuMono-Regular.ttf | Bin vendor/fonts/pixel_font/Pixelated_7_10.ttf | Bin 0 -> 8444 bytes 14 files changed, 79 insertions(+), 10 deletions(-) rename vendor/fonts/{ => UbuntuMono}/UFL.txt (100%) rename vendor/fonts/{ => UbuntuMono}/UbuntuMono-Bold.ttf (100%) rename vendor/fonts/{ => UbuntuMono}/UbuntuMono-BoldItalic.ttf (100%) rename vendor/fonts/{ => UbuntuMono}/UbuntuMono-Italic.ttf (100%) rename vendor/fonts/{ => UbuntuMono}/UbuntuMono-Regular.ttf (100%) create mode 100644 vendor/fonts/pixel_font/Pixelated_7_10.ttf diff --git a/src/gui/scene/controls.cpp b/src/gui/scene/controls.cpp index 1c15c5ea..53711eb1 100644 --- a/src/gui/scene/controls.cpp +++ b/src/gui/scene/controls.cpp @@ -118,7 +118,7 @@ Controls::handle_mouse_scroll_input( void Controls::handle_mouse_button_input( - GLFWwindow* window, int button, int action, int mods + GLFWwindow* window, int button, int action, [[maybe_unused]] int mods ) { if (static_cast(button) == Key::MOUSE_LEFT && action == GLFW_PRESS) { double xpos; diff --git a/src/gui/scene/keymapping.hpp b/src/gui/scene/keymapping.hpp index c418e906..d20cca3d 100644 --- a/src/gui/scene/keymapping.hpp +++ b/src/gui/scene/keymapping.hpp @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -424,6 +425,64 @@ to_string(const Key& key) { } } +enum KeyAction { + PRESS = GLFW_PRESS, + RELEASE = GLFW_RELEASE, + REPEAT = GLFW_REPEAT +}; + +constexpr inline std::string +to_string(const KeyAction& key) { + switch (key) { + case KeyAction::PRESS: + return "KEY_PRESS"; + case KeyAction::RELEASE: + return "KEY_RELEASE"; + case KeyAction::REPEAT: + return "KEY_REPEAT"; + default: + throw exc::not_implemented_error("Unknown key action"); + } +} + +enum KeyModifier { + SHIFT = GLFW_MOD_SHIFT, + CONTROL = GLFW_MOD_CONTROL, + ALT = GLFW_MOD_ALT, + SUPER = GLFW_MOD_SUPER, + CAPS_LOCK = GLFW_MOD_CAPS_LOCK, + NUM_LOCK = GLFW_MOD_NUM_LOCK +}; +/* +// TODO want to make this constexpr +// ftm::join and fmt format are not cont expr +inline std::string +to_string(const KeyModifier& key) { + +std::vector mods; +// std::string mods = ""; +if (key | KeyModifier::SHIFT) { + mods.push_back("SHIFT"); +} if (key | KeyModifier::CONTROL) { + mods.push_back("CONTROL"); +} +if (key | KeyModifier::ALT) { + mods.push_back("ALT"); +} +if (key | KeyModifier::SUPER) { + mods.push_back("SUPER"); +} +if (key | KeyModifier::CAPS_LOCK) { + mods.push_back("CAPS_LOCK"); +} +if (key | KeyModifier::NUM_LOCK) { + mods.push_back("NUM_LOCK"); +} + +return fmtquill::format("{}", fmtquill::join(mods, " & ")); +} +*/ + namespace scene { enum Action : int { diff --git a/src/gui/the_buttons/README.md b/src/gui/the_buttons/README.md index f3ff3c4b..d0207825 100644 --- a/src/gui/the_buttons/README.md +++ b/src/gui/the_buttons/README.md @@ -26,13 +26,20 @@ todo: - need to rename "the buttons" - need to refactor all the file names and what not + could make widow base that widget and frame inherit from. - - want to reduce the amount of code duplications + + want to reduce the amount of code duplications - want to start making buttons and other things - - text rendering + = buttons + - text + - radio buttons + - enums + - key select (for keybinding) + - toggle button + + > text rendering - mouse click enums + in fact the top level inputs should handle keybinding + everything else should take enums, and maybe screen coordinates - - widget needs a get global position function. + > widget needs a get global position function. - need a seconds inputs template that uses the types I created object has the frame diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index 603bcad6..669b781c 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -31,12 +31,12 @@ class BorderedWidget : public virtual WidgetBase { /** * @brief Default move constructor */ - BorderedWidget(BorderedWidget&& obj) = default; + BorderedWidget(BorderedWidget&& obj) = delete; /** * @brief Default move constructor */ - BorderedWidget& operator=(BorderedWidget&& obj) = default; + BorderedWidget& operator=(BorderedWidget&& obj) = delete; BorderedWidget( WidgetInterface* parent, std::shared_ptr data, diff --git a/src/gui/the_buttons/button_widget.hpp b/src/gui/the_buttons/button_widget.hpp index d92f2ff4..24743167 100644 --- a/src/gui/the_buttons/button_widget.hpp +++ b/src/gui/the_buttons/button_widget.hpp @@ -31,15 +31,17 @@ class ButtonWidget : public virtual WidgetBase { */ ButtonWidget& operator=(const ButtonWidget& obj) = delete; + // TODO reimplement + // https://stackoverflow.com/questions/64325516/move-assignment-operator-and-virtual-inheritance/64326111#64326111 /** * @brief Default move constructor */ - ButtonWidget(ButtonWidget&& obj) = default; + ButtonWidget(ButtonWidget&& obj) = delete; /** * @brief Default move constructor */ - ButtonWidget& operator=(ButtonWidget&& obj) = default; + ButtonWidget& operator=(ButtonWidget&& obj) = delete; ButtonWidget( WidgetInterface* parent, std::shared_ptr data, diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index b92f7803..5a631191 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -31,6 +31,7 @@ class WidgetBase : public virtual WidgetInterface { position_(position), frame_size_(frame_size), exterior_points_(exterior_points){}; + WidgetBase() = delete; /** * @brief Deleted copy constructor */ diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index b3d1eebe..fb79c31b 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -67,7 +67,7 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s } void -UserInterface::update(screen_size_t width, screen_size_t height) { +UserInterface::update([[maybe_unused]] screen_size_t width, [[maybe_unused]] screen_size_t height) { // cascade update frames using width and height FrameBufferHandler::instance().bind_fbo(0); // the screen diff --git a/src/gui/ui/imgui_style.cpp b/src/gui/ui/imgui_style.cpp index 40e62ff3..16113b80 100644 --- a/src/gui/ui/imgui_style.cpp +++ b/src/gui/ui/imgui_style.cpp @@ -77,7 +77,7 @@ set_imgui_style() { ImGuiIO& io = ImGui::GetIO(); std::filesystem::path mono_font = - files::get_root_path() / "vendor" / "fonts" / "UbuntuMono-Regular.ttf"; + files::get_root_path() / "vendor" / "fonts" / "UbuntuMono" / "UbuntuMono-Regular.ttf"; // - If no fonts are loaded, dear imgui will use the default font. You can also load // multiple fonts and use ImGui::PushFont()/PopFont() to select them. diff --git a/vendor/fonts/UFL.txt b/vendor/fonts/UbuntuMono/UFL.txt similarity index 100% rename from vendor/fonts/UFL.txt rename to vendor/fonts/UbuntuMono/UFL.txt diff --git a/vendor/fonts/UbuntuMono-Bold.ttf b/vendor/fonts/UbuntuMono/UbuntuMono-Bold.ttf similarity index 100% rename from vendor/fonts/UbuntuMono-Bold.ttf rename to vendor/fonts/UbuntuMono/UbuntuMono-Bold.ttf diff --git a/vendor/fonts/UbuntuMono-BoldItalic.ttf b/vendor/fonts/UbuntuMono/UbuntuMono-BoldItalic.ttf similarity index 100% rename from vendor/fonts/UbuntuMono-BoldItalic.ttf rename to vendor/fonts/UbuntuMono/UbuntuMono-BoldItalic.ttf diff --git a/vendor/fonts/UbuntuMono-Italic.ttf b/vendor/fonts/UbuntuMono/UbuntuMono-Italic.ttf similarity index 100% rename from vendor/fonts/UbuntuMono-Italic.ttf rename to vendor/fonts/UbuntuMono/UbuntuMono-Italic.ttf diff --git a/vendor/fonts/UbuntuMono-Regular.ttf b/vendor/fonts/UbuntuMono/UbuntuMono-Regular.ttf similarity index 100% rename from vendor/fonts/UbuntuMono-Regular.ttf rename to vendor/fonts/UbuntuMono/UbuntuMono-Regular.ttf diff --git a/vendor/fonts/pixel_font/Pixelated_7_10.ttf b/vendor/fonts/pixel_font/Pixelated_7_10.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3f8110b2ea378c7540f9852a69b2c1bac4d2fce6 GIT binary patch literal 8444 zcmd6sTZ~;*8OPV&``qW+%k%;*96W`VOQ+L0913NCR?2X(Tw9A5v>n=Erg5gzOb5~u zO?WXeBpO4Eslh~^d?3Wo#`s`(;DHz=m?%->0}qIr@F0Tm5(UEe`+wis=bV|gT;hv+ zpS|~5Yw!Ji|L^~O>sxE>6Os@@e|REf;n4W_{=1+1-NHK|)L*A{!|i)+8xKQaHT9QN zzjxoZ(L0|$@TU-xY3hd#&rTfQpY@y$A^kmV4t;UI}5{>FLRdBUipX{UZ1N!g1X+4dKf0AhI@5-!whDa57uH_yP5w za}3VR9iI4A>E)mD{x0r6IXiLkc=%@cI`{6NUOzT5J2`UinID9(@d%inJ3e<}q5N#Q z$*n=|KO1CgSpU6$-1YZ24-Sm|GxW%|5dOUPm5N>G#tVxdEWR7o20dR1sao0e-XQI1 zSSK{xH%Yn`w>{RfC+rVpYtfsDwe1SS)=~()$+tt1avyvHFJ7yZX-z{Bp5nGd`hAbw zb|k!rl*hxs;(I(e7)m_n&(y*Ix)WhpZMh9V+Wy zE<<%ZOFVSm(Q|rFSINrX)3fV1a+$g(Oge<6mqYq>RXx|Cx)>_La$a6VU1iD8Rfpcy zJK{QTTS+;8M)!i^&W;U{tB0tGwGH6d#kCh1DdpjCL-=C&Qh1zL4b(=$ZfX;Yi;KTq z{LSJo7hhTYMU=p8-x65Pos@|Aoc;C#c_F`Mp-?Q9E7e+0uUOR9KQOpr<*L;~Yu2t? zf6>JoHePaR{jyIrHeG(j<}LJs5U#rVnytgzMz)VOuWenohYo|S%b8``B;sye&j5GJ*8jp!WXP_vpO{Nk1-nS)ckSS$#k^l?eD0w*18 zImRk_w=J={EnlEzI9i6bA4z;jiOan znPsw0d)W-5ai}D+%BBlVCT^gnYnGWsMa(KmuJbKh=xg$zAvYhQ;Q|&7HNfY*bQxkM zpiPX)$O7uPcH_S+Y|Zh5_k3E+p0y%RP%tkm0vm~@Pr)ON90Mj_CK;hsqKiUN_P9+o za`#5G8BIoyD@1DBtf3O`yM&}dp;Rg=$dVL?Qy|C{=gP7JLD+AK=sk|27(lugmc~5z z8!dSxw?wzo7(@nIs%j(5vx+?n|dJ`gk?6}lVw&ZaZZeK z=e-}^*OFT{Ti!8^PAF&Z?F||YL^)n-CJcE!X-X$f3UKLN%b4veiB6sJIO)f>mRr_R zpNhL{a63`J9(DSCYiTu!7qD9o<7_c1OWD$Nka+UD)hVp)GhE-(VM0NNfDovOe)=t z?w4o~@IEE^WO_q;Uit91Om0>=M`lOf0Nn5RNbZqo-j>IGKR^3PR)*jU(2r5-RXP7| z&mi_(>|+|-xE{p-W&B~+a#}(pKf4T&A|OPWqMH|uSIoK$XZt<9HlSxa_9}-n8}zXX z`O=8449tuMdc2pRAmatcr>Aer<$|iSJJuL28HO4S;9gUWK-qG)Jb*I;H5mHb5&ZN4XrY)w^+nUj2kV(!sclqdaCj|AER7x`UlfLz*MgXv~&pIUAi- zSGKVk4VOYp2;KE|JbhfhIf6Dzxqgp~HUQTv-2%ZzKGb3(`VFmdJ*Kr=_wHuOXgRNY zk5ADiL)qvtorRfIq$sMiiFv1jLW`GonW+!zOGxCs!DyNdrYqwbhp$#$_W{u$_|m~O zslJ!w>#G|5uF=kJ<{8DB?Otoz%7g|DKx8gX%vTw*!B?{tg!Lu4go5UPjqFT()2qC)$mbR%1y0Q9rE@)wPjU77t1&<$hgoIc2wv*~{z>#8z< zl2Q(mkujdToor*|E;Jd+5QZ>TF0D##UAQ&g4`Ue{3t zZ`rw)P{4J|HYVUB$E~G!l&v+hct~@>azKP1^In-aAb)m!JHYx58)AevUP9Sb>-lK5coC~o zOZ?I^l3oo=$)J5R>R`9|R|kC5YElfklPMECtfN6D*bL!hTbz-}vd-5W?g)efX>;Z_ zGPXtojUBy6bmnXQmH54nnU2Le$S5CV6fqOtvE6!n` zb7!_~-e~)^W?$1>_cGZ|&w2eS(I$DBUlqq6>-${hsRk*LIp$k=6KG53I{Ghj!5(C; z*B2uZ;3VY!H>x1W10v^#?>KoT6BXt%v=HvDgEsgQQK;$YSgX~n@{k1q=k5$tc6V5s z(2bgrEcjhXu14q~*7K#YPPH8m%A0)2Z}%b7lzZ9Y*D{0>gOH|jS>FH3yzAf0&~1Ss zV=1ZDGQ-7wvN_*%!_yeSmlsMlQn_6W9d0xJ*4+3iu}hoyqxg=){kR3 zMgAXRISU8Ee`2{1HY8t*#SRjQ9DBWyuCFMpE=Rhz6+^(>nQhzkvm6?d~)mD z@l*3hr=}O`TMl1Y9~~KOT~psZGdVkPYVOhL`o3eQj!e$iw@lD-!pgg*W+#r$3?H7G z<>mX3b`q^K$X(!iBpl@X+CjeDj&Sqn$;p|Cg~=lacO2YK{Q(}B0lhO+BIj-ho9I1PkTvxW=2hWp;$$nBwt-BfG{d#T&UJX^dcK71q$iB= z_2K5QE9~KG-*~t^+!5{!cZJV{z2WX~Pq-K8_v5a8{IC95;`hPux$yb$1^%slh<|9c hC9KaaZ& Date: Tue, 23 Dec 2025 15:36:31 -0500 Subject: [PATCH 24/56] almost working texture loading --- CMakeLists.txt | 3 +- src/gui/render/structures/font.cpp | 117 +++++++++++ src/gui/render/structures/font.hpp | 49 +++++ src/gui/the_buttons/text_widget.hpp | 116 +++++++++++ src/gui/ui/user_interface_setup.cpp | 3 + src/util/image.cpp | 28 +++ src/util/image.hpp | 71 +++++++ src/util/png_image.hpp | 299 +++++----------------------- 8 files changed, 437 insertions(+), 249 deletions(-) create mode 100644 src/gui/render/structures/font.cpp create mode 100644 src/gui/render/structures/font.hpp create mode 100644 src/gui/the_buttons/text_widget.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ee924644..145269ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,13 +55,14 @@ find_package(GLEW REQUIRED) find_package(glfw3 REQUIRED) find_package(glm REQUIRED) find_package(PNG REQUIRED) +find_package(Freetype REQUIRED) # find_package(OpenMP REQUIRED) target_link_libraries(FunGame PRIVATE glfw) target_link_libraries(FunGame PRIVATE OpenGL::GL) target_link_libraries(FunGame PRIVATE GLEW::GLEW) target_link_libraries(FunGame PRIVATE PNG::PNG) -# target_link_libraries(FunGame PRIVATE OpenMP::OpenMP_CXX) +target_link_libraries(FunGame PRIVATE Freetype::Freetype) if(WIN32) target_link_libraries(FunGame PRIVATE glm) diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp new file mode 100644 index 00000000..6f17de82 --- /dev/null +++ b/src/gui/render/structures/font.cpp @@ -0,0 +1,117 @@ +#include "font.hpp" +//#include "../render/texture.hpp" +#include "logging.hpp" +#include "util/files.hpp" +#include "util/png_image.hpp" + +#include +#include FT_FREETYPE_H +// ^ what type of mad man write this? +// + +namespace gui { + +namespace render { + +namespace structures { + + + + +// FontHandler::FontHandler () { +// FT_Library ft; + +// if (FT_Init_FreeType(&ft)) { +// LOG_WARNING(logging::main_logger, "Could not initiate FreeType."); +// return; +// } +// } + + +/// + + +FontTexture::FontTexture(std::filesystem::path font_file) { + + FT_Library ft; + + if (FT_Init_FreeType(&ft)) { + LOG_WARNING(logging::main_logger, "Could not initiate FreeType."); + return; + } + + FT_Face font_face; + if (FT_New_Face(ft, + font_file.c_str(), + 0, &font_face) ) { + LOG_WARNING(logging::main_logger, "Could not load Pixelated Font"); + return; + } + + FT_Set_Pixel_Sizes(font_face, 0, 10); + + if (FT_Load_Char(font_face, 'a', FT_LOAD_RENDER)) { + LOG_WARNING(logging::main_logger, "Failed to load \"{}\" from font.", 'a'); + return; + } + + + auto settings = gpu_data::TextureSettings{.internal_format = gpu_data::GPUPixelStorageFormat::R, + .read_format = gpu_data::GPUPixelReadFormat::RED, + .type = gpu_data::GPUPixelType::UNSIGNED_BYTE, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST}; + + unsigned int max_height = 0; + unsigned int total_width = 0; + + std::unordered_map images; + + for (unsigned char c = 0; c < 128; c++) { + if (FT_Load_Char(font_face, c, FT_LOAD_RENDER)) { + LOG_WARNING(logging::main_logger, "Failed to load \"{}\" from font.", c); + return; + } + + auto char_size = glm::uvec2(font_face->glyph->bitmap.width, font_face->glyph->bitmap.rows); + auto char_position = glm::uvec2(font_face->glyph->bitmap_left, font_face->glyph->bitmap_top); + //auto char_texture = gpu_data::Texture2D(char_size.x, char_size.y, settings); + + images.emplace(c, util::image::ByteMonochromeImage(font_face->glyph->bitmap.buffer, char_size.x, char_size.y, sizeof(char))); + + image::write_image(images.at(c), files::get_log_path() / ("font_as_image_" + std::string(1, c) + ".png")); + + + font_textures_.emplace(c, Character{ + .size = char_size, + .bearing = char_position, + .advance = static_cast(font_face->glyph->advance.x), + .position_in_texture = glm::ivec4(total_width, 0, total_width + char_size.x, char_size.y)}); + + total_width += char_size.x; + if (char_size.y > max_height) { + max_height = char_size.y; + } + } + + // std::shared_ptr image(new char[max_height * total_width]); + + auto image = std::make_shared(total_width, max_height, sizeof(char)); + + for (unsigned char c = 0; c < 128; c++) { + image->draw_at(images.at(c), font_textures_[c].position_in_texture.x, font_textures_[c].position_in_texture.y); + } + + LOG_DEBUG(logging::main_logger, "saving fonts to file."); + image::write_image(*image, files::get_log_path() / "font_as_image.png"); + texture_ = std::make_shared(image, settings); +} + + +} + +} + +} // namespace gui + + diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp new file mode 100644 index 00000000..da00b2f9 --- /dev/null +++ b/src/gui/render/structures/font.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "../gpu_data/texture.hpp" +#include +#include + + +namespace gui { + +namespace render { + +namespace structures { + + +struct Character { + glm::ivec2 size; + glm::ivec2 bearing; + unsigned int advance; + glm::ivec4 position_in_texture; +}; + +class FontTexture { + private: + + std::shared_ptr texture_; + + std::unordered_map font_textures_; + + public: + FontTexture(std::filesystem::path font_file); + + +}; + + + + +class FontHandler { + FontHandler(std::filesystem::path font_file); +}; + + + + +} + +} + +} // namespace gui diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp new file mode 100644 index 00000000..865a2653 --- /dev/null +++ b/src/gui/the_buttons/text_widget.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include "bordered_widget.hpp" +#include "frame_part.hpp" +#include "gui/render/structures/font.hpp" +#include "types.hpp" +#include "widget.hpp" + +#include + +namespace gui { + +namespace the_buttons { + +class TextWidget : public virtual WidgetBase { + private: + //std::shared_ptr data_; + std::shared_ptr data_; + std::string text_; + + public: + TextWidget() = delete; + /** + * @brief Deleted copy constructor + */ + TextWidget(const TextWidget& obj) = delete; + + /** + * @brief Deleted copy operator + */ + TextWidget& operator=(const TextWidget& obj) = delete; + + /** + * @brief Default move constructor + */ + TextWidget(TextWidget&& obj) = delete; + + /** + * @brief Default move constructor + */ + TextWidget& operator=(TextWidget&& obj) = delete; + + TextWidget( + WidgetInterface* parent, std::shared_ptr data, + glm::ivec2 position, glm::ivec2 widget_size + ) : + WidgetBase( + parent, position, widget_size, + {position, glm::ivec2(position.x + widget_size.x, position.y), + position + widget_size, glm::ivec2(position.x, position.y + widget_size.y)} + ), + + data_(data) { + data_->update_position(get_bounding_box()); + } + + inline virtual ~TextWidget(){}; + + inline unsigned int + get_num_vertices() const { + return data_->get_num_vertices(); + } + + inline virtual void + bind() const { + data_->bind(); + }; + + inline virtual void + release() const { + data_->release(); + } + + inline virtual bool + do_render() const { + return data_->do_render(); + }; + + inline void + user_interface_render( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position + ) const override { + user_interface->render_frame(this, x_position, y_position); + + for (const auto& child : children) { + child->user_interface_render( + user_interface, x_position + position_.x, y_position + position_.y + ); + } + } + + [[nodiscard]] inline virtual glm::ivec4 + get_border_size() const { + return data_->get_border_size(); + } + + [[nodiscard]] inline virtual glm::ivec4 + get_side_lengths() const { + return data_->get_side_lengths(); + } + + [[nodiscard]] inline virtual glm::ivec2 + get_inner_pattern_size() const { + return data_->get_inner_pattern_size(); + } + + [[nodiscard]] inline virtual std::array + get_texture_regions() const { + return data_->get_texture_regions(); + } +}; + +} // namespace the_buttons + +} // namespace gui \ No newline at end of file diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index 66540928..28f01231 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -7,6 +7,7 @@ #include "util/files.hpp" #include "util/png_image.hpp" #include "../the_buttons/button_widget.hpp" +#include "gui/render/structures/font.hpp" namespace gui { @@ -107,6 +108,8 @@ setup(the_buttons::UserInterface& user_interface) { // window_pipeline->data.push_back(scene.a_window.get()); + auto my_font = render::structures::FontTexture(files::get_root_path() / "vendor" / "fonts" / "pixel_font" / "Pixelated_7_10.ttf"); + return; } diff --git a/src/util/image.cpp b/src/util/image.cpp index 2f631788..1436d8f3 100644 --- a/src/util/image.cpp +++ b/src/util/image.cpp @@ -1,11 +1,30 @@ #include "image.hpp" #include "util/color.hpp" +#include namespace util { namespace image { + + Image::Image( + void* data, size_t width, size_t height, size_t data_size + ) : + width_(width), + height_(height), data_size_(data_size), data_(new char[width * height * data_size]){ + std::memcpy(data_.get(), data, width * height * data_size); + }; + + + Image::Image( + size_t width, size_t height, size_t data_size + ) : + width_(width), + height_(height), data_size_(data_size), data_(new char[width * height * data_size]) { + std::memset(data_.get(), char(0), width * height * data_size); + }; + png_byte FloatMonochromeImage::get_color(size_t i, size_t j) const { assert(i < width_ && j < height_ && "Position must be within image."); @@ -116,6 +135,15 @@ BytePolychromeAlphaImage::get_color(size_t i, size_t j) const { return read_data_byte(data_, i * height_ + j); } +void +ByteMonochromeImage::draw_at(const ByteMonochromeImage& other, size_t position_x, size_t position_y) { + for (size_t i = 0; i < other.get_width(); i++) { + for (size_t j = 0; j < other.get_height(); j++) { + set_color(other.get_color(i,j), i + position_x, j + position_y); + } + } +} + } // namespace image } // namespace util \ No newline at end of file diff --git a/src/util/image.hpp b/src/util/image.hpp index d2bba3bc..0bc6c4b0 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -91,6 +91,16 @@ class Image { width_(width), height_(height), data_size_(data_size), data_(data){}; + Image( + void* data, size_t width, size_t height, size_t data_size + ); + + + Image( + size_t width, size_t height, size_t data_size + ); + + virtual ~Image() {} }; @@ -238,6 +248,31 @@ class ByteMonochromeImage : public virtual MonochromeImage { ); } + ByteMonochromeImage( + void* data, size_t width, size_t height, size_t data_size + ) : + Image(data, width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + + ByteMonochromeImage( + size_t width, size_t height, size_t data_size + ) : + Image(width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + + void draw_at(const ByteMonochromeImage& other, size_t position_x, size_t position_y); + + void set_color(png_byte color, size_t i, size_t j) { + data_[i * height_ + j] = color; + } + + inline virtual size_t get_width() const { return width_; @@ -266,6 +301,24 @@ class BytePolychromeImage : public virtual PolychromeImage { ); } + BytePolychromeImage( + void* data, size_t width, size_t height, size_t data_size + ) : + Image(data, width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + + BytePolychromeImage( + size_t width, size_t height, size_t data_size + ) : + Image(width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + inline virtual size_t get_width() const { return width_; @@ -303,6 +356,24 @@ class BytePolychromeAlphaImage : public virtual PolychromeAlphaImage { ); } + BytePolychromeAlphaImage( + void* data, size_t width, size_t height, size_t data_size + ) : + Image(data, width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + + BytePolychromeAlphaImage( + size_t width, size_t height, size_t data_size + ) : + Image(width, height, data_size) { + assert( + data_size == sizeof(unsigned char) && "data size must match expected size" + ); + } + // BytePolychromeAlphaImage(std::vector> data) : // BytePolychromeAlphaImage(pad_color_data(data)) {} diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index da519821..d80f320f 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -70,125 +70,6 @@ concept ImageRGBA = requires(T const img, size_t i, size_t j) { { img.get_color(i, j) } -> std::same_as>; }; -template -[[nodiscard]] write_result_t -write_image(T image, const std::filesystem::path& path) { - // Keep track of if we succeeded or not - write_result_t status = WR_OK; - - // Get image information - size_t WIDTH = image.get_width(); - size_t HEIGHT = image.get_height(); - - char meta_lang[] = "en"; - char meta_key[] = "An Image"; - char meta_text[] = "Some text"; - - // Create png variables - png_structp png_ptr = nullptr; - png_infop info_ptr = nullptr; - - // Open the file for writing - auto path_str = path.string(); // need to keep this from being free'd - std::FILE* file = fopen(path_str.c_str(), "wb"); - - if (!file) { - status = WR_FOPEN_FAILED; - goto fopen_failed; - } - - // Create our write struct - // TODO these nullptr should be function pointers - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png_ptr) { - status = WR_CREATE_WRITE_STRUCT_FAILED; - goto png_create_write_struct_failed; - } - - // Create our info struct for this png image - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - status = WR_CREATE_INFO_STRUCT_FAILED; - goto png_create_info_struct_failed; - } - - // Set jump buffer for callbacks - if (setjmp(png_jmpbuf(png_ptr))) { - status = WR_SETJMP_PNG_JMPBUF_FAILED; - goto setjmp_png_jmpbuf_failed; - } - - // Set up IO for our file - png_init_io(png_ptr, file); - - // set information about our image - png_set_IHDR( - png_ptr, info_ptr, WIDTH, HEIGHT, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT - ); - - // Set metadata about the PNG file - png_text meta_data; - memset(&meta_data, 0, sizeof(meta_data)); // clear struct - - meta_data.compression = PNG_TEXT_COMPRESSION_NONE; // no compression - meta_data.lang_key = meta_lang; - meta_data.key = meta_key; - meta_data.text = meta_text; - - png_set_text(png_ptr, info_ptr, &meta_data, 1); - png_write_info(png_ptr, info_ptr); - - // multiple colors are written in the same row - // not sure how I want to implement this in a template safe way - // https://stackoverflow.com/questions/48757099/write-an-image-row-by-row-with-libpng-using-c - - /* - * write rows of image - */ - size_t i, j; - png_bytep row; - - // allocate data for row - row = new (std::nothrow) png_byte[WIDTH]; - if (!row) { - status = WR_ROW_MALLOC_FAILED; - goto row_malloc_failed; - } - - // write row data - for (i = 0; i < HEIGHT; i++) { - // set row data - for (j = 0; j < WIDTH; j++) - row[j] = static_cast(image.get_color(i, j)); - - // write the row - png_write_row(png_ptr, row); - } - - /* - * Cleanups - */ - // Free our row data - delete[] row; - -row_malloc_failed: - // Finish our write - png_write_end(png_ptr, info_ptr); - -setjmp_png_jmpbuf_failed: -png_create_info_struct_failed: - // Free our write struct - png_destroy_write_struct(&png_ptr, &info_ptr); - -png_create_write_struct_failed: - // Close our file - fclose(file); - -fopen_failed: - return status; -} - void log_result(write_result_t result, const std::filesystem::path& path); // #if DEBUG() @@ -213,9 +94,21 @@ class ImageTest { } }; -template +namespace { + +template +auto to_array(std::array array) { + return array; +} + +template +auto to_array(T value) { + return std::array({value}); +} + +template [[nodiscard]] write_result_t -write_image(T image, const std::filesystem::path& path) { +write_image_base(T image, const std::filesystem::path& path/*other settings*/) { // Keep track of if we succeeded or not write_result_t status = WR_OK; @@ -264,10 +157,22 @@ write_image(T image, const std::filesystem::path& path) { // Set up IO for our file png_init_io(png_ptr, file); + int color_type; + + if constexpr (n == 1) { + color_type = PNG_COLOR_TYPE_GRAY; + } else if constexpr (n == 3) { + color_type = PNG_COLOR_TYPE_RGB; + } else if constexpr (n == 4) { + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + } else { + static_assert(n == 1 || n == 3 || n == 4, "Invalid number of color channels"); + } + // set information about our image png_set_IHDR( - png_ptr, info_ptr, WIDTH, HEIGHT, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT + png_ptr, info_ptr, WIDTH, HEIGHT, 8, color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); // Set metadata about the PNG file @@ -293,20 +198,22 @@ write_image(T image, const std::filesystem::path& path) { png_bytep row; // allocate data for row - row = new (std::nothrow) png_byte[3 * WIDTH]; + row = new (std::nothrow) png_byte[n * WIDTH]; if (!row) { status = WR_ROW_MALLOC_FAILED; goto row_malloc_failed; } // write row data - for (i = 0; i < HEIGHT; i++) { + for (i = 0; i < WIDTH; i++) { // set row data - for (j = 0; j < WIDTH; j++) { - const std::array pixel_color = image.get_color(i, j); - row[3 * j] = pixel_color[0]; - row[3 * j + 1] = pixel_color[1]; - row[3 * j + 2] = pixel_color[2]; + for (j = 0; j < HEIGHT; j++) { + + const std::array pixel_color = to_array(image.get_color(i, j)); + for (unsigned int channel = 0; channel < n; channel ++) { + + row[n * j + channel] = pixel_color[channel]; + } } // write the row @@ -336,128 +243,24 @@ write_image(T image, const std::filesystem::path& path) { return status; } -template +} + +template [[nodiscard]] write_result_t write_image(T image, const std::filesystem::path& path) { - // Keep track of if we succeeded or not - write_result_t status = WR_OK; - - // Get image information - size_t WIDTH = image.get_width(); - size_t HEIGHT = image.get_height(); - - char meta_lang[] = "en"; - char meta_key[] = "An Image"; - char meta_text[] = "Some text"; - - // Create png variables - png_structp png_ptr = nullptr; - png_infop info_ptr = nullptr; - - // Open the file for writing - auto path_str = path.string(); // need to keep this from being free'd - std::FILE* file = fopen(path_str.c_str(), "wb"); - - if (!file) { - status = WR_FOPEN_FAILED; - goto fopen_failed; - } - - // Create our write struct - // TODO these nullptr should be function pointers - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png_ptr) { - status = WR_CREATE_WRITE_STRUCT_FAILED; - goto png_create_write_struct_failed; - } - - // Create our info struct for this png image - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - status = WR_CREATE_INFO_STRUCT_FAILED; - goto png_create_info_struct_failed; - } - - // Set jump buffer for callbacks - if (setjmp(png_jmpbuf(png_ptr))) { - status = WR_SETJMP_PNG_JMPBUF_FAILED; - goto setjmp_png_jmpbuf_failed; - } - - // Set up IO for our file - png_init_io(png_ptr, file); - - // set information about our image - png_set_IHDR( - png_ptr, info_ptr, WIDTH, HEIGHT, 8, PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT - ); - - // Set metadata about the PNG file - png_text meta_data; - memset(&meta_data, 0, sizeof(meta_data)); // clear struct - - meta_data.compression = PNG_TEXT_COMPRESSION_NONE; // no compression - meta_data.lang_key = meta_lang; - meta_data.key = meta_key; - meta_data.text = meta_text; - - png_set_text(png_ptr, info_ptr, &meta_data, 1); - png_write_info(png_ptr, info_ptr); - - // multiple colors are written in the same row - // not sure how I want to implement this in a template safe way - // https://stackoverflow.com/questions/48757099/write-an-image-row-by-row-with-libpng-using-c - - /* - * write rows of image - */ - size_t i, j; - png_bytep row; - - // allocate data for row - row = new (std::nothrow) png_byte[4 * WIDTH]; - if (!row) { - status = WR_ROW_MALLOC_FAILED; - goto row_malloc_failed; - } - - // write row data - for (i = 0; i < HEIGHT; i++) { - // set row data - for (j = 0; j < WIDTH; j++) { - const std::array pixel_color = image.get_color(i, j); - row[4 * j] = pixel_color[0]; - row[4 * j + 1] = pixel_color[1]; - row[4 * j + 2] = pixel_color[2]; - row[4 * j + 3] = pixel_color[3]; - } - - // write the row - png_write_row(png_ptr, row); - } - - /* - * Cleanups - */ - // Free our row data - delete[] row; - -row_malloc_failed: - // Finish our write - png_write_end(png_ptr, info_ptr); - -setjmp_png_jmpbuf_failed: -png_create_info_struct_failed: - // Free our write struct - png_destroy_write_struct(&png_ptr, &info_ptr); + return write_image_base(image, path); +} -png_create_write_struct_failed: - // Close our file - fclose(file); +template +[[nodiscard]] write_result_t +write_image(T image, const std::filesystem::path& path) { + return write_image_base(image, path); +} -fopen_failed: - return status; +template +[[nodiscard]] write_result_t +write_image(T image, const std::filesystem::path& path) { + return write_image_base(image, path); } class ColorImageTest { From d7001c700aaa704b5c44478f36418473dac12987 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 23 Dec 2025 19:17:27 -0500 Subject: [PATCH 25/56] writing fonts works --- src/gui/render/structures/font.cpp | 28 ++++++++++++++++++++++------ src/util/image.hpp | 2 +- src/util/png_image.hpp | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 6f17de82..622fb716 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -48,7 +48,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { return; } - FT_Set_Pixel_Sizes(font_face, 0, 10); + FT_Set_Pixel_Sizes(font_face, 0, 20); if (FT_Load_Char(font_face, 'a', FT_LOAD_RENDER)) { LOG_WARNING(logging::main_logger, "Failed to load \"{}\" from font.", 'a'); @@ -68,7 +68,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { std::unordered_map images; for (unsigned char c = 0; c < 128; c++) { - if (FT_Load_Char(font_face, c, FT_LOAD_RENDER)) { + if (FT_Load_Char(font_face, c, FT_LOAD_RENDER | FT_LOAD_MONOCHROME)) { LOG_WARNING(logging::main_logger, "Failed to load \"{}\" from font.", c); return; } @@ -77,9 +77,25 @@ FontTexture::FontTexture(std::filesystem::path font_file) { auto char_position = glm::uvec2(font_face->glyph->bitmap_left, font_face->glyph->bitmap_top); //auto char_texture = gpu_data::Texture2D(char_size.x, char_size.y, settings); - images.emplace(c, util::image::ByteMonochromeImage(font_face->glyph->bitmap.buffer, char_size.x, char_size.y, sizeof(char))); + + std::vector data; + data.resize(char_size.x * char_size.y); + for (size_t i = 0; i < font_face->glyph->bitmap.width; i++){ + for (size_t j=0; j < font_face->glyph->bitmap.rows; j++) { + + png_byte font_bit = font_face->glyph->bitmap.buffer[j * font_face->glyph->bitmap.pitch + i / 8]; + uint8_t one = 1; + uint8_t value = font_bit >> (7 - i % 8); + data[j * font_face->glyph->bitmap.width + i] = (value & one) * 255; + } + } +// if (c == 'a' || c == 'b') { +// LOG_DEBUG(logging::main_logger, "{}", data); +// } - image::write_image(images.at(c), files::get_log_path() / ("font_as_image_" + std::string(1, c) + ".png")); + images.emplace(c, util::image::ByteMonochromeImage(data.data(), char_size.y, char_size.x, sizeof(char))); + +// image::write_image(images.at(c), files::get_log_path() / ("font_as_image_" + std::string(1, c) + ".png")); font_textures_.emplace(c, Character{ @@ -96,10 +112,10 @@ FontTexture::FontTexture(std::filesystem::path font_file) { // std::shared_ptr image(new char[max_height * total_width]); - auto image = std::make_shared(total_width, max_height, sizeof(char)); + auto image = std::make_shared(max_height, total_width, sizeof(char)); for (unsigned char c = 0; c < 128; c++) { - image->draw_at(images.at(c), font_textures_[c].position_in_texture.x, font_textures_[c].position_in_texture.y); + image->draw_at(images.at(c), font_textures_[c].position_in_texture.y, font_textures_[c].position_in_texture.x); } LOG_DEBUG(logging::main_logger, "saving fonts to file."); diff --git a/src/util/image.hpp b/src/util/image.hpp index 0bc6c4b0..b01c09d1 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -269,7 +269,7 @@ class ByteMonochromeImage : public virtual MonochromeImage { void draw_at(const ByteMonochromeImage& other, size_t position_x, size_t position_y); void set_color(png_byte color, size_t i, size_t j) { - data_[i * height_ + j] = color; + reinterpret_cast(data_.get())[i * height_ + j] = color; } diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index d80f320f..59a55fa3 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -171,7 +171,7 @@ write_image_base(T image, const std::filesystem::path& path/*other settings*/) { // set information about our image png_set_IHDR( - png_ptr, info_ptr, WIDTH, HEIGHT, 8, color_type, + png_ptr, info_ptr, HEIGHT, WIDTH, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); From 15e53ea0bfd6fcd727fb8ef2d7ee465f46ee188f Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Mon, 29 Dec 2025 18:06:59 -0500 Subject: [PATCH 26/56] write text render shader --- resources/shaders/overlay/TextWindow.frag | 23 ++++ resources/shaders/overlay/TextWindow.vert | 22 ++++ src/gui/render/gl_enums.hpp | 4 +- src/gui/render/gpu_data/frame_buffer.cpp | 4 +- .../render/gpu_data/vertex_array_object.hpp | 11 +- src/gui/render/structures/font.cpp | 103 +++++++++-------- src/gui/render/structures/font.hpp | 27 ++--- src/gui/render/structures/i_mesh.hpp | 6 +- src/gui/render/structures/window_texture.cpp | 8 +- src/gui/render/structures/window_texture.hpp | 107 +++++++++++------- src/gui/scene/keymapping.hpp | 11 +- src/gui/the_buttons/bordered_widget.cpp | 22 ++++ src/gui/the_buttons/bordered_widget.hpp | 15 +-- src/gui/the_buttons/button_widget.hpp | 8 +- src/gui/the_buttons/frame_part.hpp | 27 ++--- src/gui/the_buttons/text_widget.cpp | 39 +++++++ src/gui/the_buttons/text_widget.hpp | 84 +++++++------- src/gui/the_buttons/user_interface.cpp | 35 +++++- src/gui/the_buttons/user_interface.hpp | 9 +- src/gui/ui/imgui_style.cpp | 4 +- src/gui/ui/user_interface_setup.cpp | 33 +++--- src/util/image.cpp | 33 +++--- src/util/image.hpp | 37 ++---- src/util/png_image.hpp | 22 ++-- 24 files changed, 417 insertions(+), 277 deletions(-) create mode 100644 resources/shaders/overlay/TextWindow.frag create mode 100644 resources/shaders/overlay/TextWindow.vert create mode 100644 src/gui/the_buttons/bordered_widget.cpp create mode 100644 src/gui/the_buttons/text_widget.cpp diff --git a/resources/shaders/overlay/TextWindow.frag b/resources/shaders/overlay/TextWindow.frag new file mode 100644 index 00000000..36c912c2 --- /dev/null +++ b/resources/shaders/overlay/TextWindow.frag @@ -0,0 +1,23 @@ +#version 450 core + + +// Ouput data +layout(location = 0) out vec3 color; + +uniform sampler2D texture_id; +//uniform vec3 font_color; + +in vec2 UV; + +void +main() { + color = vec3(0.6,0.2,0.1); + // vec3 font_color = vec3(0,0,0); + + // float alpha = texture(texture_id, UV).a; + // if (alpha > 0) { + // color = font_color; + // } else { + // discard; + // } +} diff --git a/resources/shaders/overlay/TextWindow.vert b/resources/shaders/overlay/TextWindow.vert new file mode 100644 index 00000000..217fe3cb --- /dev/null +++ b/resources/shaders/overlay/TextWindow.vert @@ -0,0 +1,22 @@ +#version 450 core + +// Input vertex data, different for all executions of this shader. +layout(location = 0) in ivec4 pos; +//layout(location = 1) in vec2 vertex_position_screenspace; + +// this is the size of the view +// then switch to division +//uniform vec2 projection_matrix; + +// Output data ; will be interpolated for each fragment. +out vec2 UV; + +void +main() { + + //vec2 projection_matrix = vec2(1/250, 1/250); + + gl_Position = vec4( (pos.xy - 100) / 150, 1, 1); + UV = pos.zw; +} + diff --git a/src/gui/render/gl_enums.hpp b/src/gui/render/gl_enums.hpp index b8dc7e80..7aa382a4 100644 --- a/src/gui/render/gl_enums.hpp +++ b/src/gui/render/gl_enums.hpp @@ -156,7 +156,7 @@ enum class GPUPixelType : GLenum { }; enum class GPUPixelStorageFormat : GLenum { - R = GL_R, + RED = GL_RED, DEPTH = GL_DEPTH_COMPONENT, DEPTH_16 = GL_DEPTH_COMPONENT16, DEPTH_24 = GL_DEPTH_COMPONENT24, @@ -622,7 +622,7 @@ get_size(const GPUPixelReadFormat& data_format) { constexpr inline size_t get_size(const GPUPixelStorageFormat& data_format) { switch (data_format) { - case GPUPixelStorageFormat::R: + case GPUPixelStorageFormat::RED: case GPUPixelStorageFormat::DEPTH: return 1; case GPUPixelStorageFormat::RGB: diff --git a/src/gui/render/gpu_data/frame_buffer.cpp b/src/gui/render/gpu_data/frame_buffer.cpp index 0c8b2d39..28aa2480 100644 --- a/src/gui/render/gpu_data/frame_buffer.cpp +++ b/src/gui/render/gpu_data/frame_buffer.cpp @@ -100,7 +100,7 @@ FrameBufferBase::read_data( type = color_texture->get_type(); format = color_texture->get_format(); switch (format) { - case GPUPixelStorageFormat::R: + case GPUPixelStorageFormat::RED: read_format = GPUPixelReadFormat::RED; break; case GPUPixelStorageFormat::RGB: @@ -133,7 +133,7 @@ FrameBufferBase::read_data( } switch (format) { - case GPUPixelStorageFormat::R: + case GPUPixelStorageFormat::RED: case GPUPixelStorageFormat::DEPTH: // in this case format_size should be 1 return std::make_shared( diff --git a/src/gui/render/gpu_data/vertex_array_object.hpp b/src/gui/render/gpu_data/vertex_array_object.hpp index 85e40f20..c9d8fdc5 100644 --- a/src/gui/render/gpu_data/vertex_array_object.hpp +++ b/src/gui/render/gpu_data/vertex_array_object.hpp @@ -16,9 +16,14 @@ class VertexArrayObject { /** * @brief construct a new VertexArrayObject */ - inline VertexArrayObject() { - GlobalContext& context = GlobalContext::instance(); - context.push_opengl_task([this]() { glGenVertexArrays(1, &vertex_array_); }); + inline VertexArrayObject(bool differed = true) { + if (differed) { + GlobalContext& context = GlobalContext::instance(); + context.push_opengl_task([this]() { glGenVertexArrays(1, &vertex_array_); } + ); + } else { + glGenVertexArrays(1, &vertex_array_); + } }; // copy and move constructor diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 622fb716..42cf3f43 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -1,23 +1,21 @@ #include "font.hpp" -//#include "../render/texture.hpp" +// #include "../render/texture.hpp" #include "logging.hpp" #include "util/files.hpp" #include "util/png_image.hpp" #include #include FT_FREETYPE_H + // ^ what type of mad man write this? -// +// namespace gui { - + namespace render { namespace structures { - - - // FontHandler::FontHandler () { // FT_Library ft; @@ -27,12 +25,9 @@ namespace structures { // } // } - -/// - +/// FontTexture::FontTexture(std::filesystem::path font_file) { - FT_Library ft; if (FT_Init_FreeType(&ft)) { @@ -40,10 +35,8 @@ FontTexture::FontTexture(std::filesystem::path font_file) { return; } - FT_Face font_face; - if (FT_New_Face(ft, - font_file.c_str(), - 0, &font_face) ) { + FT_Face font_face; + if (FT_New_Face(ft, font_file.c_str(), 0, &font_face)) { LOG_WARNING(logging::main_logger, "Could not load Pixelated Font"); return; } @@ -55,12 +48,12 @@ FontTexture::FontTexture(std::filesystem::path font_file) { return; } - - auto settings = gpu_data::TextureSettings{.internal_format = gpu_data::GPUPixelStorageFormat::R, - .read_format = gpu_data::GPUPixelReadFormat::RED, - .type = gpu_data::GPUPixelType::UNSIGNED_BYTE, - .min_filter = GL_NEAREST, - .mag_filter = GL_NEAREST}; + auto settings = gpu_data::TextureSettings{ + .internal_format = gpu_data::GPUPixelStorageFormat::RED, + .read_format = gpu_data::GPUPixelReadFormat::RED, + .type = gpu_data::GPUPixelType::UNSIGNED_BYTE, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST}; unsigned int max_height = 0; unsigned int total_width = 0; @@ -73,36 +66,46 @@ FontTexture::FontTexture(std::filesystem::path font_file) { return; } - auto char_size = glm::uvec2(font_face->glyph->bitmap.width, font_face->glyph->bitmap.rows); - auto char_position = glm::uvec2(font_face->glyph->bitmap_left, font_face->glyph->bitmap_top); - //auto char_texture = gpu_data::Texture2D(char_size.x, char_size.y, settings); + auto char_size = + glm::uvec2(font_face->glyph->bitmap.width, font_face->glyph->bitmap.rows); + auto char_position = + glm::uvec2(font_face->glyph->bitmap_left, font_face->glyph->bitmap_top); + // auto char_texture = gpu_data::Texture2D(char_size.x, char_size.y, settings); - std::vector data; data.resize(char_size.x * char_size.y); - for (size_t i = 0; i < font_face->glyph->bitmap.width; i++){ - for (size_t j=0; j < font_face->glyph->bitmap.rows; j++) { - - png_byte font_bit = font_face->glyph->bitmap.buffer[j * font_face->glyph->bitmap.pitch + i / 8]; + for (size_t i = 0; i < font_face->glyph->bitmap.width; i++) { + for (size_t j = 0; j < font_face->glyph->bitmap.rows; j++) { + png_byte font_bit = + font_face->glyph->bitmap + .buffer[j * font_face->glyph->bitmap.pitch + i / 8]; uint8_t one = 1; uint8_t value = font_bit >> (7 - i % 8); data[j * font_face->glyph->bitmap.width + i] = (value & one) * 255; } } -// if (c == 'a' || c == 'b') { -// LOG_DEBUG(logging::main_logger, "{}", data); -// } - - images.emplace(c, util::image::ByteMonochromeImage(data.data(), char_size.y, char_size.x, sizeof(char))); - -// image::write_image(images.at(c), files::get_log_path() / ("font_as_image_" + std::string(1, c) + ".png")); - - - font_textures_.emplace(c, Character{ - .size = char_size, - .bearing = char_position, - .advance = static_cast(font_face->glyph->advance.x), - .position_in_texture = glm::ivec4(total_width, 0, total_width + char_size.x, char_size.y)}); + // if (c == 'a' || c == 'b') { + // LOG_DEBUG(logging::main_logger, "{}", data); + // } + + images.emplace( + c, util::image::ByteMonochromeImage( + data.data(), char_size.y, char_size.x, sizeof(char) + ) + ); + + // image::write_image(images.at(c), files::get_log_path() / + // ("font_as_image_" + std::string(1, c) + ".png")); + + font_textures_.emplace( + c, + Character{ + .size = char_size, + .bearing = char_position, + .advance = static_cast(font_face->glyph->advance.x), + .position_in_texture = + glm::ivec4(total_width, 0, total_width + char_size.x, char_size.y)} + ); total_width += char_size.x; if (char_size.y > max_height) { @@ -112,10 +115,15 @@ FontTexture::FontTexture(std::filesystem::path font_file) { // std::shared_ptr image(new char[max_height * total_width]); - auto image = std::make_shared(max_height, total_width, sizeof(char)); + auto image = std::make_shared( + max_height, total_width, sizeof(char) + ); for (unsigned char c = 0; c < 128; c++) { - image->draw_at(images.at(c), font_textures_[c].position_in_texture.y, font_textures_[c].position_in_texture.x); + image->draw_at( + images.at(c), font_textures_[c].position_in_texture.y, + font_textures_[c].position_in_texture.x + ); } LOG_DEBUG(logging::main_logger, "saving fonts to file."); @@ -123,11 +131,8 @@ FontTexture::FontTexture(std::filesystem::path font_file) { texture_ = std::make_shared(image, settings); } +} // namespace structures -} - -} +} // namespace render } // namespace gui - - diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index da00b2f9..ff92c4fe 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -1,17 +1,16 @@ #pragma once #include "../gpu_data/texture.hpp" -#include -#include +#include +#include namespace gui { - + namespace render { namespace structures { - struct Character { glm::ivec2 size; glm::ivec2 bearing; @@ -21,7 +20,6 @@ struct Character { class FontTexture { private: - std::shared_ptr texture_; std::unordered_map font_textures_; @@ -29,21 +27,14 @@ class FontTexture { public: FontTexture(std::filesystem::path font_file); - + inline virtual void + bind(GLuint texture_index) const { + texture_->bind(texture_index); + } }; +} // namespace structures - - -class FontHandler { - FontHandler(std::filesystem::path font_file); -}; - - - - -} - -} +} // namespace render } // namespace gui diff --git a/src/gui/render/structures/i_mesh.hpp b/src/gui/render/structures/i_mesh.hpp index 4a54e449..4d501072 100644 --- a/src/gui/render/structures/i_mesh.hpp +++ b/src/gui/render/structures/i_mesh.hpp @@ -85,15 +85,17 @@ class IMeshGPU : virtual public GPUDataElements { * @param util::Mesh& mesh to load * @param bool b set to false when calling this constructor when inherited */ - explicit inline IMeshGPU(const util::Mesh& mesh, bool b = true) : + explicit inline IMeshGPU(const util::Mesh& mesh, bool differed = true) : vertex_array_(mesh.get_indexed_vertices()), color_array_(mesh.get_indexed_color_ids()), normal_array_(mesh.get_indexed_normals()), element_array_(mesh.get_indices()), num_vertices_(mesh.get_indices().size()), do_render_(mesh.get_indices().size()) { - if (b) { + if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { initialize(); }); + } else { + initialize(); } } diff --git a/src/gui/render/structures/window_texture.cpp b/src/gui/render/structures/window_texture.cpp index 6630f6e7..2f13514b 100644 --- a/src/gui/render/structures/window_texture.cpp +++ b/src/gui/render/structures/window_texture.cpp @@ -52,10 +52,12 @@ WindowTexture::WindowTexture( }); } -WindowTexture::WindowTexture(std::shared_ptr image,const window_texture_data_t& texture_data) : +WindowTexture::WindowTexture( + std::shared_ptr image, const window_texture_data_t& texture_data +) : WindowTexture( - image, texture_data.border_size, - texture_data.side_lengths, texture_data.inner_pattern_size, texture_data.texture_regions + image, texture_data.border_size, texture_data.side_lengths, + texture_data.inner_pattern_size, texture_data.texture_regions ) {} } // namespace render diff --git a/src/gui/render/structures/window_texture.hpp b/src/gui/render/structures/window_texture.hpp index 1e8af2f8..985026d2 100644 --- a/src/gui/render/structures/window_texture.hpp +++ b/src/gui/render/structures/window_texture.hpp @@ -23,52 +23,69 @@ struct window_texture_data_t { glm::ivec2 inner_pattern_size; std::array texture_regions; - inline std::array border_size_write() { - return {border_size[0], border_size[1],border_size[2],border_size[3]}; + inline std::array + border_size_write() { + return {border_size[0], border_size[1], border_size[2], border_size[3]}; } - inline void border_size_read(std::array border_size_in) { - border_size = glm::ivec4(border_size_in[0], border_size_in[1],border_size_in[2],border_size_in[3]); + inline void + border_size_read(std::array border_size_in) { + border_size = glm::ivec4( + border_size_in[0], border_size_in[1], border_size_in[2], border_size_in[3] + ); } - inline std::array side_lengths_write() { - return {side_lengths[0], side_lengths[1],side_lengths[2],side_lengths[3]}; + inline std::array + side_lengths_write() { + return {side_lengths[0], side_lengths[1], side_lengths[2], side_lengths[3]}; } - inline void side_lengths_read(std::array side_lengths_in) { - side_lengths = glm::ivec4(side_lengths_in[0], side_lengths_in[1],side_lengths_in[2],side_lengths_in[3]); + inline void + side_lengths_read(std::array side_lengths_in) { + side_lengths = glm::ivec4( + side_lengths_in[0], side_lengths_in[1], side_lengths_in[2], + side_lengths_in[3] + ); } - inline std::array inner_pattern_size_write() { + inline std::array + inner_pattern_size_write() { return {inner_pattern_size[0], inner_pattern_size[1]}; } - inline void inner_pattern_size_read(std::array inner_pattern_size_in) { - inner_pattern_size = glm::ivec2(inner_pattern_size_in[0], inner_pattern_size_in[1]); + inline void + inner_pattern_size_read(std::array inner_pattern_size_in) { + inner_pattern_size = + glm::ivec2(inner_pattern_size_in[0], inner_pattern_size_in[1]); } - inline std::array, 9> texture_regions_write() { - return {std::array({texture_regions[0].x, texture_regions[0].y}), - std::array({texture_regions[1].x, texture_regions[1].y}), - std::array({texture_regions[2].x, texture_regions[2].y}), - std::array({texture_regions[3].x, texture_regions[3].y}), - std::array({texture_regions[4].x, texture_regions[4].y}), - std::array({texture_regions[5].x, texture_regions[5].y}), - std::array({texture_regions[6].x, texture_regions[6].y}), - std::array({texture_regions[7].x, texture_regions[7].y}), - std::array({texture_regions[8].x, texture_regions[8].y})}; + inline std::array, 9> + texture_regions_write() { + return { + std::array({texture_regions[0].x, texture_regions[0].y}), + std::array({texture_regions[1].x, texture_regions[1].y}), + std::array({texture_regions[2].x, texture_regions[2].y}), + std::array({texture_regions[3].x, texture_regions[3].y}), + std::array({texture_regions[4].x, texture_regions[4].y}), + std::array({texture_regions[5].x, texture_regions[5].y}), + std::array({texture_regions[6].x, texture_regions[6].y}), + std::array({texture_regions[7].x, texture_regions[7].y}), + std::array({texture_regions[8].x, texture_regions[8].y})}; } - inline void texture_regions_read(std::array, 9> texture_regions_in) { - texture_regions = std::array({glm::ivec2(texture_regions_in[0][0], texture_regions_in[0][1]), - glm::ivec2(texture_regions_in[1][0], texture_regions_in[1][1]), - glm::ivec2(texture_regions_in[2][0], texture_regions_in[2][1]), - glm::ivec2(texture_regions_in[3][0], texture_regions_in[3][1]), - glm::ivec2(texture_regions_in[4][0], texture_regions_in[4][1]), - glm::ivec2(texture_regions_in[5][0], texture_regions_in[5][1]), - glm::ivec2(texture_regions_in[6][0], texture_regions_in[6][1]), - glm::ivec2(texture_regions_in[7][0], texture_regions_in[7][1]), - glm::ivec2(texture_regions_in[8][0], texture_regions_in[8][1])}); + inline void + texture_regions_read(std::array, 9> texture_regions_in) { + texture_regions = std::array( + {glm::ivec2(texture_regions_in[0][0], texture_regions_in[0][1]), + glm::ivec2(texture_regions_in[1][0], texture_regions_in[1][1]), + glm::ivec2(texture_regions_in[2][0], texture_regions_in[2][1]), + glm::ivec2(texture_regions_in[3][0], texture_regions_in[3][1]), + glm::ivec2(texture_regions_in[4][0], texture_regions_in[4][1]), + glm::ivec2(texture_regions_in[5][0], texture_regions_in[5][1]), + glm::ivec2(texture_regions_in[6][0], texture_regions_in[6][1]), + glm::ivec2(texture_regions_in[7][0], texture_regions_in[7][1]), + glm::ivec2(texture_regions_in[8][0], texture_regions_in[8][1])} + ); } }; @@ -119,7 +136,10 @@ class WindowTexture : public virtual gpu_data::GPUData { std::array texture_regions ); - WindowTexture(std::shared_ptr image, const window_texture_data_t& texture_data); + WindowTexture( + std::shared_ptr image, + const window_texture_data_t& texture_data + ); inline virtual ~WindowTexture() {} @@ -133,16 +153,23 @@ class WindowTexture : public virtual gpu_data::GPUData { return num_vertices_; } - [[nodiscard]] inline auto get_border_size() const { + [[nodiscard]] inline auto + get_border_size() const { return border_size_; } - [[nodiscard]] inline auto get_side_lengths() const { + + [[nodiscard]] inline auto + get_side_lengths() const { return side_lengths_; } - [[nodiscard]] inline auto get_inner_pattern_size() const { + + [[nodiscard]] inline auto + get_inner_pattern_size() const { return inner_pattern_size_; } - [[nodiscard]] inline auto get_texture_regions() const { + + [[nodiscard]] inline auto + get_texture_regions() const { return texture_regions_; } @@ -184,10 +211,6 @@ template <> struct glz::meta { using T = gui::render::window_texture_data_t; - static constexpr auto value = object("texture_file", &T::texture_file, - "border_size", custom<&T::border_size_read, &T::border_size_write>, - "side_lengths", custom<&T::side_lengths_read, &T::side_lengths_write>, - "inner_pattern_size", custom<&T::inner_pattern_size_read, &T::inner_pattern_size_write>, - "texture_regions", custom<&T::texture_regions_read, &T::texture_regions_write>); + static constexpr auto + value = object("texture_file", &T::texture_file, "border_size", custom<&T::border_size_read, &T::border_size_write>, "side_lengths", custom<&T::side_lengths_read, &T::side_lengths_write>, "inner_pattern_size", custom<&T::inner_pattern_size_read, &T::inner_pattern_size_write>, "texture_regions", custom<&T::texture_regions_read, &T::texture_regions_write>); }; - diff --git a/src/gui/scene/keymapping.hpp b/src/gui/scene/keymapping.hpp index d20cca3d..6b702c25 100644 --- a/src/gui/scene/keymapping.hpp +++ b/src/gui/scene/keymapping.hpp @@ -4,9 +4,9 @@ #include +#include #include -#include #include #include #include @@ -425,11 +425,7 @@ to_string(const Key& key) { } } -enum KeyAction { - PRESS = GLFW_PRESS, - RELEASE = GLFW_RELEASE, - REPEAT = GLFW_REPEAT -}; +enum KeyAction { PRESS = GLFW_PRESS, RELEASE = GLFW_RELEASE, REPEAT = GLFW_REPEAT }; constexpr inline std::string to_string(const KeyAction& key) { @@ -453,12 +449,13 @@ enum KeyModifier { CAPS_LOCK = GLFW_MOD_CAPS_LOCK, NUM_LOCK = GLFW_MOD_NUM_LOCK }; + /* // TODO want to make this constexpr // ftm::join and fmt format are not cont expr inline std::string to_string(const KeyModifier& key) { - + std::vector mods; // std::string mods = ""; if (key | KeyModifier::SHIFT) { diff --git a/src/gui/the_buttons/bordered_widget.cpp b/src/gui/the_buttons/bordered_widget.cpp new file mode 100644 index 00000000..25f14e30 --- /dev/null +++ b/src/gui/the_buttons/bordered_widget.cpp @@ -0,0 +1,22 @@ +#include "bordered_widget.hpp" + +#include "user_interface.hpp" + +namespace gui { +namespace the_buttons { + +void +BorderedWidget::user_interface_render( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position +) const { + user_interface->render_frame(this, x_position, y_position); + + for (const auto& child : children) { + child->user_interface_render( + user_interface, x_position + position_.x, y_position + position_.y + ); + } +} +} // namespace the_buttons +} // namespace gui \ No newline at end of file diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index 669b781c..b7d71186 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -38,7 +38,7 @@ class BorderedWidget : public virtual WidgetBase { */ BorderedWidget& operator=(BorderedWidget&& obj) = delete; - BorderedWidget( + inline BorderedWidget( WidgetInterface* parent, std::shared_ptr data, glm::ivec2 position, glm::ivec2 widget_size ) : @@ -74,19 +74,10 @@ class BorderedWidget : public virtual WidgetBase { return data_->do_render(); }; - inline void - user_interface_render( + void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position - ) const override { - user_interface->render_frame(this, x_position, y_position); - - for (const auto& child : children) { - child->user_interface_render( - user_interface, x_position + position_.x, y_position + position_.y - ); - } - } + ) const override; [[nodiscard]] inline virtual glm::ivec4 get_border_size() const { diff --git a/src/gui/the_buttons/button_widget.hpp b/src/gui/the_buttons/button_widget.hpp index 24743167..55fe80a0 100644 --- a/src/gui/the_buttons/button_widget.hpp +++ b/src/gui/the_buttons/button_widget.hpp @@ -36,7 +36,7 @@ class ButtonWidget : public virtual WidgetBase { /** * @brief Default move constructor */ - ButtonWidget(ButtonWidget&& obj) = delete; + ButtonWidget(ButtonWidget&& obj) = delete; /** * @brief Default move constructor @@ -45,7 +45,8 @@ class ButtonWidget : public virtual WidgetBase { ButtonWidget( WidgetInterface* parent, std::shared_ptr data, - glm::ivec2 position, glm::ivec2 widget_size, std::function button_function + glm::ivec2 position, glm::ivec2 widget_size, + std::function button_function ) : WidgetBase( parent, position, widget_size, @@ -115,7 +116,8 @@ class ButtonWidget : public virtual WidgetBase { // rn this may work, but... // want to separate between has clickable and renderable children. - inline bool has_children() const { + inline bool + has_children() const { return false; } diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index 5a631191..568575a0 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -71,13 +71,13 @@ class WidgetBase : public virtual WidgetInterface { // screen_size_t y_position // ) const override; - [[nodiscard]] virtual bool has_children() const; + [[nodiscard]] virtual bool has_children() const override; virtual std::weak_ptr get_child_at_position(screen_size_t x, screen_size_t y) const override; inline virtual std::array - get_bounding_box() const { + get_bounding_box() const override { return {position_.x, position_.y, frame_size_.x, frame_size_.y}; } @@ -94,7 +94,7 @@ class WidgetBase : public virtual WidgetInterface { [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, [[maybe_unused]] int scancode, [[maybe_unused]] int action, [[maybe_unused]] int mods - ){}; + ) override{}; /** * @brief Handle text input @@ -105,7 +105,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_text_input_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] unsigned int codepoint - ){}; + ) override{}; /** * @brief Handle mouse movement events. @@ -117,7 +117,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_mouse_event_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xpos, [[maybe_unused]] double ypos - ){}; + ) override{}; /** * @brief Handle mouse enter window events @@ -130,7 +130,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_mouse_button_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, [[maybe_unused]] int action, [[maybe_unused]] int mods - ){}; + ) override{}; /** * @brief Handle mouse scroll events @@ -142,7 +142,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_mouse_scroll_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xoffset, [[maybe_unused]] double yoffset - ){}; + ) override{}; /** * @brief Handle joystick event @@ -150,8 +150,9 @@ class WidgetBase : public virtual WidgetInterface { * @param int jid joystick id * @param int event */ - virtual void - handle_joystick_input([[maybe_unused]] int jid, [[maybe_unused]] int event){}; + virtual void handle_joystick_input( + [[maybe_unused]] int jid, [[maybe_unused]] int event + ) override{}; /** * @brief Handle file drop event @@ -163,28 +164,28 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_file_drop_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int count, [[maybe_unused]] const char** paths - ){}; + ) override{}; /** * @brief Handle all pooled inputs * * @param GLFWwindow* window window */ - virtual void handle_pooled_inputs([[maybe_unused]] GLFWwindow* window){}; + virtual void handle_pooled_inputs([[maybe_unused]] GLFWwindow* window) override{}; /** * @brief Setup so this objects handles inputs correctly * * @param GLFWwindow* window window */ - virtual void setup([[maybe_unused]] GLFWwindow* window){}; + virtual void setup([[maybe_unused]] GLFWwindow* window) override{}; /** * @brief Cleanup to original state * * @param GLFWwindow* window window */ - virtual void cleanup([[maybe_unused]] GLFWwindow* window){}; + virtual void cleanup([[maybe_unused]] GLFWwindow* window) override{}; }; } // namespace the_buttons diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp new file mode 100644 index 00000000..eaf503fa --- /dev/null +++ b/src/gui/the_buttons/text_widget.cpp @@ -0,0 +1,39 @@ +#include "text_widget.hpp" + +#include "user_interface.hpp" + +namespace gui { +namespace the_buttons { +void +TextWidget::update_text_data(bool differed) { + std::vector data; + + data.push_back(glm::ivec4(100, 100, 100, 15)); + data.push_back(glm::ivec4(100, 250, 100, 0)); + data.push_back(glm::ivec4(250, 100, 115, 15)); + data.push_back(glm::ivec4(250, 250, 115, 0)); + + text_data_.insert(data, 0, text_data_.size()); +} + +void +TextWidget::user_interface_render( + const UserInterface* user_interface, screen_size_t x_position, + screen_size_t y_position +) const { + user_interface->render_frame(this, x_position, y_position); +} + +void +TextWidget::attach_all() { + text_data_.attach_to_vertex_attribute(0); +} + +void +TextWidget::initialize() { + vertex_array_object_.bind(); + attach_all(); + vertex_array_object_.release(); +} +} // namespace the_buttons +} // namespace gui diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index 865a2653..90da3ace 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -2,6 +2,8 @@ #include "bordered_widget.hpp" #include "frame_part.hpp" +#include "global_context.hpp" +#include "gui/render/gpu_data/vertex_buffer_object.hpp" #include "gui/render/structures/font.hpp" #include "types.hpp" #include "widget.hpp" @@ -14,9 +16,16 @@ namespace the_buttons { class TextWidget : public virtual WidgetBase { private: - //std::shared_ptr data_; - std::shared_ptr data_; + gpu_data::VertexArrayObject vertex_array_object_; + + std::shared_ptr font_; + gpu_data::VertexBufferObject text_data_; std::string text_; + uint32_t num_characters_; + + void update_text_data(bool differed = true); + + void initialize(); public: TextWidget() = delete; @@ -40,75 +49,64 @@ class TextWidget : public virtual WidgetBase { */ TextWidget& operator=(TextWidget&& obj) = delete; - TextWidget( - WidgetInterface* parent, std::shared_ptr data, - glm::ivec2 position, glm::ivec2 widget_size + inline TextWidget( + WidgetInterface* parent, std::shared_ptr font, + glm::ivec2 position, glm::ivec2 widget_size, std::string text = std::string(""), + bool differed = true ) : WidgetBase( parent, position, widget_size, {position, glm::ivec2(position.x + widget_size.x, position.y), position + widget_size, glm::ivec2(position.x, position.y + widget_size.y)} ), - - data_(data) { - data_->update_position(get_bounding_box()); + vertex_array_object_(differed), + + font_(font), text_(text), num_characters_(text_.length()) { + if (differed) { + GlobalContext& context = GlobalContext::instance(); + context.push_opengl_task([this]() { initialize(); }); + } else { + initialize(); + } + update_text_data(); } inline virtual ~TextWidget(){}; + void attach_all(); + + inline void + set_text(std::string&& text) { + text_ = text; + update_text_data(); + } + inline unsigned int get_num_vertices() const { - return data_->get_num_vertices(); + // return num_characters_ * 4; // four vertices per character + return 4; } inline virtual void bind() const { - data_->bind(); + // text_data_.attach_to_vertex_attribute(0); + vertex_array_object_.bind(); }; inline virtual void release() const { - data_->release(); + vertex_array_object_.release(); } inline virtual bool do_render() const { - return data_->do_render(); + return true; }; - inline void - user_interface_render( + void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position - ) const override { - user_interface->render_frame(this, x_position, y_position); - - for (const auto& child : children) { - child->user_interface_render( - user_interface, x_position + position_.x, y_position + position_.y - ); - } - } - - [[nodiscard]] inline virtual glm::ivec4 - get_border_size() const { - return data_->get_border_size(); - } - - [[nodiscard]] inline virtual glm::ivec4 - get_side_lengths() const { - return data_->get_side_lengths(); - } - - [[nodiscard]] inline virtual glm::ivec2 - get_inner_pattern_size() const { - return data_->get_inner_pattern_size(); - } - - [[nodiscard]] inline virtual std::array - get_texture_regions() const { - return data_->get_texture_regions(); - } + ) const override; }; } // namespace the_buttons diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index fb79c31b..880e9d44 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -9,6 +9,7 @@ #include "bordered_window.hpp" #include "button_widget.hpp" #include "manifest/object_handler.hpp" +#include "text_widget.hpp" #include "widget.hpp" namespace gui { @@ -30,6 +31,12 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s files::get_resources_path() / "shaders" / "overlay" / "FramedWindow.frag" ); + shader::Program& text_render_program = shader_handler.load_program( + "Windows", + files::get_resources_path() / "shaders" / "overlay" / "TextWindow.vert", + files::get_resources_path() / "shaders" / "overlay" / "TextWindow.frag" + ); + // auto image_result = image::read_image(files::get_resources_path() / "textures" / // "GenericBorder.png"); if (!image_result.has_value()) { // LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); @@ -40,8 +47,6 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s // gpu_data::Texture2D border_texture(image, gui::gpu_data::TextureSettings{}, // false); - // frame_texture_uniform_ = std::make_shared<>(); - // Overwrites anything that was there before std::function render_setup = []() { // Draw over everything @@ -60,14 +65,24 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s window_render_program.set_uniform(inner_pattern_size_, "inner_pattern_size"); window_render_program.set_uniform(texture_regions_, "positions[0]"); + text_render_program.set_uniform(frame_texture_uniform_, "font_texture"); + // vec3 font color_uniform + // vec2 position + // windows window_pipeline_ = std::make_shared( window_render_program, render_setup ); + + text_pipeline_ = std::make_shared( + text_render_program, render_setup + ); } void -UserInterface::update([[maybe_unused]] screen_size_t width, [[maybe_unused]] screen_size_t height) { +UserInterface::update( + [[maybe_unused]] screen_size_t width, [[maybe_unused]] screen_size_t height +) { // cascade update frames using width and height FrameBufferHandler::instance().bind_fbo(0); // the screen @@ -164,6 +179,20 @@ UserInterface::render_frame( // widget->render_children(this, x_frame_position, y_frame_position); } +void +UserInterface::render_frame( + const TextWidget* widget, screen_size_t x_frame_position, + screen_size_t y_frame_position +) const { + const auto bounding_box = widget->get_bounding_box(); + + // set uniforms + text_pipeline_->render( + bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, + bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, widget + ); +} + std::pair, std::weak_ptr> UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const { diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 6ee7589f..b5a022a1 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -14,6 +14,7 @@ namespace the_buttons { class BorderedWidget; class BorderedWindow; class ButtonWidget; +class TextWidget; class UserInterface : public virtual scene::Inputs { private: @@ -28,6 +29,7 @@ class UserInterface : public virtual scene::Inputs { // widget renderer std::shared_ptr window_pipeline_; + std::shared_ptr text_pipeline_; std::list> frames_; @@ -68,23 +70,26 @@ class UserInterface : public virtual scene::Inputs { frames_.insert(pos, frame); } + // one of these for each void render_frame( const BorderedWindow* frame, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; - // one of these for each void render_frame( const BorderedWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; - // one of these for each void render_frame( const ButtonWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; + void render_frame( + const TextWidget* widget, screen_size_t x_frame_position, + screen_size_t y_frame_position + ) const; /** * @brief Handle key input including mouse keys diff --git a/src/gui/ui/imgui_style.cpp b/src/gui/ui/imgui_style.cpp index 16113b80..2095f8c1 100644 --- a/src/gui/ui/imgui_style.cpp +++ b/src/gui/ui/imgui_style.cpp @@ -76,8 +76,8 @@ set_imgui_style() { ImGuiIO& io = ImGui::GetIO(); - std::filesystem::path mono_font = - files::get_root_path() / "vendor" / "fonts" / "UbuntuMono" / "UbuntuMono-Regular.ttf"; + std::filesystem::path mono_font = files::get_root_path() / "vendor" / "fonts" + / "UbuntuMono" / "UbuntuMono-Regular.ttf"; // - If no fonts are loaded, dear imgui will use the default font. You can also load // multiple fonts and use ImGui::PushFont()/PopFont() to select them. diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index 28f01231..dfdb77ce 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -2,12 +2,13 @@ #include "../the_buttons/bordered_widget.hpp" #include "../the_buttons/bordered_window.hpp" +#include "../the_buttons/button_widget.hpp" +#include "../the_buttons/text_widget.hpp" #include "../the_buttons/user_interface.hpp" +#include "gui/render/structures/font.hpp" #include "gui/render/structures/window_texture.hpp" #include "util/files.hpp" #include "util/png_image.hpp" -#include "../the_buttons/button_widget.hpp" -#include "gui/render/structures/font.hpp" namespace gui { @@ -63,7 +64,6 @@ setup(the_buttons::UserInterface& user_interface) { } std::shared_ptr image_2 = image_result_2.value(); - std::shared_ptr a_widget = a_second_window->make( std::make_shared(image_2, texture_data_2.value()), @@ -71,8 +71,6 @@ setup(the_buttons::UserInterface& user_interface) { glm::ivec2(20, 20), glm::ivec2(180, 300) ); - - auto texture_data_3 = files::read_json_from_file( files::get_resources_path() / "textures" / "GenericButton.json" ); @@ -91,24 +89,27 @@ setup(the_buttons::UserInterface& user_interface) { } std::shared_ptr image_3 = image_result_3.value(); + auto a_button = a_widget->make( + std::make_shared(image_3, texture_data_3.value()), - auto a_button = - a_widget->make( - std::make_shared(image_3, texture_data_3.value()), - - glm::ivec2(20, 28), glm::ivec2(140, 80), - std::function([](){ - LOG_INFO(logging::main_logger, "Button Was Pressed"); - }) - ); - + glm::ivec2(20, 28), glm::ivec2(140, 80), std::function([]() { + LOG_INFO(logging::main_logger, "Button Was Pressed"); + }) + ); user_interface.add(a_window); user_interface.add(a_second_window); // window_pipeline->data.push_back(scene.a_window.get()); - auto my_font = render::structures::FontTexture(files::get_root_path() / "vendor" / "fonts" / "pixel_font" / "Pixelated_7_10.ttf"); + auto my_font = std::make_shared( + files::get_root_path() / "vendor" / "fonts" / "pixel_font" + / "Pixelated_7_10.ttf" + ); + + auto text_widget = a_widget->make( + my_font, glm::ivec2(20, 100), glm::ivec2(140, 140), "Hello World", true + ); return; } diff --git a/src/util/image.cpp b/src/util/image.cpp index 1436d8f3..6dc35a59 100644 --- a/src/util/image.cpp +++ b/src/util/image.cpp @@ -1,29 +1,24 @@ #include "image.hpp" #include "util/color.hpp" + #include namespace util { namespace image { +Image::Image(void* data, size_t width, size_t height, size_t data_size) : + width_(width), height_(height), data_size_(data_size), + data_(new char[width * height * data_size]) { + std::memcpy(data_.get(), data, width * height * data_size); +}; - Image::Image( - void* data, size_t width, size_t height, size_t data_size - ) : - width_(width), - height_(height), data_size_(data_size), data_(new char[width * height * data_size]){ - std::memcpy(data_.get(), data, width * height * data_size); - }; - - - Image::Image( - size_t width, size_t height, size_t data_size - ) : - width_(width), - height_(height), data_size_(data_size), data_(new char[width * height * data_size]) { - std::memset(data_.get(), char(0), width * height * data_size); - }; +Image::Image(size_t width, size_t height, size_t data_size) : + width_(width), height_(height), data_size_(data_size), + data_(new char[width * height * data_size]) { + std::memset(data_.get(), char(0), width * height * data_size); +}; png_byte FloatMonochromeImage::get_color(size_t i, size_t j) const { @@ -136,10 +131,12 @@ BytePolychromeAlphaImage::get_color(size_t i, size_t j) const { } void -ByteMonochromeImage::draw_at(const ByteMonochromeImage& other, size_t position_x, size_t position_y) { +ByteMonochromeImage::draw_at( + const ByteMonochromeImage& other, size_t position_x, size_t position_y +) { for (size_t i = 0; i < other.get_width(); i++) { for (size_t j = 0; j < other.get_height(); j++) { - set_color(other.get_color(i,j), i + position_x, j + position_y); + set_color(other.get_color(i, j), i + position_x, j + position_y); } } } diff --git a/src/util/image.hpp b/src/util/image.hpp index b01c09d1..2aa137a9 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -91,15 +91,9 @@ class Image { width_(width), height_(height), data_size_(data_size), data_(data){}; - Image( - void* data, size_t width, size_t height, size_t data_size - ); - - - Image( - size_t width, size_t height, size_t data_size - ); + Image(void* data, size_t width, size_t height, size_t data_size); + Image(size_t width, size_t height, size_t data_size); virtual ~Image() {} }; @@ -248,31 +242,28 @@ class ByteMonochromeImage : public virtual MonochromeImage { ); } - ByteMonochromeImage( - void* data, size_t width, size_t height, size_t data_size - ) : + ByteMonochromeImage(void* data, size_t width, size_t height, size_t data_size) : Image(data, width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" ); } - ByteMonochromeImage( - size_t width, size_t height, size_t data_size - ) : + ByteMonochromeImage(size_t width, size_t height, size_t data_size) : Image(width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" ); } - void draw_at(const ByteMonochromeImage& other, size_t position_x, size_t position_y); + void + draw_at(const ByteMonochromeImage& other, size_t position_x, size_t position_y); - void set_color(png_byte color, size_t i, size_t j) { + void + set_color(png_byte color, size_t i, size_t j) { reinterpret_cast(data_.get())[i * height_ + j] = color; } - inline virtual size_t get_width() const { return width_; @@ -301,18 +292,14 @@ class BytePolychromeImage : public virtual PolychromeImage { ); } - BytePolychromeImage( - void* data, size_t width, size_t height, size_t data_size - ) : + BytePolychromeImage(void* data, size_t width, size_t height, size_t data_size) : Image(data, width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" ); } - BytePolychromeImage( - size_t width, size_t height, size_t data_size - ) : + BytePolychromeImage(size_t width, size_t height, size_t data_size) : Image(width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" @@ -365,9 +352,7 @@ class BytePolychromeAlphaImage : public virtual PolychromeAlphaImage { ); } - BytePolychromeAlphaImage( - size_t width, size_t height, size_t data_size - ) : + BytePolychromeAlphaImage(size_t width, size_t height, size_t data_size) : Image(width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 59a55fa3..d46e460e 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -97,18 +97,20 @@ class ImageTest { namespace { template -auto to_array(std::array array) { +auto +to_array(std::array array) { return array; } template -auto to_array(T value) { +auto +to_array(T value) { return std::array({value}); } template [[nodiscard]] write_result_t -write_image_base(T image, const std::filesystem::path& path/*other settings*/) { +write_image_base(T image, const std::filesystem::path& path /*other settings*/) { // Keep track of if we succeeded or not write_result_t status = WR_OK; @@ -162,7 +164,7 @@ write_image_base(T image, const std::filesystem::path& path/*other settings*/) { if constexpr (n == 1) { color_type = PNG_COLOR_TYPE_GRAY; } else if constexpr (n == 3) { - color_type = PNG_COLOR_TYPE_RGB; + color_type = PNG_COLOR_TYPE_RGB; } else if constexpr (n == 4) { color_type = PNG_COLOR_TYPE_RGB_ALPHA; } else { @@ -171,8 +173,8 @@ write_image_base(T image, const std::filesystem::path& path/*other settings*/) { // set information about our image png_set_IHDR( - png_ptr, info_ptr, HEIGHT, WIDTH, 8, color_type, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT + png_ptr, info_ptr, HEIGHT, WIDTH, 8, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); // Set metadata about the PNG file @@ -198,7 +200,7 @@ write_image_base(T image, const std::filesystem::path& path/*other settings*/) { png_bytep row; // allocate data for row - row = new (std::nothrow) png_byte[n * WIDTH]; + row = new (std::nothrow) png_byte[n * HEIGHT]; if (!row) { status = WR_ROW_MALLOC_FAILED; goto row_malloc_failed; @@ -208,10 +210,8 @@ write_image_base(T image, const std::filesystem::path& path/*other settings*/) { for (i = 0; i < WIDTH; i++) { // set row data for (j = 0; j < HEIGHT; j++) { - const std::array pixel_color = to_array(image.get_color(i, j)); - for (unsigned int channel = 0; channel < n; channel ++) { - + for (unsigned int channel = 0; channel < n; channel++) { row[n * j + channel] = pixel_color[channel]; } } @@ -243,7 +243,7 @@ write_image_base(T image, const std::filesystem::path& path/*other settings*/) { return status; } -} +} // namespace template [[nodiscard]] write_result_t From aab95cb95e5f7444651e145e54a2f939831a97ae Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Mon, 29 Dec 2025 18:24:09 -0500 Subject: [PATCH 27/56] add frame size uniform --- resources/shaders/overlay/TextWindow.vert | 4 ++-- src/gui/the_buttons/text_widget.cpp | 8 ++++---- src/gui/the_buttons/user_interface.cpp | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/resources/shaders/overlay/TextWindow.vert b/resources/shaders/overlay/TextWindow.vert index 217fe3cb..48d7d7c9 100644 --- a/resources/shaders/overlay/TextWindow.vert +++ b/resources/shaders/overlay/TextWindow.vert @@ -6,7 +6,7 @@ layout(location = 0) in ivec4 pos; // this is the size of the view // then switch to division -//uniform vec2 projection_matrix; +uniform ivec2 frame_size; // Output data ; will be interpolated for each fragment. out vec2 UV; @@ -16,7 +16,7 @@ main() { //vec2 projection_matrix = vec2(1/250, 1/250); - gl_Position = vec4( (pos.xy - 100) / 150, 1, 1); + gl_Position = vec4( 2 * pos.xy / vec2(frame_size) - 1, 1, 1); UV = pos.zw; } diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index eaf503fa..ea9768d9 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -8,10 +8,10 @@ void TextWidget::update_text_data(bool differed) { std::vector data; - data.push_back(glm::ivec4(100, 100, 100, 15)); - data.push_back(glm::ivec4(100, 250, 100, 0)); - data.push_back(glm::ivec4(250, 100, 115, 15)); - data.push_back(glm::ivec4(250, 250, 115, 0)); + data.push_back(glm::ivec4(10, 10, 100, 15)); + data.push_back(glm::ivec4(10, 40, 100, 0)); + data.push_back(glm::ivec4(110, 10, 115, 15)); + data.push_back(glm::ivec4(110, 40, 115, 0)); text_data_.insert(data, 0, text_data_.size()); } diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 880e9d44..6531975c 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -65,6 +65,7 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s window_render_program.set_uniform(inner_pattern_size_, "inner_pattern_size"); window_render_program.set_uniform(texture_regions_, "positions[0]"); + text_render_program.set_uniform(frame_size_uniform_, "frame_size"); text_render_program.set_uniform(frame_texture_uniform_, "font_texture"); // vec3 font color_uniform // vec2 position @@ -186,6 +187,11 @@ UserInterface::render_frame( ) const { const auto bounding_box = widget->get_bounding_box(); + + frame_size_uniform_->set_frame_size( + glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) + ); + // set uniforms text_pipeline_->render( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, From 6a36324206585913ab13136d8922b38aa78a987a Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Mon, 29 Dec 2025 18:27:43 -0500 Subject: [PATCH 28/56] add ui scale --- resources/shaders/overlay/TextWindow.vert | 3 ++- src/gui/the_buttons/text_widget.cpp | 8 ++++---- src/gui/the_buttons/user_interface.cpp | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/resources/shaders/overlay/TextWindow.vert b/resources/shaders/overlay/TextWindow.vert index 48d7d7c9..8007a971 100644 --- a/resources/shaders/overlay/TextWindow.vert +++ b/resources/shaders/overlay/TextWindow.vert @@ -7,6 +7,7 @@ layout(location = 0) in ivec4 pos; // this is the size of the view // then switch to division uniform ivec2 frame_size; +uniform int ui_scale; // Output data ; will be interpolated for each fragment. out vec2 UV; @@ -16,7 +17,7 @@ main() { //vec2 projection_matrix = vec2(1/250, 1/250); - gl_Position = vec4( 2 * pos.xy / vec2(frame_size) - 1, 1, 1); + gl_Position = vec4(ui_scale * 2 * pos.xy / vec2(frame_size) - 1, 1, 1); UV = pos.zw; } diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index ea9768d9..799e0f77 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -8,10 +8,10 @@ void TextWidget::update_text_data(bool differed) { std::vector data; - data.push_back(glm::ivec4(10, 10, 100, 15)); - data.push_back(glm::ivec4(10, 40, 100, 0)); - data.push_back(glm::ivec4(110, 10, 115, 15)); - data.push_back(glm::ivec4(110, 40, 115, 0)); + data.push_back(glm::ivec4(2, 2, 100, 15)); + data.push_back(glm::ivec4(2, 10, 100, 0)); + data.push_back(glm::ivec4(28, 2, 115, 15)); + data.push_back(glm::ivec4(28, 10, 115, 0)); text_data_.insert(data, 0, text_data_.size()); } diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 6531975c..23b44233 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -66,6 +66,7 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s window_render_program.set_uniform(texture_regions_, "positions[0]"); text_render_program.set_uniform(frame_size_uniform_, "frame_size"); + text_render_program.set_uniform(ui_scale_uniform_, "ui_scale"); text_render_program.set_uniform(frame_texture_uniform_, "font_texture"); // vec3 font color_uniform // vec2 position @@ -191,7 +192,7 @@ UserInterface::render_frame( frame_size_uniform_->set_frame_size( glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) ); - + // set uniforms text_pipeline_->render( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, From d79418488c06c3e4d50aef855d075859ab7febfb Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 30 Dec 2025 12:58:53 -0500 Subject: [PATCH 29/56] generate text spacing --- resources/shaders/overlay/TextWindow.vert | 2 +- src/gui/render/structures/font.hpp | 9 +++++ src/gui/the_buttons/text_widget.cpp | 49 ++++++++++++++++++++--- src/gui/the_buttons/text_widget.hpp | 2 + src/gui/ui/user_interface_setup.cpp | 2 +- 5 files changed, 57 insertions(+), 7 deletions(-) diff --git a/resources/shaders/overlay/TextWindow.vert b/resources/shaders/overlay/TextWindow.vert index 8007a971..dc5a8243 100644 --- a/resources/shaders/overlay/TextWindow.vert +++ b/resources/shaders/overlay/TextWindow.vert @@ -17,7 +17,7 @@ main() { //vec2 projection_matrix = vec2(1/250, 1/250); - gl_Position = vec4(ui_scale * 2 * pos.xy / vec2(frame_size) - 1, 1, 1); + gl_Position = vec4(ui_scale * 2 * (vec2(pos.xy) / vec2(frame_size)) - 1, 1, 1); UV = pos.zw; } diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index ff92c4fe..2f4d9870 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -31,6 +31,15 @@ class FontTexture { bind(GLuint texture_index) const { texture_->bind(texture_index); } + + [[nodiscard]] inline const Character* get_character(char character) const { + const auto data = font_textures_.find(character); + if (data != font_textures_.end()) { + return &data->second; + } else { + return nullptr; + } + } }; } // namespace structures diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index 799e0f77..8d395e3b 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -6,12 +6,14 @@ namespace gui { namespace the_buttons { void TextWidget::update_text_data(bool differed) { - std::vector data; - data.push_back(glm::ivec4(2, 2, 100, 15)); - data.push_back(glm::ivec4(2, 10, 100, 0)); - data.push_back(glm::ivec4(28, 2, 115, 15)); - data.push_back(glm::ivec4(28, 10, 115, 0)); + + std::vector data = generate_data(); + + // data.push_back(glm::ivec4(2, 2, 100, 15)); + // data.push_back(glm::ivec4(2, 10, 100, 0)); + // data.push_back(glm::ivec4(28, 2, 115, 15)); + // data.push_back(glm::ivec4(28, 10, 115, 0)); text_data_.insert(data, 0, text_data_.size()); } @@ -35,5 +37,42 @@ TextWidget::initialize() { attach_all(); vertex_array_object_.release(); } + +std::vector TextWidget::generate_data() const { + std::vector data; + + int advance = 0; + + int line_spacing = 25; // eed to read this from the font + int line_advance = line_spacing; + + for (char character : text_) { + const render::structures::Character* character_data = font_->get_character(character); + if (! character_data) { + LOG_WARNING(logging::main_logger, "Could not find character \"{}\" with value \"{}\" in font. Required for string \"{}\".", + std::string(1, character), static_cast(character), text_); + } + + //if (advance + character_data->advance > frame width or character is new_line) { advance = 0; line_advance += line_spacing} + + glm::ivec4 position_in_texture = character_data->position_in_texture; + + glm::ivec2 bearing = character_data->bearing; + glm::ivec2 size = character_data->size; + + data.push_back(glm::ivec4(bearing.x, line_advance - bearing.y + size.y, position_in_texture.x, position_in_texture.z)); + data.push_back(glm::ivec4(bearing.x, line_advance - bearing.y, position_in_texture.x, position_in_texture.w)); + data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y + size.y, position_in_texture.y, position_in_texture.z)); + data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y, position_in_texture.y, position_in_texture.w)); + + + advance += character_data->advance; + } + + return data; +} + + } // namespace the_buttons + } // namespace gui diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index 90da3ace..a820b553 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -107,6 +107,8 @@ class TextWidget : public virtual WidgetBase { const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position ) const override; + + [[nodiscard]] std::vector generate_data() const; }; } // namespace the_buttons diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index dfdb77ce..bd75ac87 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -108,7 +108,7 @@ setup(the_buttons::UserInterface& user_interface) { ); auto text_widget = a_widget->make( - my_font, glm::ivec2(20, 100), glm::ivec2(140, 140), "Hello World", true + my_font, glm::ivec2(20, 100), glm::ivec2(140, 240), "Hello World", true ); return; From 2205028ef53c07935e8208ccb34fd5aff02dfb4b Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 30 Dec 2025 19:43:17 -0500 Subject: [PATCH 30/56] fix image orientation --- resources/shaders/overlay/TextWindow.frag | 21 ++++++++++++--------- src/gui/render/structures/font.cpp | 10 +++++----- src/gui/the_buttons/frame_part.hpp | 5 +++-- src/gui/the_buttons/text_widget.cpp | 6 +++--- src/gui/the_buttons/text_widget.hpp | 1 + src/gui/the_buttons/user_interface.cpp | 1 + src/gui/the_buttons/user_interface.hpp | 1 + src/util/png_image.hpp | 10 +++++----- 8 files changed, 31 insertions(+), 24 deletions(-) diff --git a/resources/shaders/overlay/TextWindow.frag b/resources/shaders/overlay/TextWindow.frag index 36c912c2..18a10db3 100644 --- a/resources/shaders/overlay/TextWindow.frag +++ b/resources/shaders/overlay/TextWindow.frag @@ -4,20 +4,23 @@ // Ouput data layout(location = 0) out vec3 color; -uniform sampler2D texture_id; +uniform usampler2D font_texture; //uniform vec3 font_color; in vec2 UV; void main() { - color = vec3(0.6,0.2,0.1); - // vec3 font_color = vec3(0,0,0); + //color = vec3(0.6,0.2,0.1); + vec3 font_color = vec3(0.6,0.2,0.1); - // float alpha = texture(texture_id, UV).a; - // if (alpha > 0) { - // color = font_color; - // } else { - // discard; - // } + //float alpha = texture(font_texture, UV).a; + uint alpha = texelFetch(font_texture, ivec2(UV), 0).r; +// uint alpha = texelFetch(font_texture, , 0).r; + + if (alpha > 0) { + color = font_color; + } else { + discard; + } } diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 42cf3f43..6c04c699 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -81,7 +81,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { .buffer[j * font_face->glyph->bitmap.pitch + i / 8]; uint8_t one = 1; uint8_t value = font_bit >> (7 - i % 8); - data[j * font_face->glyph->bitmap.width + i] = (value & one) * 255; + data[i * font_face->glyph->bitmap.rows + j] = (value & one) * 255; } } // if (c == 'a' || c == 'b') { @@ -90,7 +90,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { images.emplace( c, util::image::ByteMonochromeImage( - data.data(), char_size.y, char_size.x, sizeof(char) + data.data(), char_size.x, char_size.y, sizeof(char) ) ); @@ -116,13 +116,13 @@ FontTexture::FontTexture(std::filesystem::path font_file) { // std::shared_ptr image(new char[max_height * total_width]); auto image = std::make_shared( - max_height, total_width, sizeof(char) + total_width, max_height, sizeof(char) ); for (unsigned char c = 0; c < 128; c++) { image->draw_at( - images.at(c), font_textures_[c].position_in_texture.y, - font_textures_[c].position_in_texture.x + images.at(c), font_textures_[c].position_in_texture.x, + font_textures_[c].position_in_texture.y ); } diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index 568575a0..c3507154 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -18,9 +18,10 @@ class WidgetBase : public virtual WidgetInterface { std::vector exterior_points_; std::unordered_set> children; - void exterior_changed(); // need to change exterior for parent. - + bool is_selected; + + void exterior_changed(); // need to change exterior for parent. public: WidgetBase( diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index 8d395e3b..238e3a79 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -60,10 +60,10 @@ std::vector TextWidget::generate_data() const { glm::ivec2 bearing = character_data->bearing; glm::ivec2 size = character_data->size; - data.push_back(glm::ivec4(bearing.x, line_advance - bearing.y + size.y, position_in_texture.x, position_in_texture.z)); + data.push_back(glm::ivec4(bearing.x, line_advance - bearing.y + size.y, position_in_texture.x, position_in_texture.y)); data.push_back(glm::ivec4(bearing.x, line_advance - bearing.y, position_in_texture.x, position_in_texture.w)); - data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y + size.y, position_in_texture.y, position_in_texture.z)); - data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y, position_in_texture.y, position_in_texture.w)); + data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y + size.y, position_in_texture.z, position_in_texture.y)); + data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y, position_in_texture.z, position_in_texture.w)); advance += character_data->advance; diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index a820b553..ed4df33b 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -90,6 +90,7 @@ class TextWidget : public virtual WidgetBase { inline virtual void bind() const { // text_data_.attach_to_vertex_attribute(0); + font_->bind(0); vertex_array_object_.bind(); }; diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 23b44233..b2d5a06c 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -189,6 +189,7 @@ UserInterface::render_frame( const auto bounding_box = widget->get_bounding_box(); + frame_size_uniform_->set_frame_size( glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) ); diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index b5a022a1..6c6df884 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -26,6 +26,7 @@ class UserInterface : public virtual scene::Inputs { std::shared_ptr side_lengths_; std::shared_ptr inner_pattern_size_; std::shared_ptr texture_regions_; +// std::shared_ptr font_texture_uniform_; // widget renderer std::shared_ptr window_pipeline_; diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index d46e460e..605d06bc 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -173,7 +173,7 @@ write_image_base(T image, const std::filesystem::path& path /*other settings*/) // set information about our image png_set_IHDR( - png_ptr, info_ptr, HEIGHT, WIDTH, 8, color_type, PNG_INTERLACE_NONE, + png_ptr, info_ptr, WIDTH, HEIGHT, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); @@ -200,17 +200,17 @@ write_image_base(T image, const std::filesystem::path& path /*other settings*/) png_bytep row; // allocate data for row - row = new (std::nothrow) png_byte[n * HEIGHT]; + row = new (std::nothrow) png_byte[n * WIDTH]; if (!row) { status = WR_ROW_MALLOC_FAILED; goto row_malloc_failed; } // write row data - for (i = 0; i < WIDTH; i++) { + for (i = 0; i < HEIGHT; i++) { // set row data - for (j = 0; j < HEIGHT; j++) { - const std::array pixel_color = to_array(image.get_color(i, j)); + for (j = 0; j < WIDTH; j++) { + const std::array pixel_color = to_array(image.get_color(j, i)); for (unsigned int channel = 0; channel < n; channel++) { row[n * j + channel] = pixel_color[channel]; } From ac139e50ea515aa49310fb32d68b43efe12c1ffd Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 7 Jan 2026 18:32:33 -0500 Subject: [PATCH 31/56] transpose data for gpu --- resources/shaders/overlay/TextWindow.frag | 3 +- resources/shaders/overlay/TextWindow.vert | 3 +- src/gui/render/gl_enums.hpp | 2 + src/gui/render/gpu_data/texture.cpp | 91 +++++++++++++++++++++++ src/gui/render/gpu_data/texture.hpp | 2 + src/gui/render/structures/font.cpp | 16 ++++ src/gui/render/structures/font.hpp | 3 +- src/gui/the_buttons/frame_part.hpp | 4 +- src/gui/the_buttons/text_widget.cpp | 43 +++++++---- src/gui/the_buttons/user_interface.cpp | 2 - src/gui/the_buttons/user_interface.hpp | 2 +- src/util/image.hpp | 6 ++ 12 files changed, 154 insertions(+), 23 deletions(-) diff --git a/resources/shaders/overlay/TextWindow.frag b/resources/shaders/overlay/TextWindow.frag index 18a10db3..22a0e9b7 100644 --- a/resources/shaders/overlay/TextWindow.frag +++ b/resources/shaders/overlay/TextWindow.frag @@ -14,9 +14,8 @@ main() { //color = vec3(0.6,0.2,0.1); vec3 font_color = vec3(0.6,0.2,0.1); - //float alpha = texture(font_texture, UV).a; uint alpha = texelFetch(font_texture, ivec2(UV), 0).r; -// uint alpha = texelFetch(font_texture, , 0).r; + //uint alpha = texelFetch(font_texture, ivec2(13, 0), 0).r; if (alpha > 0) { color = font_color; diff --git a/resources/shaders/overlay/TextWindow.vert b/resources/shaders/overlay/TextWindow.vert index dc5a8243..626096f1 100644 --- a/resources/shaders/overlay/TextWindow.vert +++ b/resources/shaders/overlay/TextWindow.vert @@ -18,6 +18,7 @@ main() { //vec2 projection_matrix = vec2(1/250, 1/250); gl_Position = vec4(ui_scale * 2 * (vec2(pos.xy) / vec2(frame_size)) - 1, 1, 1); - UV = pos.zw; + UV = vec2(pos.w, pos.z); + //UV = vec2((pos.z - 304) * 20, pos.w * 2); } diff --git a/src/gui/render/gl_enums.hpp b/src/gui/render/gl_enums.hpp index 7aa382a4..9f6d8356 100644 --- a/src/gui/render/gl_enums.hpp +++ b/src/gui/render/gl_enums.hpp @@ -648,6 +648,8 @@ get_size(const GPUPixelType type) { return 4; case GPUPixelType::HALF_FLOAT: return 2; + case GPUPixelType::UNSIGNED_BYTE: + return 1; default: LOG_CRITICAL( logging::opengl_logger, diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index f590ede6..f1218804 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -172,6 +172,97 @@ Texture2D::load_data(std::shared_ptr image) { } } +std::shared_ptr +Texture2D::get_image() const { + // width_ + // height_ + + std::shared_ptr data = std::make_shared( + width_ * height_ * get_size(settings_.type) * get_size(settings_.read_format) + ); + + if (settings_.multisample) { + LOG_ERROR(logging::opengl_logger, "Cannot load multisample texture to image."); + return nullptr; + } + glBindTexture(GL_TEXTURE_2D, texture_ID_); + + glGetTexImage( + GL_TEXTURE_2D, 0, static_cast(settings_.read_format), + static_cast(settings_.type), data.get() + ); + + switch (settings_.type) { + case GPUPixelType::FLOAT: + case GPUPixelType::HALF_FLOAT: + switch (settings_.read_format) { + case GPUPixelReadFormat::DEPTH_COMPONENT: + case GPUPixelReadFormat::DEPTH_STENCIL: + case GPUPixelReadFormat::RED: + case GPUPixelReadFormat::GREEN: + case GPUPixelReadFormat::BLUE: + return std::make_shared( + data, width_, height_, get_size(settings_.type) + ); + case GPUPixelReadFormat::RGB: + case GPUPixelReadFormat::BGR: + return std::make_shared( + data, width_, height_, get_size(settings_.type) + ); + + case GPUPixelReadFormat::RGBA: + case GPUPixelReadFormat::BGRA: + return std::make_shared( + data, width_, height_, get_size(settings_.type) + ); + + default: + LOG_ERROR( + logging::opengl_logger, + "Cannot load image. Unknown read_format {}.", + static_cast(settings_.read_format) + ); + return nullptr; + } + case GPUPixelType::UNSIGNED_BYTE: + switch (settings_.read_format) { + case GPUPixelReadFormat::DEPTH_COMPONENT: + case GPUPixelReadFormat::DEPTH_STENCIL: + case GPUPixelReadFormat::RED: + case GPUPixelReadFormat::GREEN: + case GPUPixelReadFormat::BLUE: + return std::make_shared( + data, width_, height_, get_size(settings_.type) + ); + case GPUPixelReadFormat::RGB: + case GPUPixelReadFormat::BGR: + return std::make_shared( + data, width_, height_, get_size(settings_.type) + ); + + case GPUPixelReadFormat::RGBA: + case GPUPixelReadFormat::BGRA: + return std::make_shared( + data, width_, height_, get_size(settings_.type) + ); + + default: + LOG_ERROR( + logging::opengl_logger, + "Cannot load image. Unknown read_format {}.", + static_cast(settings_.read_format) + ); + return nullptr; + } + default: + LOG_ERROR( + logging::opengl_logger, "Cannot load image. Unknown type {}.", + static_cast(settings_.type) + ); + return nullptr; + } +} + } // namespace gpu_data } // namespace gui diff --git a/src/gui/render/gpu_data/texture.hpp b/src/gui/render/gpu_data/texture.hpp index 16cd629e..a7302ee4 100644 --- a/src/gui/render/gpu_data/texture.hpp +++ b/src/gui/render/gpu_data/texture.hpp @@ -138,6 +138,8 @@ class Texture2D : virtual public GPUDataRenderBuffer { settings_.multisample ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; glBindTexture(target, texture_ID_); } + + [[nodiscard]] std::shared_ptr get_image() const; }; } // namespace gpu_data diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 6c04c699..9c1ff0f9 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -128,7 +128,23 @@ FontTexture::FontTexture(std::filesystem::path font_file) { LOG_DEBUG(logging::main_logger, "saving fonts to file."); image::write_image(*image, files::get_log_path() / "font_as_image.png"); + image->transpose(); texture_ = std::make_shared(image, settings); + + GlobalContext& global_context = GlobalContext::instance(); + global_context.run_opengl_queue(); + + auto font_image_from_gpu = texture_->get_image(); + + if (auto font_image_from_gpu_typed = + std::dynamic_pointer_cast( + font_image_from_gpu + )) { + font_image_from_gpu_typed->transpose(); + image::write_image( + *font_image_from_gpu_typed, files::get_log_path() / "font_as_image_from_texture.png" + ); + } } } // namespace structures diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index 2f4d9870..04cad53f 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -32,7 +32,8 @@ class FontTexture { texture_->bind(texture_index); } - [[nodiscard]] inline const Character* get_character(char character) const { + [[nodiscard]] inline const Character* + get_character(char character) const { const auto data = font_textures_.find(character); if (data != font_textures_.end()) { return &data->second; diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index c3507154..a20b07db 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -18,9 +18,9 @@ class WidgetBase : public virtual WidgetInterface { std::vector exterior_points_; std::unordered_set> children; - + bool is_selected; - + void exterior_changed(); // need to change exterior for parent. public: diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index 238e3a79..bb46aa40 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -6,8 +6,6 @@ namespace gui { namespace the_buttons { void TextWidget::update_text_data(bool differed) { - - std::vector data = generate_data(); // data.push_back(glm::ivec4(2, 2, 100, 15)); @@ -38,7 +36,8 @@ TextWidget::initialize() { vertex_array_object_.release(); } -std::vector TextWidget::generate_data() const { +std::vector +TextWidget::generate_data() const { std::vector data; int advance = 0; @@ -47,24 +46,41 @@ std::vector TextWidget::generate_data() const { int line_advance = line_spacing; for (char character : text_) { - const render::structures::Character* character_data = font_->get_character(character); - if (! character_data) { - LOG_WARNING(logging::main_logger, "Could not find character \"{}\" with value \"{}\" in font. Required for string \"{}\".", - std::string(1, character), static_cast(character), text_); + const render::structures::Character* character_data = + font_->get_character(character); + if (!character_data) { + LOG_WARNING( + logging::main_logger, + "Could not find character \"{}\" with value \"{}\" in font. Required " + "for string \"{}\".", + std::string(1, character), static_cast(character), text_ + ); } - //if (advance + character_data->advance > frame width or character is new_line) { advance = 0; line_advance += line_spacing} + // if (advance + character_data->advance > frame width or character is new_line) + // { advance = 0; line_advance += line_spacing} glm::ivec4 position_in_texture = character_data->position_in_texture; glm::ivec2 bearing = character_data->bearing; glm::ivec2 size = character_data->size; - data.push_back(glm::ivec4(bearing.x, line_advance - bearing.y + size.y, position_in_texture.x, position_in_texture.y)); - data.push_back(glm::ivec4(bearing.x, line_advance - bearing.y, position_in_texture.x, position_in_texture.w)); - data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y + size.y, position_in_texture.z, position_in_texture.y)); - data.push_back(glm::ivec4(bearing.x + size.x, line_advance - bearing.y, position_in_texture.z, position_in_texture.w)); - + data.push_back(glm::ivec4( + bearing.x, line_advance - bearing.y + size.y, position_in_texture.x, + position_in_texture.y + )); + data.push_back(glm::ivec4( + bearing.x, line_advance - bearing.y, position_in_texture.x, + position_in_texture.w + )); + data.push_back(glm::ivec4( + bearing.x + size.x, line_advance - bearing.y + size.y, + position_in_texture.z, position_in_texture.y + )); + data.push_back(glm::ivec4( + bearing.x + size.x, line_advance - bearing.y, position_in_texture.z, + position_in_texture.w + )); advance += character_data->advance; } @@ -72,7 +88,6 @@ std::vector TextWidget::generate_data() const { return data; } - } // namespace the_buttons } // namespace gui diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index b2d5a06c..641a3cbe 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -188,8 +188,6 @@ UserInterface::render_frame( ) const { const auto bounding_box = widget->get_bounding_box(); - - frame_size_uniform_->set_frame_size( glm::ivec2(bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1]) ); diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 6c6df884..0178eb96 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -26,7 +26,7 @@ class UserInterface : public virtual scene::Inputs { std::shared_ptr side_lengths_; std::shared_ptr inner_pattern_size_; std::shared_ptr texture_regions_; -// std::shared_ptr font_texture_uniform_; + // std::shared_ptr font_texture_uniform_; // widget renderer std::shared_ptr window_pipeline_; diff --git a/src/util/image.hpp b/src/util/image.hpp index 2aa137a9..1ff3ddd5 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -264,6 +264,12 @@ class ByteMonochromeImage : public virtual MonochromeImage { reinterpret_cast(data_.get())[i * height_ + j] = color; } + inline void transpose() { + auto temp = width_; + width_ = height_; + height_ = temp; + } + inline virtual size_t get_width() const { return width_; From ec7a610602eea3f0bcd8810f7ab4398f8698ebdb Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 7 Jan 2026 19:00:43 -0500 Subject: [PATCH 32/56] remove write image call and refactor --- src/gui/render/structures/font.cpp | 23 ++++++++++++++++++----- src/gui/scene/controls.cpp | 4 ++-- src/gui/the_buttons/text_widget.cpp | 8 ++++++++ src/util/image.hpp | 3 ++- src/world/object/entity/entity.cpp | 4 +++- src/world/object/entity_controller.cpp | 2 +- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 9c1ff0f9..80ca52af 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -127,24 +127,37 @@ FontTexture::FontTexture(std::filesystem::path font_file) { } LOG_DEBUG(logging::main_logger, "saving fonts to file."); - image::write_image(*image, files::get_log_path() / "font_as_image.png"); +/* auto result_1 = + image::write_image(*image, files::get_log_path() / "font_as_image.png"); + if (result_1 != image::write_result_t::WR_OK) { + image::log_result(result_1, files::get_log_path() / "font_as_image.png"); + }*/ + image->transpose(); texture_ = std::make_shared(image, settings); GlobalContext& global_context = GlobalContext::instance(); global_context.run_opengl_queue(); + /* auto font_image_from_gpu = texture_->get_image(); - + if (auto font_image_from_gpu_typed = std::dynamic_pointer_cast( font_image_from_gpu )) { - font_image_from_gpu_typed->transpose(); - image::write_image( - *font_image_from_gpu_typed, files::get_log_path() / "font_as_image_from_texture.png" + font_image_from_gpu_typed->transpose(); + auto result_2 = image::write_image( + *font_image_from_gpu_typed, + files::get_log_path() / "font_as_image_from_texture.png" ); + if (result_2 != image::write_result_t::WR_OK) { + image::log_result( + result_2, files::get_log_path() / "font_as_image_from_texture.png" + ); + } } + */ } } // namespace structures diff --git a/src/gui/scene/controls.cpp b/src/gui/scene/controls.cpp index 53711eb1..df58995f 100644 --- a/src/gui/scene/controls.cpp +++ b/src/gui/scene/controls.cpp @@ -125,8 +125,8 @@ Controls::handle_mouse_button_input( double ypos; glfwGetCursorPos(window, &xpos, &ypos); LOG_DEBUG(logging::main_logger, "Mouse Position: [{}, {}]", xpos, ypos); - int xpos_int = floor(xpos); - int ypos_int = floor(ypos); + // int xpos_int = floor(xpos); + // int ypos_int = floor(ypos); } } diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index bb46aa40..a8d6c9dc 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -1,11 +1,19 @@ #include "text_widget.hpp" +#include "global_context.hpp" #include "user_interface.hpp" namespace gui { namespace the_buttons { void TextWidget::update_text_data(bool differed) { + if (differed) { + GlobalContext& context = GlobalContext::instance(); + context.submit_task([this]() { + std::vector data = generate_data(); + text_data_.insert(data, 0, text_data_.size()); + }); + } std::vector data = generate_data(); // data.push_back(glm::ivec4(2, 2, 100, 15)); diff --git a/src/util/image.hpp b/src/util/image.hpp index 1ff3ddd5..606eb81d 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -264,7 +264,8 @@ class ByteMonochromeImage : public virtual MonochromeImage { reinterpret_cast(data_.get())[i * height_ + j] = color; } - inline void transpose() { + inline void + transpose() { auto temp = width_; width_ = height_; height_ = temp; diff --git a/src/world/object/entity/entity.cpp b/src/world/object/entity/entity.cpp index f03c94e2..87bbbd82 100644 --- a/src/world/object/entity/entity.cpp +++ b/src/world/object/entity/entity.cpp @@ -127,7 +127,9 @@ EntityInstance::EntityInstance(std::shared_ptr entity_type) : EntityInstance::~EntityInstance() {} void -EntityInstance::operate(std::chrono::milliseconds delta_time, bool show) { +EntityInstance::operate( + [[maybe_unused]] std::chrono::milliseconds delta_time, bool show +) { if (std::shared_ptr entity_type = entity_type_.lock()) { glm::vec3 position = entity_type->decision(this); position_ = position; diff --git a/src/world/object/entity_controller.cpp b/src/world/object/entity_controller.cpp index c0711a11..2d8dc994 100644 --- a/src/world/object/entity_controller.cpp +++ b/src/world/object/entity_controller.cpp @@ -10,7 +10,7 @@ namespace object { // then check that update entities is correctly called. void -EntityController::update_entities(glm::mat4 transforms_matrix) { +EntityController::update_entities([[maybe_unused]] glm::mat4 transforms_matrix) { // maybe multi-processes for (auto& region : entity_instances_) { if (true) { From 3d028478a41f05a1cea2b3023ec87b928a2efdf1 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 10 Jan 2026 19:05:50 -0500 Subject: [PATCH 33/56] fixes to memory errors --- CMakeLists.txt | 5 +++++ src/graphics_main.cpp | 9 +++++++-- src/gui/render/gpu_data/texture.cpp | 27 ++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 145269ec..3be40704 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,11 @@ endif() if(CMAKE_BUILD_TYPE MATCHES Debug) set(DEBUG 1) message(" Debug build, data will be loaded from repo root ") +# TODO +# This NEEDS to be committed into main but it breaks some (4) tests +# checks memory leaks +# target_compile_options(FunGame PUBLIC -fsanitize=address) +# target_link_options(FunGame PUBLIC -fsanitize=address) else() set(DEBUG 0) message(" Debug build, data will be loaded from subdirs ") diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index 0ad30d81..4c784d5f 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -86,7 +86,8 @@ graphics_main(intro_scene::result result) { while (true) { switch (result.index()) { case 0: // exiting - return std::get(result).status; + goto exit; + break; case 1: // intro page result = intro_window(window); break; @@ -109,9 +110,13 @@ graphics_main(intro_scene::result result) { break; } } +exit: + gui::scene::InputHandler::forward_inputs_to(nullptr); // this removes an object from static storage + GlobalContext& context = GlobalContext::instance(); + context.run_opengl_queue(); // this should clean up anything left in the queue glDeleteVertexArrays(1, &VertexArrayID); - return 1; + return std::get(result).status; } intro_scene::result diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index f1218804..d728cac3 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -174,11 +174,12 @@ Texture2D::load_data(std::shared_ptr image) { std::shared_ptr Texture2D::get_image() const { - // width_ - // height_ + // multiplying by 2 fixes the memory error, but that can't possibly be correct. + // TODO needs more investigation + size_t data_size = width_ * height_ * get_size(settings_.type) * get_size(settings_.read_format) * 2; std::shared_ptr data = std::make_shared( - width_ * height_ * get_size(settings_.type) * get_size(settings_.read_format) + data_size ); if (settings_.multisample) { @@ -187,6 +188,26 @@ Texture2D::get_image() const { } glBindTexture(GL_TEXTURE_2D, texture_ID_); +#if DEBUG() + int width; + int height; + int opengl_type; + + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &opengl_type); + + if (width != width_ || height != height_) { + LOG_WARNING(logging::opengl_logger, "Width or Height don't match correct value. Actual {}, {}, Saved {}, {}.", width, height, width_, height_); + } + + if (gui::gpu_data::GPUPixelStorageFormat(opengl_type) != settings_.internal_format ) { + LOG_WARNING(logging::opengl_logger, "Type sizes don't match. Actual {}, Given {}.", + get_size(gui::gpu_data::GPUPixelStorageFormat(opengl_type)), get_size(settings_.internal_format)); + } + +#endif + glGetTexImage( GL_TEXTURE_2D, 0, static_cast(settings_.read_format), static_cast(settings_.type), data.get() From 6010b0d44d0c2a16cdaff67f2247b729b1204dbf Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Mon, 12 Jan 2026 16:58:00 -0500 Subject: [PATCH 34/56] fixed some memory errors --- src/gui/render/gpu_data/texture.cpp | 2 +- src/gui/scene/input.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index d728cac3..b1556b22 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -175,7 +175,7 @@ Texture2D::load_data(std::shared_ptr image) { std::shared_ptr Texture2D::get_image() const { // multiplying by 2 fixes the memory error, but that can't possibly be correct. - // TODO needs more investigation + // TODO GL_PACK_ALIGNMENT size_t data_size = width_ * height_ * get_size(settings_.type) * get_size(settings_.read_format) * 2; std::shared_ptr data = std::make_shared( diff --git a/src/gui/scene/input.cpp b/src/gui/scene/input.cpp index 2e379d54..01150a02 100644 --- a/src/gui/scene/input.cpp +++ b/src/gui/scene/input.cpp @@ -38,7 +38,6 @@ InputHandler::forward_inputs_to(std::shared_ptr forward_to) { if (forward_to == nullptr) { // somehow prevent forwarding // this is ostensibly not a good idea - assert(forward_to != nullptr && "Must forward inputs to valid Inputs object."); } else { forward_inputs_->setup(window_); } @@ -75,6 +74,7 @@ InputHandler::handle_key_event( escape_pressed_ = false; } } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_key_event_input(window, key, scancode, action, mods); } @@ -83,6 +83,7 @@ InputHandler::handle_text_input(GLFWwindow* window, unsigned int codepoint) { if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_text_input_input(window, codepoint); } @@ -91,6 +92,7 @@ InputHandler::handle_mouse_event(GLFWwindow* window, double xpos, double ypos) { if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_mouse_event_input(window, xpos, ypos); } @@ -99,6 +101,7 @@ InputHandler::handle_mouse_enter(GLFWwindow* window, int enter) { if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_mouse_enter_input(window, enter); } @@ -109,6 +112,7 @@ InputHandler::handle_mouse_button( if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_mouse_button_input(window, button, action, mods); } @@ -117,6 +121,7 @@ InputHandler::handle_mouse_scroll(GLFWwindow* window, double xoffset, double yof if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_mouse_scroll_input(window, xoffset, yoffset); } @@ -125,6 +130,7 @@ InputHandler::handle_joystick(int jid, int event) { if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_joystick_input(jid, event); } @@ -133,6 +139,7 @@ InputHandler::handle_file_drop(GLFWwindow* window, int count, const char** paths if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_file_drop_input(window, count, paths); } @@ -141,6 +148,7 @@ InputHandler::handle_pooled_inputs(GLFWwindow* window) { if (imgui_capture()) { return; } + assert(forward_inputs_ != nullptr && "Must forward inputs to valid Inputs object."); forward_inputs_->handle_pooled_inputs(window); } From 699d70b535a6c08d150d88daeb0c539f00567f39 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 23 Jan 2026 21:24:04 -0500 Subject: [PATCH 35/56] Render Multiple characters in text --- resources/shaders/overlay/TextWindow.vert | 2 +- .../render/graphics_shaders/render_types.hpp | 2 +- .../graphics_shaders/shader_program.cpp | 32 +++++++++++++++++++ .../graphics_shaders/shader_program.hpp | 18 ++++++++++- src/gui/the_buttons/text_widget.cpp | 32 +++++++++++++++---- src/gui/the_buttons/text_widget.hpp | 14 +++++--- src/gui/the_buttons/user_interface.cpp | 2 +- src/gui/the_buttons/user_interface.hpp | 2 +- 8 files changed, 88 insertions(+), 16 deletions(-) diff --git a/resources/shaders/overlay/TextWindow.vert b/resources/shaders/overlay/TextWindow.vert index 626096f1..1cc61cb2 100644 --- a/resources/shaders/overlay/TextWindow.vert +++ b/resources/shaders/overlay/TextWindow.vert @@ -17,7 +17,7 @@ main() { //vec2 projection_matrix = vec2(1/250, 1/250); - gl_Position = vec4(ui_scale * 2 * (vec2(pos.xy) / vec2(frame_size)) - 1, 1, 1); + gl_Position = vec4(ui_scale * (vec2(pos.xy) / vec2(frame_size)) - 1, 1, 1); UV = vec2(pos.w, pos.z); //UV = vec2((pos.z - 304) * 20, pos.w * 2); } diff --git a/src/gui/render/graphics_shaders/render_types.hpp b/src/gui/render/graphics_shaders/render_types.hpp index 3cb286f8..c253c2a1 100644 --- a/src/gui/render/graphics_shaders/render_types.hpp +++ b/src/gui/render/graphics_shaders/render_types.hpp @@ -42,7 +42,7 @@ class FrameBuffer { virtual void render(screen_size_t width, screen_size_t height, GLuint frame_buffer) = 0; }; - +// TODO remove this class class ScreenSection { public: virtual void render( diff --git a/src/gui/render/graphics_shaders/shader_program.cpp b/src/gui/render/graphics_shaders/shader_program.cpp index 03c993b2..e77ef5c6 100644 --- a/src/gui/render/graphics_shaders/shader_program.cpp +++ b/src/gui/render/graphics_shaders/shader_program.cpp @@ -71,6 +71,38 @@ ShaderProgram_Windows::render( data->release(); } +void +ShaderProgramElements_Windows::render( + screen_size_t x_start, screen_size_t y_start, screen_size_t width, + screen_size_t height, GLuint framebuffer_ID, const gpu_data::GPUDataElements* data +) { + + Render_Base::render(width, height, framebuffer_ID, x_start, y_start); + + if (!data->do_render()) { + return; + } + + data->bind(); + + // test if T inherits from Instancing or not + + auto num_vertices = data->get_num_vertices(); + auto element_type = data->get_element_type(); + + // Draw the triangles ! + glDrawElements( + GL_TRIANGLES, // mode + num_vertices, // count + static_cast(element_type), // type + (void*)0 // element array buffer offset + ); + + data->release(); + +} + + void ShaderProgram_Standard::render( screen_size_t width, screen_size_t height, GLuint framebuffer_ID diff --git a/src/gui/render/graphics_shaders/shader_program.hpp b/src/gui/render/graphics_shaders/shader_program.hpp index 277bdf50..2fa61285 100644 --- a/src/gui/render/graphics_shaders/shader_program.hpp +++ b/src/gui/render/graphics_shaders/shader_program.hpp @@ -124,7 +124,7 @@ class Render_Base { // log_uniforms(shader_program.get_detected_uniforms(), uniforms.get_names()); } - void virtual render( + void render( screen_size_t width, screen_size_t height, GLuint framebuffer_ID, screen_size_t x_start = 0, screen_size_t y_start = 0 ); @@ -149,6 +149,22 @@ class ShaderProgram_Windows : ) override; }; +class ShaderProgramElements_Windows : + public virtual Render_Base { + public: + inline ShaderProgramElements_Windows( + shader::Program& shader_program, const std::function setup_commands + ) : + Render_Base(shader_program, setup_commands) {} + + inline virtual ~ShaderProgramElements_Windows() {} + + void virtual render( + screen_size_t x_start, screen_size_t y_start, screen_size_t width, + screen_size_t height, GLuint framebuffer_ID, const gpu_data::GPUDataElements* data + ); +}; + /** * @brief No elements No instancing */ diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index a8d6c9dc..9a417992 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -22,6 +22,18 @@ TextWidget::update_text_data(bool differed) { // data.push_back(glm::ivec4(28, 10, 115, 0)); text_data_.insert(data, 0, text_data_.size()); + + std::vector elements_data; + for (size_t i = 0; i < num_characters_; i++) { + elements_data.push_back(4 * i + 0); + elements_data.push_back(4 * i + 1); + elements_data.push_back(4 * i + 2); + elements_data.push_back(4 * i + 2); + elements_data.push_back(4 * i + 1); + elements_data.push_back(4 * i + 3); + } + + element_array_.insert(elements_data, 0, element_array_.size()); } void @@ -50,8 +62,8 @@ TextWidget::generate_data() const { int advance = 0; - int line_spacing = 25; // eed to read this from the font - int line_advance = line_spacing; + int line_spacing = 25; // need to read this from the font + int line_advance = frame_size_.y/4 - line_spacing; for (char character : text_) { const render::structures::Character* character_data = @@ -73,24 +85,30 @@ TextWidget::generate_data() const { glm::ivec2 bearing = character_data->bearing; glm::ivec2 size = character_data->size; + // up is data.push_back(glm::ivec4( - bearing.x, line_advance - bearing.y + size.y, position_in_texture.x, + advance + bearing.x, line_advance + bearing.y, position_in_texture.x, position_in_texture.y )); data.push_back(glm::ivec4( - bearing.x, line_advance - bearing.y, position_in_texture.x, + advance + bearing.x, line_advance + bearing.y - size.y, position_in_texture.x, position_in_texture.w )); data.push_back(glm::ivec4( - bearing.x + size.x, line_advance - bearing.y + size.y, + advance + bearing.x + size.x, line_advance + bearing.y, position_in_texture.z, position_in_texture.y )); data.push_back(glm::ivec4( - bearing.x + size.x, line_advance - bearing.y, position_in_texture.z, + advance + bearing.x + size.x, line_advance + bearing.y - size.y, position_in_texture.z, position_in_texture.w )); - advance += character_data->advance; +// LOG_DEBUG(logging::main_logger, "Advance {}", character_data->advance); + + LOG_DEBUG(logging::main_logger, "Bearing {}, {}", bearing.x, bearing.y); + + + advance += size.x; } return data; diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index ed4df33b..2ae281ad 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -14,12 +14,13 @@ namespace gui { namespace the_buttons { -class TextWidget : public virtual WidgetBase { +class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataElements { private: gpu_data::VertexArrayObject vertex_array_object_; std::shared_ptr font_; gpu_data::VertexBufferObject text_data_; + gpu_data::VertexBufferObject element_array_; std::string text_; uint32_t num_characters_; @@ -78,20 +79,25 @@ class TextWidget : public virtual WidgetBase { inline void set_text(std::string&& text) { text_ = text; + num_characters_ = text_.length(); update_text_data(); } inline unsigned int get_num_vertices() const { - // return num_characters_ * 4; // four vertices per character - return 4; + return num_characters_ * 6; // four vertices per character + //return 12; + } + + virtual gpu_data::GPUArayType get_element_type() const { + return element_array_.get_opengl_numeric_type(); } inline virtual void bind() const { - // text_data_.attach_to_vertex_attribute(0); font_->bind(0); vertex_array_object_.bind(); + element_array_.bind(); }; inline virtual void diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 641a3cbe..5b9f6832 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -76,7 +76,7 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s window_render_program, render_setup ); - text_pipeline_ = std::make_shared( + text_pipeline_ = std::make_shared( text_render_program, render_setup ); } diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 0178eb96..070cd600 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -30,7 +30,7 @@ class UserInterface : public virtual scene::Inputs { // widget renderer std::shared_ptr window_pipeline_; - std::shared_ptr text_pipeline_; + std::shared_ptr text_pipeline_; std::list> frames_; From 4dc243295b8a2c4583652a969ae3ca9e5205ea5c Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 23 Jan 2026 21:34:03 -0500 Subject: [PATCH 36/56] text placement instructions --- src/gui/the_buttons/text_widget.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index 9a417992..595eb7b3 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -66,6 +66,7 @@ TextWidget::generate_data() const { int line_advance = frame_size_.y/4 - line_spacing; for (char character : text_) { + // if character == "\n" const render::structures::Character* character_data = font_->get_character(character); if (!character_data) { @@ -77,8 +78,12 @@ TextWidget::generate_data() const { ); } + // TODO // if (advance + character_data->advance > frame width or character is new_line) // { advance = 0; line_advance += line_spacing} + // need to check for word + // then break on word + // but also need to break within a word of the world is too long glm::ivec4 position_in_texture = character_data->position_in_texture; From 1f96a6d26d530fc5b13e5eda372ddc91fa568f56 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 31 Jan 2026 13:06:10 -0500 Subject: [PATCH 37/56] Add space to font --- vendor/fonts/pixel_font/Pixelated_7_10.ttf | Bin 8444 -> 8456 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/vendor/fonts/pixel_font/Pixelated_7_10.ttf b/vendor/fonts/pixel_font/Pixelated_7_10.ttf index 3f8110b2ea378c7540f9852a69b2c1bac4d2fce6..c38917d9d508d55144a65ce49d7e855f105da3ad 100644 GIT binary patch delta 628 zcmYjOL1+^}6n)d(Y?3BTwM0onVpk2+MA9}Jhzb>{b`yox9xNghu}c~oG_eZ}QcJOd z78JCXL8u^z^&mcClqmK+mNWWjU=4>oui8R?zzh;#SPrpA*15ulXdSTDZ zR@@8j0!b0l*C4~9`_a#Dx%#Ef!C&xo$#lTikq@5M`RvC%zKb1ko2{!RKg*)b$4l%u z)A>twxcZTWnK?y~q*DYcWZwWhXoChFeK>{*T*N%Zrly1kFhtlALNvu^@kwlmx~R#o z`60#FPpjGSsBmd+kGI|D?+7?FUr@qY90`K_vC_?k`MPqGHxxfVp|`IJFCYw(is#@!R}uG}$|jKXQK6OLrq|-l<&(vFA>$5x-IG+Be8{r;$Rk z^%@k#K!#gA2fgW3GLOQ%iS&nZ{S*8Yx8v$oo7tsg3hhF)0Yahe0SHgJRmVFW@1 zU42~`UUWZp6T6cx3MA4NBvja4^aEW41{D-Ur*~@?e(;_5`T2NxpZDAu`V*fA17OB2 z2pCT$Q)kO>i{Ak0J*oB+iQ`GM!%BRm#)mHi-_0p=1>C~|c_)cWSC!mUaQM+fz%fZfl?(aV zqQ0c>CCfs73AM23eDLG+_b-=QB0phlt)&A#pQ#$^HJ=o@g$?Kv^`{Abjyaf#XIYf_ zd5L)|?^p+mUZhC1PIichQ8mE;4Pie9F@{UHL7_n`h&VAtRn<4@YxSjCRae1ypCFHs zz2yiHwK~0_so7|v-PMn|#j?G%&D!3v!`9ig)9!G(q+Pqa-Fx Date: Sat, 31 Jan 2026 15:56:04 -0500 Subject: [PATCH 38/56] Line wrapping in text widget. --- src/gui/render/structures/font.hpp | 6 + src/gui/the_buttons/text_widget.cpp | 232 ++++++++++++++++++++-------- src/gui/the_buttons/text_widget.hpp | 2 +- 3 files changed, 178 insertions(+), 62 deletions(-) diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index 04cad53f..aae6d101 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -38,6 +38,12 @@ class FontTexture { if (data != font_textures_.end()) { return &data->second; } else { + LOG_WARNING( + logging::main_logger, + "Could not find character \"{}\" with value \"{}\" " + "in font.", + std::string(1, character), static_cast(character) + ); return nullptr; } } diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index 595eb7b3..47cd99a9 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -6,14 +6,8 @@ namespace gui { namespace the_buttons { void -TextWidget::update_text_data(bool differed) { - if (differed) { - GlobalContext& context = GlobalContext::instance(); - context.submit_task([this]() { - std::vector data = generate_data(); - text_data_.insert(data, 0, text_data_.size()); - }); - } +TextWidget::update_text_data() { + // just run this on a back end thread std::vector data = generate_data(); // data.push_back(glm::ivec4(2, 2, 100, 15)); @@ -60,62 +54,178 @@ std::vector TextWidget::generate_data() const { std::vector data; - int advance = 0; - - int line_spacing = 25; // need to read this from the font - int line_advance = frame_size_.y/4 - line_spacing; - - for (char character : text_) { - // if character == "\n" - const render::structures::Character* character_data = - font_->get_character(character); - if (!character_data) { - LOG_WARNING( - logging::main_logger, - "Could not find character \"{}\" with value \"{}\" in font. Required " - "for string \"{}\".", - std::string(1, character), static_cast(character), text_ - ); + // TODO I want to put all of this into a class. Some sort of text alignment + // iterator. Need to send a text size scale to the text widget. + unsigned int text_scale = 4; // should be class value + bool wrap_text = true; // read from class + + unsigned int line_spacing = 20; // need to read this from the font + unsigned int baseline = 15; // read from font + + unsigned int text_width = frame_size_.y / text_scale; + int text_height = frame_size_.y / text_scale; + + unsigned int character_advance = 0; + int line_advance = text_height - baseline; + bool previous_char = false; + bool white_space_after_char = false; + size_t words_checked_until = 0; + + LOG_BACKTRACE(logging::main_logger, "Generating data for string \"{}\".", text_); + + for (size_t character_position = 0; character_position < text_.size(); + character_position++) { + char character = text_.at(character_position); + if (character == '\n') { + character_advance = 0; + line_advance -= line_spacing; + previous_char = false; + white_space_after_char = false; + continue; + } else if (character == '\t') { + character_advance = character_advance + (40 - character_advance % 40); + if (previous_char) { + white_space_after_char = true; + } + continue; } + // '' + else { + if (wrap_text) { + if (character_position >= words_checked_until) { + // check that the entirety of the word is safe + if (white_space_after_char) { + // this is not the first word on the line + // check next word + unsigned int local_advance = character_advance; + size_t check_word_position = character_position; + for (; check_word_position < text_.size(); + check_word_position++) { + char check_character = text_.at(check_word_position); + + // if the character is white space + if (check_character == ' ' || check_character == '\n' + || check_character == '\t') { + break; + } + const render::structures::Character* check_character_data = + font_->get_character(check_word_position); + if (!check_character_data) { + continue; + } + local_advance += check_character_data->size.x; + } + if (local_advance > text_width) { + character_advance = 0; + line_advance -= line_spacing; + previous_char = false; + white_space_after_char = false; + + if (local_advance < text_width * 2) { + words_checked_until = check_word_position; + } + } + } else { + const render::structures::Character* check_character_data = + font_->get_character(character); + if (!check_character_data) { + continue; + } + + if (character_advance + check_character_data->size.x + > text_width) { + if (check_character_data->size.x > text_width) { + LOG_WARNING( + logging::main_logger, + "Character \'{}\' has width {}, but TextWidth has " + "width {}.", + std::string(1, character), + check_character_data->size.x, text_width + ); + } else { + // newline + character_advance = 0; + line_advance -= line_spacing; + previous_char = false; + white_space_after_char = false; + } + } + unsigned int local_advance = character_advance; + size_t check_word_position = character_position; + for (; check_word_position < text_.size(); + check_word_position++) { + char check_character = text_.at(check_word_position); + + // if the character is white space + if (check_character == ' ' || check_character == '\n' + || check_character == '\t') { + break; + } + const render::structures::Character* check_character_data = + font_->get_character(check_word_position); + if (!check_character_data) { + continue; + } + local_advance += check_character_data->size.x; + if (local_advance > text_width) { + check_word_position -= 1; + break; + } + } + words_checked_until = check_word_position; + } + } + } + + // if (advance + character_data->advance > frame width or character is + // new_line) { advance = 0; line_advance += line_spacing} need to check for + // word then break on word but also need to break within a word of the world + // is too long + + // reading character data from font + const render::structures::Character* character_data = + font_->get_character(character); + if (!character_data) { + continue; + } + + glm::ivec4 position_in_texture = character_data->position_in_texture; + glm::ivec2 bearing = character_data->bearing; + glm::ivec2 size = character_data->size; + + data.push_back( + glm::ivec4( + character_advance + bearing.x, line_advance + bearing.y, + position_in_texture.x, position_in_texture.y + ) + ); + data.push_back( + glm::ivec4( + character_advance + bearing.x, line_advance + bearing.y - size.y, + position_in_texture.x, position_in_texture.w + ) + ); + data.push_back( + glm::ivec4( + character_advance + bearing.x + size.x, line_advance + bearing.y, + position_in_texture.z, position_in_texture.y + ) + ); + data.push_back( + glm::ivec4( + character_advance + bearing.x + size.x, + line_advance + bearing.y - size.y, position_in_texture.z, + position_in_texture.w + ) + ); - // TODO - // if (advance + character_data->advance > frame width or character is new_line) - // { advance = 0; line_advance += line_spacing} - // need to check for word - // then break on word - // but also need to break within a word of the world is too long - - glm::ivec4 position_in_texture = character_data->position_in_texture; - - glm::ivec2 bearing = character_data->bearing; - glm::ivec2 size = character_data->size; - - // up is - data.push_back(glm::ivec4( - advance + bearing.x, line_advance + bearing.y, position_in_texture.x, - position_in_texture.y - )); - data.push_back(glm::ivec4( - advance + bearing.x, line_advance + bearing.y - size.y, position_in_texture.x, - position_in_texture.w - )); - data.push_back(glm::ivec4( - advance + bearing.x + size.x, line_advance + bearing.y, - position_in_texture.z, position_in_texture.y - )); - data.push_back(glm::ivec4( - advance + bearing.x + size.x, line_advance + bearing.y - size.y, position_in_texture.z, - position_in_texture.w - )); - -// LOG_DEBUG(logging::main_logger, "Advance {}", character_data->advance); - - LOG_DEBUG(logging::main_logger, "Bearing {}, {}", bearing.x, bearing.y); - - - advance += size.x; + character_advance += size.x; + } + } + // I might want to suppress this as it might not be a problem + if (line_advance > text_height) { + LOG_WARNING(logging::main_logger, "Text larger then allocated size."); } - return data; } diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index 2ae281ad..7904f0b5 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -24,7 +24,7 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl std::string text_; uint32_t num_characters_; - void update_text_data(bool differed = true); + void update_text_data(); void initialize(); From 358a72334a7dfffde9865a0153c8e641a29df585 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 6 Feb 2026 17:27:35 -0500 Subject: [PATCH 39/56] sizes are positive --- src/gui/render/structures/font.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index aae6d101..bfe6ccbc 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -12,7 +12,7 @@ namespace render { namespace structures { struct Character { - glm::ivec2 size; + glm::uvec2 size; glm::ivec2 bearing; unsigned int advance; glm::ivec4 position_in_texture; From e171f03d4ca7607889717c80e0755fc3b5956535 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 6 Feb 2026 18:33:23 -0500 Subject: [PATCH 40/56] save font sizes --- src/gui/render/structures/font.cpp | 4 ++++ src/gui/render/structures/font.hpp | 19 +++++++++++++++++++ src/gui/the_buttons/text_widget.cpp | 13 +++++++------ src/gui/the_buttons/text_widget.hpp | 7 +++++-- src/gui/the_buttons/user_interface.cpp | 6 ------ 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 80ca52af..78307ee0 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -60,6 +60,10 @@ FontTexture::FontTexture(std::filesystem::path font_file) { std::unordered_map images; + descender_height_ = -font_face->descender; + ascender_height_ = -font_face->ascender; + text_height_ = font_face->ascender + descender_height_; + for (unsigned char c = 0; c < 128; c++) { if (FT_Load_Char(font_face, c, FT_LOAD_RENDER | FT_LOAD_MONOCHROME)) { LOG_WARNING(logging::main_logger, "Failed to load \"{}\" from font.", c); diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index bfe6ccbc..fd65759f 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -24,6 +24,10 @@ class FontTexture { std::unordered_map font_textures_; + uint16_t text_height_; + uint16_t ascender_height_; + uint16_t descender_height_; // the distance from the baseline to the top of the character + public: FontTexture(std::filesystem::path font_file); @@ -47,6 +51,21 @@ class FontTexture { return nullptr; } } + + [[nodiscard]] inline auto + get_text_height() const { + return text_height_; + } + + [[nodiscard]] inline auto + get_ascender_height() const { + return ascender_height_; + } + + [[nodiscard]] inline auto + get_descender_height() const { + return descender_height_; + } }; } // namespace structures diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index 47cd99a9..0ec0588b 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -54,13 +54,14 @@ std::vector TextWidget::generate_data() const { std::vector data; - // TODO I want to put all of this into a class. Some sort of text alignment - // iterator. Need to send a text size scale to the text widget. - unsigned int text_scale = 4; // should be class value - bool wrap_text = true; // read from class - unsigned int line_spacing = 20; // need to read this from the font - unsigned int baseline = 15; // read from font + // TODO I want to put all of this into a class. Some sort of text alignment + // iterator. + unsigned int text_scale = text_scale_; + bool wrap_text = wrap_text_; + + unsigned int line_spacing = font_->get_text_height(); + unsigned int baseline = font_->get_ascender_height(); unsigned int text_width = frame_size_.y / text_scale; int text_height = frame_size_.y / text_scale; diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index 7904f0b5..da88a8ea 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -24,6 +24,9 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl std::string text_; uint32_t num_characters_; + bool wrap_text_; + uint8_t text_scale_; + void update_text_data(); void initialize(); @@ -53,7 +56,7 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl inline TextWidget( WidgetInterface* parent, std::shared_ptr font, glm::ivec2 position, glm::ivec2 widget_size, std::string text = std::string(""), - bool differed = true + bool differed = true, bool wrap_text = true, uint8_t text_scale = 4 ) : WidgetBase( parent, position, widget_size, @@ -62,7 +65,7 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl ), vertex_array_object_(differed), - font_(font), text_(text), num_characters_(text_.length()) { + font_(font), text_(text), num_characters_(text_.length()), wrap_text_(wrap_text), text_scale_(text_scale) { if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { initialize(); }); diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index 5b9f6832..a1e8f703 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -138,7 +138,6 @@ UserInterface::render_frame( const BorderedWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const { - // TODO border_sizes_->set_border_size(widget->get_border_size()); side_lengths_->set_side_lengths(widget->get_side_lengths()); inner_pattern_size_->set_inner_pattern_size(widget->get_inner_pattern_size()); @@ -153,8 +152,6 @@ UserInterface::render_frame( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, widget ); - - // widget->render_children(this, x_frame_position, y_frame_position); } void @@ -162,7 +159,6 @@ UserInterface::render_frame( const ButtonWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const { - // TODO border_sizes_->set_border_size(widget->get_border_size()); side_lengths_->set_side_lengths(widget->get_side_lengths()); inner_pattern_size_->set_inner_pattern_size(widget->get_inner_pattern_size()); @@ -177,8 +173,6 @@ UserInterface::render_frame( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, widget ); - - // widget->render_children(this, x_frame_position, y_frame_position); } void From 96c318f781d844f9b92538cd7be9607b910d2ec9 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 6 Feb 2026 18:33:34 -0500 Subject: [PATCH 41/56] copy fonts to release --- CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3be40704..3ca5d10b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,8 +130,17 @@ else() WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) + add_custom_target(fonts + # maybe vendor is already made by something else? + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/vendor/fonts + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/vendor/fonts ${CMAKE_BINARY_DIR}/vendor/fonts + COMMENT " copying ${CMAKE_SOURCE_DIR}/vendor/fonts to ${CMAKE_BINARY_DIR}/vendor/fonts " + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + add_dependencies(FunGame resources) add_dependencies(FunGame data) + add_dependencies(FunGame fonts) endif() configure_file(src/config.h.in config.h) From 23241f75e7befcd8f248d3189367d8c09d2a9ec6 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 20 Feb 2026 18:23:57 -0500 Subject: [PATCH 42/56] add freetype package --- .github/workflows/build-test.yml | 3 ++- README.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 156140d5..90975f65 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -59,7 +59,8 @@ jobs: libglew-dev \ libglm-dev \ libomp-17-dev \ - libpng-dev + libpng-dev \ + libfreetype-dev - name: Build diff --git a/README.md b/README.md index 28ac4335..44110ef8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ pacman -Su \ mingw-w64-x86_64-glew \ mingw-w64-x86_64-glfw \ mingw-w64-x86_64-glm \ - mingw-w64-x86_64-lua # not 100% sure this is the right lua version + mingw-w64-x86_64-lua \ # not 100% sure this is the right lua version + mingw-w64-x86_64-freetype ``` ## Building From afd1106208c00c68bc5d5ff935a1bd90e29345ea Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 25 Feb 2026 18:41:04 -0500 Subject: [PATCH 43/56] Include expected to fix clang error --- src/util/png_image.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 605d06bc..48bc420d 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace util { namespace image { From 0785fdd4cdd12abdfdf356d5261907d766e812fa Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 27 Feb 2026 15:18:18 -0500 Subject: [PATCH 44/56] maybe this will fix clang --- .github/workflows/build-test.yml | 2 +- src/util/png_image.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 90975f65..a81be54c 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -25,7 +25,7 @@ jobs: # - macos-latest compiler: [ { cc: "gcc", cxx: "g++"}, - { cc: "clang", cxx: "clang++"} + { cc: "clang-20", cxx: "clang++-20"} ] build: - Release diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 48bc420d..605d06bc 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -31,7 +31,6 @@ #include #include #include -#include namespace util { namespace image { From 118d3ae9b8252443a3e9d7cb22e744cb38167892 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 28 Feb 2026 15:43:36 -0500 Subject: [PATCH 45/56] formatting --- src/exceptions.hpp | 8 ++--- src/global_context.hpp | 5 +-- src/graphics_main.cpp | 7 ++-- src/gui/render/gpu_data/frame_buffer.cpp | 24 ++++++------- .../gpu_data/frame_buffer_multisample.cpp | 23 +++++++------ src/gui/render/gpu_data/render_buffer.hpp | 3 +- src/gui/render/gpu_data/shadow_map.cpp | 3 +- src/gui/render/gpu_data/texture.cpp | 34 +++++++++++-------- .../render/gpu_data/vertex_array_object.hpp | 5 +-- .../render/gpu_data/vertex_buffer_object.hpp | 5 ++- .../graphics_shaders/program_handler.cpp | 15 +++++--- .../graphics_shaders/program_handler.hpp | 2 +- .../render/graphics_shaders/render_types.hpp | 1 + .../graphics_shaders/shader_program.cpp | 6 ++-- .../graphics_shaders/shader_program.hpp | 31 ++++++----------- .../structures/floating_instanced_i_mesh.cpp | 4 +-- .../structures/floating_instanced_i_mesh.hpp | 8 ++--- src/gui/render/structures/font.cpp | 18 +++++----- src/gui/render/structures/font.hpp | 3 +- .../render/structures/instanced_i_mesh.cpp | 4 +-- src/gui/render/structures/model.hpp | 2 +- src/gui/render/structures/static_mesh.hpp | 3 +- src/gui/render/structures/terrain_mesh.cpp | 3 +- src/gui/render/structures/terrain_mesh.hpp | 4 +-- src/gui/render/structures/uniform_types.hpp | 14 ++++---- src/gui/render/structures/window_texture.cpp | 3 +- src/gui/render/structures/window_texture.hpp | 12 +++++-- src/gui/scene/scene.hpp | 3 +- src/gui/the_buttons/bordered_widget.hpp | 2 +- src/gui/the_buttons/bordered_window.hpp | 2 +- src/gui/the_buttons/button_widget.hpp | 2 +- src/gui/the_buttons/frame.hpp | 12 +++---- src/gui/the_buttons/frame_part.hpp | 25 +++++++------- src/gui/the_buttons/text_widget.cpp | 1 - src/gui/the_buttons/text_widget.hpp | 14 +++++--- src/gui/the_buttons/user_interface.cpp | 13 ++++--- src/gui/the_buttons/widget.hpp | 2 +- src/gui/ui/imgui_gui.cpp | 6 ++-- src/gui/ui/imgui_windows.cpp | 3 +- src/gui/ui/scene_setup.cpp | 6 ++-- src/manifest/manifest.hpp | 3 +- src/manifest/object_handler.hpp | 6 ++-- src/util/image.hpp | 25 +++++--------- src/util/mesh.hpp | 7 ++-- src/util/png_image.hpp | 4 +-- src/world/biome.cpp | 8 +++-- src/world/object/entity/entity.cpp | 12 +++---- src/world/object/entity/entity.hpp | 2 +- .../object/entity/implemented_entity.hpp | 3 +- src/world/object/entity/object.hpp | 4 +-- src/world/object/entity/tile_object.cpp | 8 ++--- src/world/object/entity_controller.cpp | 11 +++--- src/world/object/entity_controller.hpp | 6 ++-- src/world/plant.hpp | 7 ++-- src/world/terrain/chunk.cpp | 9 +++-- src/world/terrain/chunk.hpp | 4 +-- .../terrain/generation/land_generator.cpp | 14 ++++---- .../terrain/generation/land_generator.hpp | 6 ++-- src/world/terrain/generation/map_tile.hpp | 4 +-- src/world/terrain/generation/mat_tile.cpp | 4 +-- src/world/terrain/generation/noise.cpp | 5 +-- .../generation/terrain_genreration_types.hpp | 12 +++---- src/world/terrain/generation/terrain_map.hpp | 10 +++--- src/world/terrain/generation/worley_noise.cpp | 5 +-- src/world/terrain/generation/worley_noise.hpp | 5 ++- src/world/terrain/material.cpp | 6 ++-- src/world/terrain/material.hpp | 12 +++---- src/world/terrain/path/node.hpp | 4 +-- src/world/terrain/path/node_group.cpp | 4 +-- src/world/terrain/path/node_wrappers.hpp | 2 +- src/world/terrain/path/tile_iterator.cpp | 4 +-- src/world/terrain/terrain.cpp | 13 +++---- src/world/terrain/terrain.hpp | 4 +-- src/world/terrain/terrain_helper-impls.cpp | 10 +++--- src/world/terrain/terrain_helper.cpp | 2 +- src/world/world.cpp | 23 +++++++------ 76 files changed, 315 insertions(+), 294 deletions(-) diff --git a/src/exceptions.hpp b/src/exceptions.hpp index 6976bc28..d47557c4 100644 --- a/src/exceptions.hpp +++ b/src/exceptions.hpp @@ -19,8 +19,8 @@ class file_not_found_error : public std::runtime_error { file_not_found_error(const file_not_found_error& other) noexcept = default; - file_not_found_error& operator=(const file_not_found_error& other - ) noexcept = default; + file_not_found_error& + operator=(const file_not_found_error& other) noexcept = default; [[nodiscard]] virtual inline const std::filesystem::path path() const noexcept { @@ -36,8 +36,8 @@ class not_implemented_error : public std::logic_error { not_implemented_error(const not_implemented_error& other) noexcept = default; - not_implemented_error& operator=(const not_implemented_error& other - ) noexcept = default; + not_implemented_error& + operator=(const not_implemented_error& other) noexcept = default; }; } // namespace exc diff --git a/src/global_context.hpp b/src/global_context.hpp index fdd9ba29..50fe4ed7 100644 --- a/src/global_context.hpp +++ b/src/global_context.hpp @@ -102,8 +102,9 @@ class GlobalContext { } // this must be run before exit if lua has been initialized on thread local - // - inline void close_threads() { + // + inline void + close_threads() { thread_pool_.reset(0); } diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index 4c784d5f..fc20a0d6 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -47,7 +47,8 @@ graphics_main(const argh::parser& cmdl) { bool imgui_debug = cmdl[{"-g", "--imgui"}]; intro_scene::result new_game_settings = intro_scene::NewGame{ - .biome = biome_name, .seed = seed, .size = size, .DearIMGUI = imgui_debug}; + .biome = biome_name, .seed = seed, .size = size, .DearIMGUI = imgui_debug + }; return graphics_main(new_game_settings); } @@ -111,7 +112,9 @@ graphics_main(intro_scene::result result) { } } exit: - gui::scene::InputHandler::forward_inputs_to(nullptr); // this removes an object from static storage + gui::scene::InputHandler::forward_inputs_to( + nullptr + ); // this removes an object from static storage GlobalContext& context = GlobalContext::instance(); context.run_opengl_queue(); // this should clean up anything left in the queue diff --git a/src/gui/render/gpu_data/frame_buffer.cpp b/src/gui/render/gpu_data/frame_buffer.cpp index 28aa2480..19a9867b 100644 --- a/src/gui/render/gpu_data/frame_buffer.cpp +++ b/src/gui/render/gpu_data/frame_buffer.cpp @@ -11,9 +11,7 @@ namespace gpu_data { FrameBufferBase::FrameBufferBase( screen_size_t width, screen_size_t height, FrameBufferSettings settings -) : - width_(width), - height_(height), settings_(settings) { +) : width_(width), height_(height), settings_(settings) { // frame buffer (the container for the other two) // ----------------- glGenFramebuffers(1, &frame_buffer); @@ -22,15 +20,17 @@ FrameBufferBase::FrameBufferBase( FrameBuffer::FrameBuffer( screen_size_t width, screen_size_t height, FrameBufferSettings settings -) : - FrameBufferBase(width, height, settings) { - connect_depth_texture(std::make_shared( - width_, height_, - TextureSettings{ - .internal_format = GPUPixelStorageFormat::DEPTH, - .read_format = GPUPixelReadFormat::DEPTH_COMPONENT}, - false - )); +) : FrameBufferBase(width, height, settings) { + connect_depth_texture( + std::make_shared( + width_, height_, + TextureSettings{ + .internal_format = GPUPixelStorageFormat::DEPTH, + .read_format = GPUPixelReadFormat::DEPTH_COMPONENT + }, + false + ) + ); connect_render_texture( std::make_shared( width_, height_, diff --git a/src/gui/render/gpu_data/frame_buffer_multisample.cpp b/src/gui/render/gpu_data/frame_buffer_multisample.cpp index 52fcea94..3aeabfe4 100644 --- a/src/gui/render/gpu_data/frame_buffer_multisample.cpp +++ b/src/gui/render/gpu_data/frame_buffer_multisample.cpp @@ -11,22 +11,25 @@ namespace gpu_data { FrameBufferMultisample::FrameBufferMultisample( screen_size_t width, screen_size_t height, FrameBufferSettings settings -) : - FrameBufferBase(width, height, settings) { - connect_depth_texture(std::make_shared( - width_, height_, - RenderBufferSettings{ - .samples = settings_.samples, - .multisample = settings_.samples > 1, - .internal_format = GPUPixelStorageFormat::DEPTH} - )); +) : FrameBufferBase(width, height, settings) { + connect_depth_texture( + std::make_shared( + width_, height_, + RenderBufferSettings{ + .samples = settings_.samples, + .multisample = settings_.samples > 1, + .internal_format = GPUPixelStorageFormat::DEPTH + } + ) + ); connect_render_texture( std::make_shared( width_, height_, TextureSettings{ .samples = settings.samples, .multisample = (settings_.samples > 1), - .internal_format = GPUPixelStorageFormat::RGB8}, + .internal_format = GPUPixelStorageFormat::RGB8 + }, false ), 0 diff --git a/src/gui/render/gpu_data/render_buffer.hpp b/src/gui/render/gpu_data/render_buffer.hpp index e74f5c99..5519c155 100644 --- a/src/gui/render/gpu_data/render_buffer.hpp +++ b/src/gui/render/gpu_data/render_buffer.hpp @@ -28,8 +28,7 @@ class RenderBuffer : virtual public GPUDataRenderBuffer { inline RenderBuffer( screen_size_t width, screen_size_t height, RenderBufferSettings settings - ) : - RenderBuffer(settings) { + ) : RenderBuffer(settings) { bind(); if (settings_.multisample) { glRenderbufferStorageMultisample( diff --git a/src/gui/render/gpu_data/shadow_map.cpp b/src/gui/render/gpu_data/shadow_map.cpp index a46dca73..c79349b2 100644 --- a/src/gui/render/gpu_data/shadow_map.cpp +++ b/src/gui/render/gpu_data/shadow_map.cpp @@ -23,7 +23,8 @@ ShadowMap::ShadowMap(screen_size_t w, screen_size_t h, FrameBufferSettings setti .internal_format = GPUPixelStorageFormat::DEPTH_16, .read_format = GPUPixelReadFormat::DEPTH_COMPONENT, .type = GPUPixelType::HALF_FLOAT, - .min_filter = GL_LINEAR}; + .min_filter = GL_LINEAR + }; connect_depth_texture( std::make_shared(width_, height_, depth_texture_settings, false) diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index b1556b22..6a4bf91e 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -119,9 +119,7 @@ Texture2D::setup(std::shared_ptr image) { Texture2D::Texture2D( screen_size_t width, screen_size_t height, TextureSettings settings, bool differed -) : - width_(width), - height_(height), settings_(settings) { +) : width_(width), height_(height), settings_(settings) { if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { setup(nullptr); }); @@ -132,8 +130,7 @@ Texture2D::Texture2D( Texture2D::Texture2D( std::shared_ptr image, TextureSettings settings, bool differed -) : - settings_(settings) { +) : settings_(settings) { if (!image) { return; } @@ -176,11 +173,10 @@ std::shared_ptr Texture2D::get_image() const { // multiplying by 2 fixes the memory error, but that can't possibly be correct. // TODO GL_PACK_ALIGNMENT - size_t data_size = width_ * height_ * get_size(settings_.type) * get_size(settings_.read_format) * 2; + size_t data_size = width_ * height_ * get_size(settings_.type) + * get_size(settings_.read_format) * 2; - std::shared_ptr data = std::make_shared( - data_size - ); + std::shared_ptr data = std::make_shared(data_size); if (settings_.multisample) { LOG_ERROR(logging::opengl_logger, "Cannot load multisample texture to image."); @@ -195,15 +191,25 @@ Texture2D::get_image() const { glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &opengl_type); + glGetTexLevelParameteriv( + GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &opengl_type + ); if (width != width_ || height != height_) { - LOG_WARNING(logging::opengl_logger, "Width or Height don't match correct value. Actual {}, {}, Saved {}, {}.", width, height, width_, height_); + LOG_WARNING( + logging::opengl_logger, + "Width or Height don't match correct value. Actual {}, {}, Saved {}, {}.", + width, height, width_, height_ + ); } - if (gui::gpu_data::GPUPixelStorageFormat(opengl_type) != settings_.internal_format ) { - LOG_WARNING(logging::opengl_logger, "Type sizes don't match. Actual {}, Given {}.", - get_size(gui::gpu_data::GPUPixelStorageFormat(opengl_type)), get_size(settings_.internal_format)); + if (gui::gpu_data::GPUPixelStorageFormat(opengl_type) + != settings_.internal_format) { + LOG_WARNING( + logging::opengl_logger, "Type sizes don't match. Actual {}, Given {}.", + get_size(gui::gpu_data::GPUPixelStorageFormat(opengl_type)), + get_size(settings_.internal_format) + ); } #endif diff --git a/src/gui/render/gpu_data/vertex_array_object.hpp b/src/gui/render/gpu_data/vertex_array_object.hpp index c9d8fdc5..fb70650e 100644 --- a/src/gui/render/gpu_data/vertex_array_object.hpp +++ b/src/gui/render/gpu_data/vertex_array_object.hpp @@ -19,8 +19,9 @@ class VertexArrayObject { inline VertexArrayObject(bool differed = true) { if (differed) { GlobalContext& context = GlobalContext::instance(); - context.push_opengl_task([this]() { glGenVertexArrays(1, &vertex_array_); } - ); + context.push_opengl_task([this]() { + glGenVertexArrays(1, &vertex_array_); + }); } else { glGenVertexArrays(1, &vertex_array_); } diff --git a/src/gui/render/gpu_data/vertex_buffer_object.hpp b/src/gui/render/gpu_data/vertex_buffer_object.hpp index 89dfbc02..6377c769 100644 --- a/src/gui/render/gpu_data/vertex_buffer_object.hpp +++ b/src/gui/render/gpu_data/vertex_buffer_object.hpp @@ -69,9 +69,8 @@ struct GPUStructureType { uint8_t major_size_, uint8_t minor_size_, uint8_t type_size, bool is_int, GPUArayType draw_type ) : - major_size(major_size_), - minor_size(minor_size_), type_size(type_size), is_int(is_int), - draw_type(draw_type) {} + major_size(major_size_), minor_size(minor_size_), type_size(type_size), + is_int(is_int), draw_type(draw_type) {} template < uint8_t major_size_T, uint8_t minor_size_T, uint8_t type_size_T, bool is_int_T, diff --git a/src/gui/render/graphics_shaders/program_handler.cpp b/src/gui/render/graphics_shaders/program_handler.cpp index a04667db..df8beeb2 100644 --- a/src/gui/render/graphics_shaders/program_handler.cpp +++ b/src/gui/render/graphics_shaders/program_handler.cpp @@ -170,23 +170,28 @@ Program::get_status_string() const { "OK", "This program and its corresponding shaders have compiled successfully. If " "there is still some error check that Uniforms and Locations are set " - "correctly."}; + "correctly." + }; static std::pair linking_failed_string = { "Linking Failed", "There is an error when connecting different shader types together. Check that " - "the inputs and output between shaders align."}; + "the inputs and output between shaders align." + }; static std::pair invalid_shader_string = { "Shader Failed", "Error compiling constituent shader(s). Check the log file " - "for more information."}; + "for more information." + }; static std::pair empty_program_string = { - "No Program; Reload", "Program has not been loaded. Click the reload button."}; + "No Program; Reload", "Program has not been loaded. Click the reload button." + }; static std::pair other_string = { "This should not happen", - "This is a bug that should be reported to the developers."}; + "This is a bug that should be reported to the developers." + }; switch (status_) { case ProgramStatus::OK: diff --git a/src/gui/render/graphics_shaders/program_handler.hpp b/src/gui/render/graphics_shaders/program_handler.hpp index 5d379676..efb5bb6e 100644 --- a/src/gui/render/graphics_shaders/program_handler.hpp +++ b/src/gui/render/graphics_shaders/program_handler.hpp @@ -498,7 +498,7 @@ class ShaderHandler { /** * @brief construct a new ShaderHandler */ - inline ShaderHandler(){}; + inline ShaderHandler() {}; inline ~ShaderHandler() {} }; diff --git a/src/gui/render/graphics_shaders/render_types.hpp b/src/gui/render/graphics_shaders/render_types.hpp index c253c2a1..5d2ff51f 100644 --- a/src/gui/render/graphics_shaders/render_types.hpp +++ b/src/gui/render/graphics_shaders/render_types.hpp @@ -42,6 +42,7 @@ class FrameBuffer { virtual void render(screen_size_t width, screen_size_t height, GLuint frame_buffer) = 0; }; + // TODO remove this class class ScreenSection { public: diff --git a/src/gui/render/graphics_shaders/shader_program.cpp b/src/gui/render/graphics_shaders/shader_program.cpp index e77ef5c6..ab58702b 100644 --- a/src/gui/render/graphics_shaders/shader_program.cpp +++ b/src/gui/render/graphics_shaders/shader_program.cpp @@ -76,7 +76,6 @@ ShaderProgramElements_Windows::render( screen_size_t x_start, screen_size_t y_start, screen_size_t width, screen_size_t height, GLuint framebuffer_ID, const gpu_data::GPUDataElements* data ) { - Render_Base::render(width, height, framebuffer_ID, x_start, y_start); if (!data->do_render()) { @@ -99,10 +98,8 @@ ShaderProgramElements_Windows::render( ); data->release(); - } - void ShaderProgram_Standard::render( screen_size_t width, screen_size_t height, GLuint framebuffer_ID @@ -316,7 +313,8 @@ ShaderProgram_MultiElements::render( GL_TRIANGLES, // mode mesh->get_num_vertices().data(), // count static_cast(element_type), // type - reinterpret_cast(mesh->get_elements_position().data() + reinterpret_cast( + mesh->get_elements_position().data() ), // indices mesh->get_num_objects(), // drawcount mesh->get_base_vertex().data() diff --git a/src/gui/render/graphics_shaders/shader_program.hpp b/src/gui/render/graphics_shaders/shader_program.hpp index 2fa61285..900db681 100644 --- a/src/gui/render/graphics_shaders/shader_program.hpp +++ b/src/gui/render/graphics_shaders/shader_program.hpp @@ -113,9 +113,7 @@ class Render_Base { public: inline Render_Base( shader::Program& shader_program, const std::function setup_commands - ) : - opengl_program_(shader_program), - setup_(setup_commands) { + ) : opengl_program_(shader_program), setup_(setup_commands) { LOG_DEBUG( logging::opengl_logger, "Program ID: {}, Name: {}", opengl_program_.get_program_ID(), opengl_program_.get_name() @@ -138,8 +136,7 @@ class ShaderProgram_Windows : public: inline ShaderProgram_Windows( shader::Program& shader_program, const std::function setup_commands - ) : - Render_Base(shader_program, setup_commands) {} + ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgram_Windows() {} @@ -149,19 +146,18 @@ class ShaderProgram_Windows : ) override; }; -class ShaderProgramElements_Windows : - public virtual Render_Base { +class ShaderProgramElements_Windows : public virtual Render_Base { public: inline ShaderProgramElements_Windows( shader::Program& shader_program, const std::function setup_commands - ) : - Render_Base(shader_program, setup_commands) {} + ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgramElements_Windows() {} void virtual render( screen_size_t x_start, screen_size_t y_start, screen_size_t width, - screen_size_t height, GLuint framebuffer_ID, const gpu_data::GPUDataElements* data + screen_size_t height, GLuint framebuffer_ID, + const gpu_data::GPUDataElements* data ); }; @@ -177,8 +173,7 @@ class ShaderProgram_Standard : inline ShaderProgram_Standard( shader::Program& shader_program, const std::function setup_commands - ) : - Render_Base(shader_program, setup_commands) {} + ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgram_Standard() {} @@ -199,8 +194,7 @@ class ShaderProgram_Elements : inline ShaderProgram_Elements( shader::Program& shader_program, const std::function setup_commands - ) : - Render_Base(shader_program, setup_commands) {} + ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgram_Elements() {} @@ -221,8 +215,7 @@ class ShaderProgram_Instanced : inline ShaderProgram_Instanced( shader::Program& shader_program, const std::function setup_commands - ) : - Render_Base(shader_program, setup_commands) {} + ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgram_Instanced() {} @@ -243,8 +236,7 @@ class ShaderProgram_ElementsInstanced : inline ShaderProgram_ElementsInstanced( shader::Program& shader_program, const std::function setup_commands - ) : - Render_Base(shader_program, setup_commands) {} + ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgram_ElementsInstanced() {} @@ -265,8 +257,7 @@ class ShaderProgram_MultiElements : inline ShaderProgram_MultiElements( shader::Program& shader_program, const std::function setup_commands - ) : - Render_Base(shader_program, setup_commands) {} + ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgram_MultiElements() {} diff --git a/src/gui/render/structures/floating_instanced_i_mesh.cpp b/src/gui/render/structures/floating_instanced_i_mesh.cpp index 168364e0..e5a4719d 100644 --- a/src/gui/render/structures/floating_instanced_i_mesh.cpp +++ b/src/gui/render/structures/floating_instanced_i_mesh.cpp @@ -15,9 +15,7 @@ namespace gpu_data { FloatingInstancedIMeshGPU::FloatingInstancedIMeshGPU( const util::Mesh& mesh, const std::vector& model_transforms -) : - IMeshGPU(mesh, false), - transforms_array_(model_transforms, 1) { +) : IMeshGPU(mesh, false), transforms_array_(model_transforms, 1) { // InstancedInt does not have a color texture. One must inherit from this // class and define a method that creates a color texture, and sets its id // as color_texture_. diff --git a/src/gui/render/structures/floating_instanced_i_mesh.hpp b/src/gui/render/structures/floating_instanced_i_mesh.hpp index 09a6f3a4..e6c87b0e 100644 --- a/src/gui/render/structures/floating_instanced_i_mesh.hpp +++ b/src/gui/render/structures/floating_instanced_i_mesh.hpp @@ -54,10 +54,10 @@ class FloatingInstancedIMeshGPU : inline FloatingInstancedIMeshGPU(const FloatingInstancedIMeshGPU& obj) = delete; inline FloatingInstancedIMeshGPU(FloatingInstancedIMeshGPU&& other) = default; // copy operator - inline FloatingInstancedIMeshGPU& operator=(const FloatingInstancedIMeshGPU& obj - ) = delete; - inline FloatingInstancedIMeshGPU& operator=(FloatingInstancedIMeshGPU&& other - ) = default; + inline FloatingInstancedIMeshGPU& + operator=(const FloatingInstancedIMeshGPU& obj) = delete; + inline FloatingInstancedIMeshGPU& + operator=(FloatingInstancedIMeshGPU&& other) = default; inline FloatingInstancedIMeshGPU(const util::Mesh& mesh) : FloatingInstancedIMeshGPU(mesh, {}) {} diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 78307ee0..d7f62f4c 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -53,7 +53,8 @@ FontTexture::FontTexture(std::filesystem::path font_file) { .read_format = gpu_data::GPUPixelReadFormat::RED, .type = gpu_data::GPUPixelType::UNSIGNED_BYTE, .min_filter = GL_NEAREST, - .mag_filter = GL_NEAREST}; + .mag_filter = GL_NEAREST + }; unsigned int max_height = 0; unsigned int total_width = 0; @@ -108,7 +109,8 @@ FontTexture::FontTexture(std::filesystem::path font_file) { .bearing = char_position, .advance = static_cast(font_face->glyph->advance.x), .position_in_texture = - glm::ivec4(total_width, 0, total_width + char_size.x, char_size.y)} + glm::ivec4(total_width, 0, total_width + char_size.x, char_size.y) + } ); total_width += char_size.x; @@ -131,11 +133,11 @@ FontTexture::FontTexture(std::filesystem::path font_file) { } LOG_DEBUG(logging::main_logger, "saving fonts to file."); -/* auto result_1 = - image::write_image(*image, files::get_log_path() / "font_as_image.png"); - if (result_1 != image::write_result_t::WR_OK) { - image::log_result(result_1, files::get_log_path() / "font_as_image.png"); - }*/ + /* auto result_1 = + image::write_image(*image, files::get_log_path() / "font_as_image.png"); + if (result_1 != image::write_result_t::WR_OK) { + image::log_result(result_1, files::get_log_path() / "font_as_image.png"); + }*/ image->transpose(); texture_ = std::make_shared(image, settings); @@ -145,7 +147,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { /* auto font_image_from_gpu = texture_->get_image(); - + if (auto font_image_from_gpu_typed = std::dynamic_pointer_cast( font_image_from_gpu diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index fd65759f..bb2b2c5b 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -26,7 +26,8 @@ class FontTexture { uint16_t text_height_; uint16_t ascender_height_; - uint16_t descender_height_; // the distance from the baseline to the top of the character + uint16_t + descender_height_; // the distance from the baseline to the top of the character public: FontTexture(std::filesystem::path font_file); diff --git a/src/gui/render/structures/instanced_i_mesh.cpp b/src/gui/render/structures/instanced_i_mesh.cpp index 2bd435ce..52bdc1a0 100644 --- a/src/gui/render/structures/instanced_i_mesh.cpp +++ b/src/gui/render/structures/instanced_i_mesh.cpp @@ -16,8 +16,8 @@ namespace gpu_data { InstancedIMeshGPU::InstancedIMeshGPU( const util::Mesh& mesh, const std::vector& model_transforms ) : - IMeshGPU(mesh, false), - transforms_array_(model_transforms, 1), num_models_(model_transforms.size()) { + IMeshGPU(mesh, false), transforms_array_(model_transforms, 1), + num_models_(model_transforms.size()) { // InstancedInt does not have a color texture. One must inherit from this // class and define a method that creates a color texture, and sets its id // as color_texture_. diff --git a/src/gui/render/structures/model.hpp b/src/gui/render/structures/model.hpp index ecc8c466..517e34bf 100644 --- a/src/gui/render/structures/model.hpp +++ b/src/gui/render/structures/model.hpp @@ -95,7 +95,7 @@ class ModelController : virtual public gui::gpu_data::GPUDataElementsInstanced { model_mesh_(std::move(other.model_mesh_)), model_textures_(std::move(other.model_textures_)), texture_id_(std::move(other.texture_id_)), - placements_(std::move(other.placements_)), offset_(std::move(other.offset_)){}; + placements_(std::move(other.placements_)), offset_(std::move(other.offset_)) {}; // copy operator inline ModelController& operator=(const ModelController& obj) = delete; ModelController& operator=(ModelController&& other) = default; diff --git a/src/gui/render/structures/static_mesh.hpp b/src/gui/render/structures/static_mesh.hpp index ae50a62d..4d8a7ccf 100644 --- a/src/gui/render/structures/static_mesh.hpp +++ b/src/gui/render/structures/static_mesh.hpp @@ -44,8 +44,7 @@ class StaticMesh : public virtual InstancedIMeshGPU { inline StaticMesh( const util::Mesh& mesh, const std::vector& model_transforms - ) : - InstancedIMeshGPU(mesh, model_transforms) {} + ) : InstancedIMeshGPU(mesh, model_transforms) {} inline virtual ~StaticMesh() {} diff --git a/src/gui/render/structures/terrain_mesh.cpp b/src/gui/render/structures/terrain_mesh.cpp index 0555eca8..d1977664 100644 --- a/src/gui/render/structures/terrain_mesh.cpp +++ b/src/gui/render/structures/terrain_mesh.cpp @@ -6,7 +6,8 @@ namespace gpu_data { namespace detail { -coalesced_data::coalesced_data(const std::unordered_map mesh_map +coalesced_data::coalesced_data( + const std::unordered_map mesh_map ) { size_t total_size = 0; size_t total_elements_size = 0; diff --git a/src/gui/render/structures/terrain_mesh.hpp b/src/gui/render/structures/terrain_mesh.hpp index c16d1f98..b1134069 100644 --- a/src/gui/render/structures/terrain_mesh.hpp +++ b/src/gui/render/structures/terrain_mesh.hpp @@ -177,10 +177,10 @@ class TerrainMesh : public virtual IMeshMultiGPU { public: inline TerrainMesh() : - color_texture_(terrain::TerrainColorMapping::get_color_texture()){}; + color_texture_(terrain::TerrainColorMapping::get_color_texture()) {}; inline TerrainMesh(Texture1D& color_texture_id) : - color_texture_(color_texture_id){}; + color_texture_(color_texture_id) {}; inline TerrainMesh( const std::unordered_map mesh_map, diff --git a/src/gui/render/structures/uniform_types.hpp b/src/gui/render/structures/uniform_types.hpp index f6844f15..c0a8d4a5 100644 --- a/src/gui/render/structures/uniform_types.hpp +++ b/src/gui/render/structures/uniform_types.hpp @@ -18,7 +18,7 @@ namespace render { class LightEnvironment { private: public: - virtual ~LightEnvironment(){}; + virtual ~LightEnvironment() {}; virtual glm::vec3 get_light_direction() const = 0; virtual glm::vec3 get_diffuse_light() const = 0; @@ -27,7 +27,7 @@ class LightEnvironment { class StarRotation { public: - virtual ~StarRotation(){}; + virtual ~StarRotation() {}; virtual glm::mat4 get_sky_rotation() const = 0; }; @@ -39,7 +39,7 @@ class LightDirection : public shader::UniformExecutor { LightDirection(std::shared_ptr lighting) : UniformExecutor(gpu_data::GPUArayType::FLOAT_VEC3), lighting_(lighting) {} - virtual ~LightDirection(){}; + virtual ~LightDirection() {}; virtual void bind(GLint uniform_ID) const override { @@ -66,7 +66,7 @@ class DiffuseLight : public shader::UniformExecutor { DiffuseLight(std::shared_ptr lighting) : UniformExecutor(gpu_data::GPUArayType::FLOAT_VEC3), lighting_(lighting) {} - virtual ~DiffuseLight(){}; + virtual ~DiffuseLight() {}; virtual void bind(GLint uniform_ID) const override { @@ -93,7 +93,7 @@ class SpectralLight : public shader::UniformExecutor { SpectralLight(std::shared_ptr lighting) : UniformExecutor(gpu_data::GPUArayType::FLOAT_VEC3), lighting_(lighting) {} - virtual ~SpectralLight(){}; + virtual ~SpectralLight() {}; inline virtual void bind(GLint uniform_ID) const override { @@ -117,7 +117,7 @@ class MatrixViewProjection : public shader::UniformExecutor { MatrixViewProjection(std::shared_ptr controller) : UniformExecutor(gpu_data::GPUArayType::FLOAT_MAT4), controller_(controller) {} - virtual ~MatrixViewProjection(){}; + virtual ~MatrixViewProjection() {}; inline virtual void bind(GLint uniform_ID) const override { @@ -141,7 +141,7 @@ class ViewMatrix : public shader::UniformExecutor { ViewMatrix(std::shared_ptr controller) : UniformExecutor(gpu_data::GPUArayType::FLOAT_MAT4), controller_(controller) {} - virtual ~ViewMatrix(){}; + virtual ~ViewMatrix() {}; inline virtual void bind(GLint uniform_ID) const override { diff --git a/src/gui/render/structures/window_texture.cpp b/src/gui/render/structures/window_texture.cpp index 2f13514b..d54fa108 100644 --- a/src/gui/render/structures/window_texture.cpp +++ b/src/gui/render/structures/window_texture.cpp @@ -38,7 +38,8 @@ WindowTexture::WindowTexture( .read_format = gui::gpu_data::GPUPixelReadFormat::RGBA_INTEGER, .type = gui::gpu_data::GPUPixelType::UNSIGNED_BYTE, .min_filter = GL_NEAREST, - .mag_filter = GL_NEAREST} + .mag_filter = GL_NEAREST + } ), border_size_(border_size), side_lengths_(side_lengths), inner_pattern_size_(inner_pattern_size), texture_regions_(texture_regions) { diff --git a/src/gui/render/structures/window_texture.hpp b/src/gui/render/structures/window_texture.hpp index 985026d2..7860d26d 100644 --- a/src/gui/render/structures/window_texture.hpp +++ b/src/gui/render/structures/window_texture.hpp @@ -70,7 +70,8 @@ struct window_texture_data_t { std::array({texture_regions[5].x, texture_regions[5].y}), std::array({texture_regions[6].x, texture_regions[6].y}), std::array({texture_regions[7].x, texture_regions[7].y}), - std::array({texture_regions[8].x, texture_regions[8].y})}; + std::array({texture_regions[8].x, texture_regions[8].y}) + }; } inline void @@ -211,6 +212,11 @@ template <> struct glz::meta { using T = gui::render::window_texture_data_t; - static constexpr auto - value = object("texture_file", &T::texture_file, "border_size", custom<&T::border_size_read, &T::border_size_write>, "side_lengths", custom<&T::side_lengths_read, &T::side_lengths_write>, "inner_pattern_size", custom<&T::inner_pattern_size_read, &T::inner_pattern_size_write>, "texture_regions", custom<&T::texture_regions_read, &T::texture_regions_write>); + static constexpr auto value = object( + "texture_file", &T::texture_file, "border_size", + custom<&T::border_size_read, &T::border_size_write>, "side_lengths", + custom<&T::side_lengths_read, &T::side_lengths_write>, "inner_pattern_size", + custom<&T::inner_pattern_size_read, &T::inner_pattern_size_write>, + "texture_regions", custom<&T::texture_regions_read, &T::texture_regions_write> + ); }; diff --git a/src/gui/scene/scene.hpp b/src/gui/scene/scene.hpp index 63e310b8..9f66eb48 100644 --- a/src/gui/scene/scene.hpp +++ b/src/gui/scene/scene.hpp @@ -205,7 +205,8 @@ class Scene { * @param render object that can render to a framebuffer. */ inline void - add_background_ground_renderer(const std::shared_ptr render + add_background_ground_renderer( + const std::shared_ptr render ) { background_frame_buffer_.push_back(render); } diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index b7d71186..0b69336a 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -52,7 +52,7 @@ class BorderedWidget : public virtual WidgetBase { data_->update_position(get_bounding_box()); } - inline virtual ~BorderedWidget(){}; + inline virtual ~BorderedWidget() {}; inline unsigned int get_num_vertices() const { diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp index 5cb5569f..8d01306b 100644 --- a/src/gui/the_buttons/bordered_window.hpp +++ b/src/gui/the_buttons/bordered_window.hpp @@ -40,7 +40,7 @@ class BorderedWindow : public virtual FrameBase { glm::ivec2 size ); - inline virtual ~BorderedWindow(){}; + inline virtual ~BorderedWindow() {}; inline unsigned int get_num_vertices() const { diff --git a/src/gui/the_buttons/button_widget.hpp b/src/gui/the_buttons/button_widget.hpp index 55fe80a0..3cccd668 100644 --- a/src/gui/the_buttons/button_widget.hpp +++ b/src/gui/the_buttons/button_widget.hpp @@ -58,7 +58,7 @@ class ButtonWidget : public virtual WidgetBase { data_->update_position(get_bounding_box()); } - inline virtual ~ButtonWidget(){}; + inline virtual ~ButtonWidget() {}; inline unsigned int get_num_vertices() const { diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index c6ca1dc2..80253719 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -15,7 +15,7 @@ namespace the_buttons { class FrameInterface : public virtual WidgetInterface { public: - inline virtual ~FrameInterface(){}; // kill children + inline virtual ~FrameInterface() {}; // kill children virtual bool is_fixed() const = 0; @@ -150,10 +150,10 @@ class FrameBase : public virtual FrameInterface { glm::ivec2 position, glm::ivec2 frame_size, std::vector exterior_points, bool fixed = false ) : - position_(position), - frame_size_(frame_size), exterior_points_(exterior_points), fixed_(fixed){}; + position_(position), frame_size_(frame_size), exterior_points_(exterior_points), + fixed_(fixed) {}; - inline virtual ~FrameBase(){}; // kill children + inline virtual ~FrameBase() {}; // kill children bool is_interior(screen_size_t x, screen_size_t y) const; @@ -184,9 +184,9 @@ class FrameBase : public virtual FrameInterface { return true; } - inline virtual void on_select() override{}; + inline virtual void on_select() override {}; - inline virtual void on_end_select() override{}; + inline virtual void on_end_select() override {}; // virtual void render_children( // const UserInterface* user_interface, screen_size_t x_position, diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index a20b07db..718523a2 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -28,9 +28,8 @@ class WidgetBase : public virtual WidgetInterface { WidgetInterface* parent, glm::ivec2 position, glm::ivec2 frame_size, std::vector exterior_points ) : - parent_(parent), - position_(position), frame_size_(frame_size), - exterior_points_(exterior_points){}; + parent_(parent), position_(position), frame_size_(frame_size), + exterior_points_(exterior_points) {}; WidgetBase() = delete; /** @@ -95,7 +94,7 @@ class WidgetBase : public virtual WidgetInterface { [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int key, [[maybe_unused]] int scancode, [[maybe_unused]] int action, [[maybe_unused]] int mods - ) override{}; + ) override {}; /** * @brief Handle text input @@ -106,7 +105,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_text_input_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] unsigned int codepoint - ) override{}; + ) override {}; /** * @brief Handle mouse movement events. @@ -118,7 +117,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_mouse_event_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xpos, [[maybe_unused]] double ypos - ) override{}; + ) override {}; /** * @brief Handle mouse enter window events @@ -131,7 +130,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_mouse_button_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int button, [[maybe_unused]] int action, [[maybe_unused]] int mods - ) override{}; + ) override {}; /** * @brief Handle mouse scroll events @@ -143,7 +142,7 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_mouse_scroll_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double xoffset, [[maybe_unused]] double yoffset - ) override{}; + ) override {}; /** * @brief Handle joystick event @@ -153,7 +152,7 @@ class WidgetBase : public virtual WidgetInterface { */ virtual void handle_joystick_input( [[maybe_unused]] int jid, [[maybe_unused]] int event - ) override{}; + ) override {}; /** * @brief Handle file drop event @@ -165,28 +164,28 @@ class WidgetBase : public virtual WidgetInterface { virtual void handle_file_drop_input( [[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int count, [[maybe_unused]] const char** paths - ) override{}; + ) override {}; /** * @brief Handle all pooled inputs * * @param GLFWwindow* window window */ - virtual void handle_pooled_inputs([[maybe_unused]] GLFWwindow* window) override{}; + virtual void handle_pooled_inputs([[maybe_unused]] GLFWwindow* window) override {}; /** * @brief Setup so this objects handles inputs correctly * * @param GLFWwindow* window window */ - virtual void setup([[maybe_unused]] GLFWwindow* window) override{}; + virtual void setup([[maybe_unused]] GLFWwindow* window) override {}; /** * @brief Cleanup to original state * * @param GLFWwindow* window window */ - virtual void cleanup([[maybe_unused]] GLFWwindow* window) override{}; + virtual void cleanup([[maybe_unused]] GLFWwindow* window) override {}; }; } // namespace the_buttons diff --git a/src/gui/the_buttons/text_widget.cpp b/src/gui/the_buttons/text_widget.cpp index 0ec0588b..32cca076 100644 --- a/src/gui/the_buttons/text_widget.cpp +++ b/src/gui/the_buttons/text_widget.cpp @@ -54,7 +54,6 @@ std::vector TextWidget::generate_data() const { std::vector data; - // TODO I want to put all of this into a class. Some sort of text alignment // iterator. unsigned int text_scale = text_scale_; diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index da88a8ea..ff1c4e5d 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -20,7 +20,9 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl std::shared_ptr font_; gpu_data::VertexBufferObject text_data_; - gpu_data::VertexBufferObject element_array_; + gpu_data::VertexBufferObject< + uint16_t, gpu_data::BindingTarget::ELEMENT_ARRAY_BUFFER> + element_array_; std::string text_; uint32_t num_characters_; @@ -65,7 +67,8 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl ), vertex_array_object_(differed), - font_(font), text_(text), num_characters_(text_.length()), wrap_text_(wrap_text), text_scale_(text_scale) { + font_(font), text_(text), num_characters_(text_.length()), + wrap_text_(wrap_text), text_scale_(text_scale) { if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { initialize(); }); @@ -75,7 +78,7 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl update_text_data(); } - inline virtual ~TextWidget(){}; + inline virtual ~TextWidget() {}; void attach_all(); @@ -89,10 +92,11 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl inline unsigned int get_num_vertices() const { return num_characters_ * 6; // four vertices per character - //return 12; + // return 12; } - virtual gpu_data::GPUArayType get_element_type() const { + virtual gpu_data::GPUArayType + get_element_type() const { return element_array_.get_opengl_numeric_type(); } diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index a1e8f703..dec7e1c0 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -19,9 +19,11 @@ namespace the_buttons { UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_scale) : frame_size_uniform_(std::make_shared()), ui_scale_uniform_(std::make_shared(ui_scale)), - frame_texture_uniform_(std::make_shared( - gpu_data::GPUArayType::UNSIGNED_INT_SAMPLER_2D, 0 - )), + frame_texture_uniform_( + std::make_shared( + gpu_data::GPUArayType::UNSIGNED_INT_SAMPLER_2D, 0 + ) + ), border_sizes_(std::make_shared()), side_lengths_(std::make_shared()), inner_pattern_size_(std::make_shared()), @@ -194,8 +196,9 @@ UserInterface::render_frame( } std::pair, std::weak_ptr> -UserInterface::get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) - const { +UserInterface::get_frame( + screen_size_t mouse_position_x, screen_size_t mouse_position_y +) const { // iterate from back to front auto frame_outer = frames_.end(); // might be able to do this with control flow diff --git a/src/gui/the_buttons/widget.hpp b/src/gui/the_buttons/widget.hpp index 1f8737a4..8e417f27 100644 --- a/src/gui/the_buttons/widget.hpp +++ b/src/gui/the_buttons/widget.hpp @@ -12,7 +12,7 @@ class UserInterface; class WidgetInterface : public virtual scene::Inputs, public virtual gpu_data::GPUData { public: - inline virtual ~WidgetInterface(){}; // kill children + inline virtual ~WidgetInterface() {}; // kill children virtual bool is_interior(screen_size_t x, screen_size_t y) const = 0; diff --git a/src/gui/ui/imgui_gui.cpp b/src/gui/ui/imgui_gui.cpp index b1951bb5..35636680 100644 --- a/src/gui/ui/imgui_gui.cpp +++ b/src/gui/ui/imgui_gui.cpp @@ -156,7 +156,8 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { // 2. Show a simple window that we create ourselves. We use a Begin/End pair to // create a named window. { - ImGui::Begin("Hello, world!" + ImGui::Begin( + "Hello, world!" ); // Create a window called "Hello, world!" and append into it. if (scene::InputHandler::escape()) { @@ -166,7 +167,8 @@ imgui_entry(GLFWwindow* window, world::World& world, world::Climate& climate) { scene::InputHandler::clear_escape(); } - ImGui::Text("This is some useful text." + ImGui::Text( + "This is some useful text." ); // Display some text (you can use a format strings too) ImGui::Checkbox("Position Window", &show_position_window); ImGui::Checkbox("Show Light Controls", &show_light_controls); diff --git a/src/gui/ui/imgui_windows.cpp b/src/gui/ui/imgui_windows.cpp index a713db5e..198529bc 100644 --- a/src/gui/ui/imgui_windows.cpp +++ b/src/gui/ui/imgui_windows.cpp @@ -108,7 +108,8 @@ display_data(const manifest::ObjectHandler& object_handler, bool& show) { for (auto& [id, object] : object_handler) { // Display a data item - ImGui::PushID(std::hash{}(id) + ImGui::PushID( + std::hash{}(id) ); // maybe not grate to call hashes like this ImGui::TableNextRow(); ImGui::TableNextColumn(); diff --git a/src/gui/ui/scene_setup.cpp b/src/gui/ui/scene_setup.cpp index 13d50f15..80eb9f16 100644 --- a/src/gui/ui/scene_setup.cpp +++ b/src/gui/ui/scene_setup.cpp @@ -295,7 +295,8 @@ setup( star_pipeline->data.push_back(star_data); sun_pipeline->data.push_back(star_shape); - terrain_mesh->set_shadow_texture(scene.get_shadow_map().get_depth_buffer()->value() + terrain_mesh->set_shadow_texture( + scene.get_shadow_map().get_depth_buffer()->value() ); chunks_render_pipeline->data.push_back(terrain_mesh.get()); chunks_shadow_pipeline->data.push_back(terrain_mesh.get()); @@ -306,7 +307,8 @@ setup( render_programs_t object_render_programs{ .entity_render_program = entity_render_pipeline, - .tile_object_render_program = tile_entity_render_pipeline}; + .tile_object_render_program = tile_entity_render_pipeline + }; // attach the world objects to the render program for (auto& [id, object] : *world.get_object_handler()) { diff --git a/src/manifest/manifest.hpp b/src/manifest/manifest.hpp index c0458eda..07f50ec0 100644 --- a/src/manifest/manifest.hpp +++ b/src/manifest/manifest.hpp @@ -31,7 +31,8 @@ struct manifest_t { } // namespace manifest template <> -inline glz::detail::any_t::operator std::vector() const { +inline glz::detail::any_t:: +operator std::vector() const { assert(false && "Not Implemented"); return {}; } diff --git a/src/manifest/object_handler.hpp b/src/manifest/object_handler.hpp index d59e29c0..fea7715f 100644 --- a/src/manifest/object_handler.hpp +++ b/src/manifest/object_handler.hpp @@ -156,9 +156,9 @@ class ObjectHandler { for (const auto& directory_entry : std::filesystem::directory_iterator(manifest_folder)) { - auto manifest_opt = - files::read_json_from_file(directory_entry.path() - ); + auto manifest_opt = files::read_json_from_file( + directory_entry.path() + ); if (!manifest_opt) { if constexpr (opengl) { diff --git a/src/util/image.hpp b/src/util/image.hpp index 606eb81d..9441c642 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -87,9 +87,7 @@ class Image { inline Image( std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : - width_(width), - height_(height), data_size_(data_size), data_(data){}; + ) : width_(width), height_(height), data_size_(data_size), data_(data) {}; Image(void* data, size_t width, size_t height, size_t data_size); @@ -128,8 +126,7 @@ class FloatMonochromeImage : public virtual MonochromeImage { FloatMonochromeImage( std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : - Image(data, width, height, data_size) { + ) : Image(data, width, height, data_size) { assert(data_size == sizeof(float) && "data size must match expected size"); } @@ -154,8 +151,7 @@ class FloatPolychromeImage : public virtual PolychromeImage { FloatPolychromeImage( std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : - Image(data, width, height, data_size) { + ) : Image(data, width, height, data_size) { assert(data_size == sizeof(float) && "data size must match expected size"); } @@ -187,8 +183,7 @@ class FloatPolychromeAlphaImage : public virtual PolychromeAlphaImage { FloatPolychromeAlphaImage( std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : - Image(data, width, height, data_size) { + ) : Image(data, width, height, data_size) { assert(data_size == sizeof(float) && "data size must match expected size"); } @@ -235,8 +230,7 @@ class ByteMonochromeImage : public virtual MonochromeImage { ByteMonochromeImage( std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : - Image(data, width, height, data_size) { + ) : Image(data, width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" ); @@ -292,8 +286,7 @@ class BytePolychromeImage : public virtual PolychromeImage { // if needed make inline get color BytePolychromeImage( std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : - Image(data, width, height, data_size) { + ) : Image(data, width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" ); @@ -343,8 +336,7 @@ class BytePolychromeAlphaImage : public virtual PolychromeAlphaImage { BytePolychromeAlphaImage( std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : - Image(data, width, height, data_size) { + ) : Image(data, width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" ); @@ -352,8 +344,7 @@ class BytePolychromeAlphaImage : public virtual PolychromeAlphaImage { BytePolychromeAlphaImage( void* data, size_t width, size_t height, size_t data_size - ) : - Image(data, width, height, data_size) { + ) : Image(data, width, height, data_size) { assert( data_size == sizeof(unsigned char) && "data size must match expected size" ); diff --git a/src/util/mesh.hpp b/src/util/mesh.hpp index 33c7e534..ff3dbf27 100644 --- a/src/util/mesh.hpp +++ b/src/util/mesh.hpp @@ -49,10 +49,9 @@ class Mesh { const std::vector& indexed_normals, const std::vector& color_map, glm::ivec3 size, glm::ivec3 center ) : - size_(size), - center_(center), indices_(indices), indexed_vertices_(indexed_vertices), - indexed_color_ids_(indexed_color_ids), indexed_normals_(indexed_normals), - color_map_(color_map) {} + size_(size), center_(center), indices_(indices), + indexed_vertices_(indexed_vertices), indexed_color_ids_(indexed_color_ids), + indexed_normals_(indexed_normals), color_map_(color_map) {} Mesh() : size_({0, 0, 0}), center_({0, 0, 0}), indices_({}), indexed_vertices_({}), diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 48bc420d..3741809f 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -77,7 +77,7 @@ void log_result(write_result_t result, const std::filesystem::path& path); class ImageTest { public: - ImageTest(){}; + ImageTest() {}; size_t get_height() const { @@ -266,7 +266,7 @@ write_image(T image, const std::filesystem::path& path) { class ColorImageTest { public: - ColorImageTest(){}; + ColorImageTest() {}; size_t get_height() const { diff --git a/src/world/biome.cpp b/src/world/biome.cpp index 8e23448c..7a082dae 100644 --- a/src/world/biome.cpp +++ b/src/world/biome.cpp @@ -278,9 +278,11 @@ Biome::get_plant_map(Dim length) const { std::string type_as_string = flora_type.as(); - out.emplace(std::make_pair( - std::move(type_as_string), {type_map, x_map_tiles, y_map_tiles} - )); + out.emplace( + std::make_pair( + std::move(type_as_string), {type_map, x_map_tiles, y_map_tiles} + ) + ); } return out; diff --git a/src/world/object/entity/entity.cpp b/src/world/object/entity/entity.cpp index 87bbbd82..2bdec394 100644 --- a/src/world/object/entity/entity.cpp +++ b/src/world/object/entity/entity.cpp @@ -14,9 +14,11 @@ namespace object { namespace entity { Entity::Entity(const util::Mesh& mesh) : - mesh_and_positions_(std::make_shared( - mesh, std::vector() - )) { + mesh_and_positions_( + std::make_shared( + mesh, std::vector() + ) + ) { LOG_WARNING( logging::main_logger, "Entity constructor Entity(const Mesh& mesh) is depreciated!" @@ -25,9 +27,7 @@ Entity::Entity(const util::Mesh& mesh) : Entity::Entity( const object_t& object_data, const manifest::descriptor_t& identification_data -) : - name_(object_data.name), - identification_(identification_data.identification) { +) : name_(object_data.name), identification_(identification_data.identification) { const auto& model_data = object_data.models[0]; // read mesh from path std::filesystem::path object_path_copy = identification_data.path; diff --git a/src/world/object/entity/entity.hpp b/src/world/object/entity/entity.hpp index 453cd45e..e825d7d1 100644 --- a/src/world/object/entity/entity.hpp +++ b/src/world/object/entity/entity.hpp @@ -83,7 +83,7 @@ class Entity : public virtual Object, public virtual Cognition { Entity(const object_t& object_data, const manifest::descriptor_t& model_path); - virtual ~Entity(){}; + virtual ~Entity() {}; inline void reserve(size_t size) const { diff --git a/src/world/object/entity/implemented_entity.hpp b/src/world/object/entity/implemented_entity.hpp index dcd93bda..efad9069 100644 --- a/src/world/object/entity/implemented_entity.hpp +++ b/src/world/object/entity/implemented_entity.hpp @@ -12,8 +12,7 @@ class ImplementedEntity : public virtual Entity { public: ImplementedEntity( const object_t& object_data, const manifest::descriptor_t& model_path - ) : - Entity(object_data, model_path) {} + ) : Entity(object_data, model_path) {} [[nodiscard]] virtual glm::vec3 decision(EntityInstance* entity_instance) override; }; diff --git a/src/world/object/entity/object.hpp b/src/world/object/entity/object.hpp index c5a042ae..80229d99 100644 --- a/src/world/object/entity/object.hpp +++ b/src/world/object/entity/object.hpp @@ -110,8 +110,8 @@ struct glz::meta { }; template <> -inline glz::detail::any_t::operator std::vector( -) const { +inline glz::detail::any_t:: +operator std::vector() const { assert(false && "Not Implemented"); return {}; } diff --git a/src/world/object/entity/tile_object.cpp b/src/world/object/entity/tile_object.cpp index 0514f3e6..4a899e26 100644 --- a/src/world/object/entity/tile_object.cpp +++ b/src/world/object/entity/tile_object.cpp @@ -11,9 +11,7 @@ namespace entity { TileObjectInstance::TileObjectInstance( std::shared_ptr object_type, uint8_t model_id, gui::Placement placement -) : - placement_(placement), - model_id_(model_id), object_type_(object_type) { +) : placement_(placement), model_id_(model_id), object_type_(object_type) { object_type->get_model(model_id_).insert(placement_); } @@ -48,9 +46,7 @@ TileObject::num_models() const noexcept { TileObject::TileObject( const object_t& object_data, const manifest::descriptor_t& identification_data -) : - name_(object_data.name), - identification_(identification_data.identification) { +) : name_(object_data.name), identification_(identification_data.identification) { for (const model_t& model_data : object_data.models) { // each object may have multiple models std::filesystem::path object_path_copy = identification_data.path; diff --git a/src/world/object/entity_controller.cpp b/src/world/object/entity_controller.cpp index 2d8dc994..1198e00a 100644 --- a/src/world/object/entity_controller.cpp +++ b/src/world/object/entity_controller.cpp @@ -61,7 +61,8 @@ EntityController::spawn_entity(std::string identification, glm::vec3 position) { } void -EntityController::remove_entity(std::shared_ptr entity_instance +EntityController::remove_entity( + std::shared_ptr entity_instance ) { // get position ChunkPos chunk_position = @@ -107,9 +108,11 @@ EntityController::spawn_tile_object( // tile_object_instances_.at(position).insert(object); auto inserted = object_instances_.at(chunk_position) - .insert(std::make_shared( - tile_object_type, model_id, placement - )); + .insert( + std::make_shared( + tile_object_type, model_id, placement + ) + ); return *inserted.first; } diff --git a/src/world/object/entity_controller.hpp b/src/world/object/entity_controller.hpp index 21d2aa68..879ed392 100644 --- a/src/world/object/entity_controller.hpp +++ b/src/world/object/entity_controller.hpp @@ -25,7 +25,7 @@ class EntityController { public: EntityController(manifest::ObjectHandler* object_handler) : - object_handler_(object_handler){}; + object_handler_(object_handler) {}; void update_entities(glm::mat4 transforms_matrix); @@ -39,8 +39,8 @@ class EntityController { std::string identification, uint8_t model_id, gui::Placement placement ); - void remove_tile_object(std::shared_ptr entity_instance - ); + void + remove_tile_object(std::shared_ptr entity_instance); void load_to_gup(); diff --git a/src/world/plant.hpp b/src/world/plant.hpp index 7910c1c3..d7f341c7 100644 --- a/src/world/plant.hpp +++ b/src/world/plant.hpp @@ -28,8 +28,8 @@ struct plant_t { // path to lua file that contains function map_name std::optional map_generator_path; - [[nodiscard]] inline std::strong_ordering operator<=>(const plant_t& other - ) const = default; + [[nodiscard]] inline std::strong_ordering + operator<=>(const plant_t& other) const = default; }; } // namespace generation @@ -46,7 +46,8 @@ struct std::hash { }; template <> -inline glz::detail::any_t::operator std::filesystem::path() const { +inline glz::detail::any_t:: +operator std::filesystem::path() const { assert(false && "Not Implemented"); return {}; } diff --git a/src/world/terrain/chunk.cpp b/src/world/terrain/chunk.cpp index 9ac83160..7cb04f8f 100644 --- a/src/world/terrain/chunk.cpp +++ b/src/world/terrain/chunk.cpp @@ -55,7 +55,8 @@ Chunk::stamp_tile_region( void Chunk::init_nodegroups() { - std::unordered_map temporary_position_to_nodegroup_map({} + std::unordered_map temporary_position_to_nodegroup_map( + {} ); // for all tiles: @@ -171,7 +172,8 @@ Chunk::add_nodegroup_adjacent_mp() { continue; } std::scoped_lock lock{ - mut_, ter_->get_chunk(adjacent_chunk)->get_mutex()}; + mut_, ter_->get_chunk(adjacent_chunk)->get_mutex() + }; NG.add_adjacent(to_add, 31); } } @@ -207,7 +209,8 @@ Chunk::add_nodegroup_adjacent_all() { continue; } std::scoped_lock lock{ - mut_, ter_->get_chunk(adjacent_chunk)->get_mutex()}; + mut_, ter_->get_chunk(adjacent_chunk)->get_mutex() + }; NG.add_adjacent(to_add, 31); } } diff --git a/src/world/terrain/chunk.hpp b/src/world/terrain/chunk.hpp index 4c6d51a4..b856c106 100644 --- a/src/world/terrain/chunk.hpp +++ b/src/world/terrain/chunk.hpp @@ -65,7 +65,7 @@ class Chunk : public voxel_utility::VoxelBase { * @param bz chunk z position * @param ter the terrain this chunk is in */ - Chunk(Dim bx, Dim by, Dim bz, Terrain* ter) : Chunk({bx, by, bz}, ter){}; + Chunk(Dim bx, Dim by, Dim bz, Terrain* ter) : Chunk({bx, by, bz}, ter) {}; Chunk(TerrainDim3 chunk_position, Terrain* ter); @@ -238,7 +238,7 @@ class ChunkData : public voxel_utility::VoxelBase { inline ChunkData(const Chunk& chunk) : data_(get_mat_color_from_chunk(chunk)), offset_(chunk.get_offset()), - color_ids_(chunk.get_color_ids()){}; + color_ids_(chunk.get_color_ids()) {}; /** * @brief Used for getting mesh diff --git a/src/world/terrain/generation/land_generator.cpp b/src/world/terrain/generation/land_generator.cpp index ab2ad8c5..526342f2 100644 --- a/src/world/terrain/generation/land_generator.cpp +++ b/src/world/terrain/generation/land_generator.cpp @@ -67,8 +67,9 @@ LandGenerator::next() { namespace stamps { TileStamp -StampGenerator::get_volume(glm::imat2x2 center, std::default_random_engine& rand_engine) - const { +StampGenerator::get_volume( + glm::imat2x2 center, std::default_random_engine& rand_engine +) const { // center_x between center[1][0] and center[0][0] inclusive std::uniform_int_distribution center_x_dist( center[0][0], center[1][0] @@ -172,9 +173,7 @@ FromRadius::get_stamp( FromPosition::FromPosition( const generation_stamp_t& data, const stamp_generation_position_data_t& type_data -) : - StampGenerator(data), - center_variance_(data.center_range) { +) : StampGenerator(data), center_variance_(data.center_range) { points_.reserve(type_data.positions.size()); for (const auto& [x, y] : type_data.positions) { @@ -196,8 +195,9 @@ FromPosition::get_stamp( } TileStamp -FromGrid::get_stamp(size_t current_sub_region, std::default_random_engine& rand_engine) - const { +FromGrid::get_stamp( + size_t current_sub_region, std::default_random_engine& rand_engine +) const { TerrainOffset x_center = (1 + 2 * (current_sub_region % number_)) * (radius_ / number_) - radius_; TerrainOffset y_center = diff --git a/src/world/terrain/generation/land_generator.hpp b/src/world/terrain/generation/land_generator.hpp index 50aef3bb..6bdf3cee 100644 --- a/src/world/terrain/generation/land_generator.hpp +++ b/src/world/terrain/generation/land_generator.hpp @@ -175,8 +175,7 @@ class FromRadius : public StampGenerator { FromRadius( const generation_stamp_t& data, const stamp_generation_radius_data_t& type_data ) : - StampGenerator(data), - radius_(type_data.radius), number_(type_data.number), + StampGenerator(data), radius_(type_data.radius), number_(type_data.number), center_variance_(data.center_range) {} FromRadius(const generation_stamp_t& data) : @@ -202,8 +201,7 @@ class FromGrid : public StampGenerator { FromGrid( const generation_stamp_t& data, const stamp_generation_grid_data_t& type_data ) : - StampGenerator(data), - radius_(type_data.radius), number_(type_data.number), + StampGenerator(data), radius_(type_data.radius), number_(type_data.number), center_variance_(data.center_range) {} FromGrid(const generation_stamp_t& data) : FromGrid(data, data.grid.value()) {} diff --git a/src/world/terrain/generation/map_tile.hpp b/src/world/terrain/generation/map_tile.hpp index 695b744b..b71b1164 100644 --- a/src/world/terrain/generation/map_tile.hpp +++ b/src/world/terrain/generation/map_tile.hpp @@ -123,7 +123,7 @@ class MapTile { rand_engine_( Noise::get_double((seed ^ tile_type.get_tile_type()) % RANDOM_NUMBER, x, y) * INT32_MAX - ){}; + ) {}; /** * @brief Get the x coordinate @@ -191,7 +191,7 @@ class PlantMap { * * @details Default constructor */ - inline PlantMap() : width_(0), height_(0){}; + inline PlantMap() : width_(0), height_(0) {}; /** * @brief Construct a new PlantMap object diff --git a/src/world/terrain/generation/mat_tile.cpp b/src/world/terrain/generation/mat_tile.cpp index 3949c1cf..4f971c20 100644 --- a/src/world/terrain/generation/mat_tile.cpp +++ b/src/world/terrain/generation/mat_tile.cpp @@ -9,9 +9,7 @@ TileType::TileType( const std::unordered_set land_generators, MapTile_t tile_type, const std::vector& layer_effect_generators, const std::unordered_map materials -) : - land_generators_(land_generators), - tile_type_(tile_type) { +) : land_generators_(land_generators), tile_type_(tile_type) { Dim max_height = 0; ColorId stamp_color_id = 0; diff --git a/src/world/terrain/generation/noise.cpp b/src/world/terrain/generation/noise.cpp index 60c7cc64..4ba8aa12 100644 --- a/src/world/terrain/generation/noise.cpp +++ b/src/world/terrain/generation/noise.cpp @@ -38,8 +38,9 @@ Noise::get_double(size_t i, NoiseTileIndex x, NoiseTileIndex y) { } double -generation::FractalNoise::smoothed_noise_(size_t i, NoiseTileIndex x, NoiseTileIndex y) - const { +generation::FractalNoise::smoothed_noise_( + size_t i, NoiseTileIndex x, NoiseTileIndex y +) const { // clang-format off double corners = (get_double(i, x - 1, y - 1) + get_double(i, x + 1, y - 1) diff --git a/src/world/terrain/generation/terrain_genreration_types.hpp b/src/world/terrain/generation/terrain_genreration_types.hpp index a24b4f13..ed2251f4 100644 --- a/src/world/terrain/generation/terrain_genreration_types.hpp +++ b/src/world/terrain/generation/terrain_genreration_types.hpp @@ -146,22 +146,22 @@ struct glz::meta { // error with glaze // when using optional glaze causes compiler errors and this suppresses those errors template <> -inline glz::detail::any_t::operator terrain::generation::stamp_generation_grid_data_t( -) const { +inline glz::detail::any_t:: +operator terrain::generation::stamp_generation_grid_data_t() const { assert(false && "Not Implemented"); return {}; } template <> -inline glz::detail::any_t::operator terrain::generation:: - stamp_generation_position_data_t() const { +inline glz::detail::any_t:: +operator terrain::generation::stamp_generation_position_data_t() const { assert(false && "Not Implemented"); return {}; } template <> -inline glz::detail::any_t::operator terrain::generation::stamp_generation_radius_data_t( -) const { +inline glz::detail::any_t:: +operator terrain::generation::stamp_generation_radius_data_t() const { assert(false && "Not Implemented"); return {}; } diff --git a/src/world/terrain/generation/terrain_map.hpp b/src/world/terrain/generation/terrain_map.hpp index a401a91c..4d98702a 100644 --- a/src/world/terrain/generation/terrain_map.hpp +++ b/src/world/terrain/generation/terrain_map.hpp @@ -23,7 +23,7 @@ class TerrainMacroMap { * * @details default constructor */ - inline TerrainMacroMap() : width_(0), height_(0){}; + inline TerrainMacroMap() : width_(0), height_(0) {}; /** * @brief Create a new TerrainMacroMap @@ -34,9 +34,7 @@ class TerrainMacroMap { */ inline TerrainMacroMap( std::vector terrain_map, size_t width, size_t height - ) : - width_(width), - height_(height), terrain_map_(terrain_map) { + ) : width_(width), height_(height), terrain_map_(terrain_map) { assert(terrain_map_.size() == width_ * height_); }; @@ -133,8 +131,8 @@ class TerrainMapRepresentation { const TerrainMacroMap& map, unsigned int tile_size = 4, unsigned int tile_border = 1 ) : - terrain_map_(map), - tile_size_in_pixels_(tile_size), tile_border_size_(tile_border) {} + terrain_map_(map), tile_size_in_pixels_(tile_size), + tile_border_size_(tile_border) {} [[nodiscard]] inline size_t get_height() const { diff --git a/src/world/terrain/generation/worley_noise.cpp b/src/world/terrain/generation/worley_noise.cpp index 6ec9081e..3688362b 100644 --- a/src/world/terrain/generation/worley_noise.cpp +++ b/src/world/terrain/generation/worley_noise.cpp @@ -33,8 +33,9 @@ WorleyNoise::get_noise(NoisePosition x, NoisePosition y) const { } std::set -WorleyNoise::get_points_(NoiseTileIndex xt, NoiseTileIndex yt, NoiseTileIndex range) - const { +WorleyNoise::get_points_( + NoiseTileIndex xt, NoiseTileIndex yt, NoiseTileIndex range +) const { // assert(range % 2 == 0 && "range must be even"); std::set out; // compute index of worley tile diff --git a/src/world/terrain/generation/worley_noise.hpp b/src/world/terrain/generation/worley_noise.hpp index b0afc454..725980a2 100644 --- a/src/world/terrain/generation/worley_noise.hpp +++ b/src/world/terrain/generation/worley_noise.hpp @@ -80,7 +80,7 @@ class WorleyNoise : protected Noise { * @details Default constructor sets tile_size to 1; */ inline WorleyNoise(NoisePosition tile_size, NoisePosition point_radius) : - tile_size_(tile_size), point_radius_(point_radius){}; + tile_size_(tile_size), point_radius_(point_radius) {}; /** * @brief Get the noise value at given position. @@ -112,8 +112,7 @@ class AlternativeWorleyNoise : public WorleyNoise { */ inline AlternativeWorleyNoise( NoisePosition tile_size, double positive_chance, NoisePosition radius - ) : - WorleyNoise(tile_size, radius) { + ) : WorleyNoise(tile_size, radius) { positive_chance_ = positive_chance; } diff --git a/src/world/terrain/material.cpp b/src/world/terrain/material.cpp index 3fa8cda9..dae86c6c 100644 --- a/src/world/terrain/material.cpp +++ b/src/world/terrain/material.cpp @@ -79,9 +79,9 @@ MaterialGroup::insert( return false; } -MaterialGroup::MaterialGroup(const std::vector& data -) : - contain_all_materials(false) { +MaterialGroup::MaterialGroup( + const std::vector& data +) : contain_all_materials(false) { // want to generated a group that represents the given data // There will be elements with no requirements on the color // materials_no_color_requirement_ diff --git a/src/world/terrain/material.hpp b/src/world/terrain/material.hpp index 2ebdb9e1..c1ae6f65 100644 --- a/src/world/terrain/material.hpp +++ b/src/world/terrain/material.hpp @@ -199,9 +199,9 @@ class MaterialGroup { * * @details Default constructor. Nothing will be in the group. */ - inline MaterialGroup() : contain_all_materials(false){}; + inline MaterialGroup() : contain_all_materials(false) {}; - inline MaterialGroup(bool all_materials) : contain_all_materials(all_materials){}; + inline MaterialGroup(bool all_materials) : contain_all_materials(all_materials) {}; /** * @brief Construct new MaterialGroup object. @@ -215,9 +215,8 @@ class MaterialGroup { std::unordered_set materials, std::unordered_map> materials_w_color ) : - contain_all_materials(false), - materials_no_color_requirement_(materials), - materials_with_color_requirement_(materials_w_color){}; + contain_all_materials(false), materials_no_color_requirement_(materials), + materials_with_color_requirement_(materials_w_color) {}; /** * @brief Read the materials and colors that this stamp can overwrite in @@ -342,7 +341,8 @@ struct glz::meta { }; template <> -inline glz::detail::any_t::operator terrain::grass_data_t() const { +inline glz::detail::any_t:: +operator terrain::grass_data_t() const { assert(false && "Not Implemented"); return {}; } diff --git a/src/world/terrain/path/node.hpp b/src/world/terrain/path/node.hpp index eb798d24..903ea9c6 100644 --- a/src/world/terrain/path/node.hpp +++ b/src/world/terrain/path/node.hpp @@ -59,12 +59,12 @@ class Node { // Used to find paths. */ Node(T* tile, float hc) : tile_(tile), parent_node_(nullptr), g_cost_(0), h_cost_(hc), - f_cost_(g_cost_ + h_cost_), explored_(false){}; + f_cost_(g_cost_ + h_cost_), explored_(false) {}; /** * @brief Construct a new Node object (default initializer) * @deprecated should not be used */ - Node() : Node(nullptr, 0){}; + Node() : Node(nullptr, 0) {}; /** * @brief Explore this node diff --git a/src/world/terrain/path/node_group.cpp b/src/world/terrain/path/node_group.cpp index 17051968..c448722e 100644 --- a/src/world/terrain/path/node_group.cpp +++ b/src/world/terrain/path/node_group.cpp @@ -9,8 +9,8 @@ namespace terrain { NodeGroup::NodeGroup( ChunkPos chunk_position, LocalPosition tile_position, UnitPath path_type ) : - chunk_position_(chunk_position), - path_type_(path_type), tile_positions_({tile_position}), center_x(tile_position.x), + chunk_position_(chunk_position), path_type_(path_type), + tile_positions_({tile_position}), center_x(tile_position.x), center_y(tile_position.y), center_z(tile_position.z) {} void diff --git a/src/world/terrain/path/node_wrappers.hpp b/src/world/terrain/path/node_wrappers.hpp index bc347f8f..4a39ac3a 100644 --- a/src/world/terrain/path/node_wrappers.hpp +++ b/src/world/terrain/path/node_wrappers.hpp @@ -8,7 +8,7 @@ class PositionWrapper { TerrainOffset3 position_; public: - inline PositionWrapper(){}; + inline PositionWrapper() {}; inline PositionWrapper(TerrainOffset3 position) : position_(position) {} diff --git a/src/world/terrain/path/tile_iterator.cpp b/src/world/terrain/path/tile_iterator.cpp index 4b06a075..a1bbd449 100644 --- a/src/world/terrain/path/tile_iterator.cpp +++ b/src/world/terrain/path/tile_iterator.cpp @@ -59,8 +59,8 @@ get_indexed_offsets(uint8_t index) { AdjacentIterator::AdjacentIterator( const Terrain& parent, TerrainOffset3 xyz, UnitPath path_type ) : - parent_(parent), - path_type_constraint_(path_type), pos_(xyz), path_type_(0), dpos_(0) { + parent_(parent), path_type_constraint_(path_type), pos_(xyz), path_type_(0), + dpos_(0) { update_path(); if (!path_type_.compatible(path_type_constraint_) || !is_valid_end_position()) { iterate_to_next_available(); diff --git a/src/world/terrain/terrain.cpp b/src/world/terrain/terrain.cpp index 198d784b..288d981b 100644 --- a/src/world/terrain/terrain.cpp +++ b/src/world/terrain/terrain.cpp @@ -82,9 +82,8 @@ Terrain::Terrain( TerrainOffset z, const generation::Biome& biome, generation::TerrainMacroMap macro_map ) : - area_size_(area_size_), - biome_(biome), X_MAX(x_map_tiles * area_size_), Y_MAX(y_map_tiles * area_size_), - Z_MAX(z) { + area_size_(area_size_), biome_(biome), X_MAX(x_map_tiles * area_size_), + Y_MAX(y_map_tiles * area_size_), Z_MAX(z) { // srand(seed); LOG_INFO(logging::terrain_logger, "Start of land generator."); @@ -174,7 +173,8 @@ Terrain::qb_read( if (color == 0) { // if the qb voxel is transparent. mat_color = &materials_inverse.at(0); // set the materials to air - } else if (materials_inverse.count(color + } else if (materials_inverse.count( + color )) { // if the color is known mat_color = &materials_inverse.at(color); } else { // the color is unknown @@ -545,8 +545,9 @@ Terrain::set_tile_material( } ColorId -Terrain::natural_color(TerrainOffset3 xyz, const material_t* mat, ColorId color_id) - const { +Terrain::natural_color( + TerrainOffset3 xyz, const material_t* mat, ColorId color_id +) const { auto mat_id = mat->material_id; if (mat_id == DIRT_ID) { // being set to dirt // adds striations to the dirt. (This should be done by lua in the future) diff --git a/src/world/terrain/terrain.hpp b/src/world/terrain/terrain.hpp index 902deda5..2fb9aa9b 100644 --- a/src/world/terrain/terrain.hpp +++ b/src/world/terrain/terrain.hpp @@ -641,8 +641,8 @@ class Terrain : public voxel_utility::VoxelBase { * @return true can stand * @return false cannot stand */ - [[nodiscard]] bool can_stand_1(TerrainOffset3 xyz - ) const; // this might be faster, and used for looping + [[nodiscard]] bool + can_stand_1(TerrainOffset3 xyz) const; // this might be faster, and used for looping /** * @brief test if dxy x dyx x dz object can stand at given position diff --git a/src/world/terrain/terrain_helper-impls.cpp b/src/world/terrain/terrain_helper-impls.cpp index 8a1bf059..4727d895 100644 --- a/src/world/terrain/terrain_helper-impls.cpp +++ b/src/world/terrain/terrain_helper-impls.cpp @@ -36,12 +36,14 @@ namespace terrain { // implementations of start of iteration template void helper::grow_grass_recursive< - helper::edge_detector_low, helper::getter_low, - helper::setter_low>(Terrain&, std::unordered_set); + helper::edge_detector_low, helper::getter_low, helper::setter_low>( + Terrain&, std::unordered_set +); template void helper::grow_grass_recursive< - helper::edge_detector_high, helper::getter_high, - helper::setter_high>(Terrain&, std::unordered_set); + helper::edge_detector_high, helper::getter_high, helper::setter_high>( + Terrain&, std::unordered_set +); // implementations of inner recursive loop template void helper::grow_grass_inner( diff --git a/src/world/terrain/terrain_helper.cpp b/src/world/terrain/terrain_helper.cpp index 0ad8a073..d758f548 100644 --- a/src/world/terrain/terrain_helper.cpp +++ b/src/world/terrain/terrain_helper.cpp @@ -20,7 +20,7 @@ namespace helper { * given a set of grass tiles gets the adjacent grass tiles that have height * equal to given hight. Then next to those tiles set the grass height to * hight-1 if this is higher than the saved height. -*/ + */ template void grow_grass_inner( diff --git a/src/world/world.cpp b/src/world/world.cpp index a41c737c..4d39ef0a 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -49,18 +49,17 @@ World::World( manifest::ObjectHandler* object_handler, const std::string& biome_name, const std::string& path, size_t seed ) : - biome_(biome_name, seed), - terrain_main_(path, biome_), controller_(object_handler) {} + biome_(biome_name, seed), terrain_main_(path, biome_), controller_(object_handler) { +} World::World( manifest::ObjectHandler* object_handler, const std::string& biome_name, MacroDim x_tiles, MacroDim y_tiles, size_t seed ) : - biome_(biome_name, seed), - terrain_main_( - x_tiles, y_tiles, macro_tile_size, height, biome_, - std::move(biome_.get_map(x_tiles)) - ), + biome_(biome_name, seed), terrain_main_( + x_tiles, y_tiles, macro_tile_size, height, biome_, + std::move(biome_.get_map(x_tiles)) + ), controller_(object_handler) {} World::World( @@ -151,8 +150,9 @@ void World::update_marked_chunks_mesh() { for (auto chunk_pos : chunks_to_update_) { GlobalContext& context = GlobalContext::instance(); - context.submit_task([this, chunk_pos]() { this->update_single_mesh(chunk_pos); } - ); + context.submit_task([this, chunk_pos]() { + this->update_single_mesh(chunk_pos); + }); } chunks_to_update_.clear(); } @@ -231,8 +231,9 @@ World::remove_entity(std::shared_ptr entity) { } std::optional> -World::pathfind_to_object(TerrainOffset3 start_position, const std::string& object_id) - const { +World::pathfind_to_object( + TerrainOffset3 start_position, const std::string& object_id +) const { auto object = get_object_handler()->get_object(object_id); if (!object) { LOG_WARNING(logging::terrain_logger, "Object {} not found.", object_id); From b34fa997e59fefc39604e6051b7ca9c26984a0f9 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 28 Feb 2026 17:00:35 -0500 Subject: [PATCH 46/56] more formatting, and light changes --- resources/shaders/overlay/FramedWindow.frag | 82 ++++++------------- resources/shaders/overlay/TextWindow.frag | 2 - resources/shaders/overlay/TextWindow.vert | 5 +- resources/textures/GenericBorder.json | 62 ++++++++++++-- resources/textures/GenericBorder_2.json | 62 ++++++++++++-- resources/textures/GenericButton.json | 62 ++++++++++++-- src/graphics_main.cpp | 24 ++---- .../render/gpu_data/vertex_buffer_object.hpp | 4 + .../graphics_shaders/program_handler.cpp | 5 +- src/gui/render/structures/font.cpp | 70 +++------------- src/gui/scene/controls.cpp | 9 +- 11 files changed, 220 insertions(+), 167 deletions(-) diff --git a/resources/shaders/overlay/FramedWindow.frag b/resources/shaders/overlay/FramedWindow.frag index 7e60ad53..073c88a7 100644 --- a/resources/shaders/overlay/FramedWindow.frag +++ b/resources/shaders/overlay/FramedWindow.frag @@ -16,17 +16,6 @@ uniform ivec2 positions[9]; void main(){ - - ivec2 position_1 = positions[0]; - ivec2 position_2 = positions[1]; - ivec2 position_3 = positions[2]; - ivec2 position_4 = positions[3]; - ivec2 position_5 = positions[4]; - ivec2 position_6 = positions[5]; - ivec2 position_7 = positions[6]; - ivec2 position_8 = positions[7]; - ivec2 position_9 = positions[8]; - int width_2 = side_lengths[0]; int height_4 = side_lengths[1]; int width_5 = inner_pattern_size[0]; @@ -40,62 +29,53 @@ main(){ ivec2 texture_offset; -// ivec2 texture_position = ivec2(texture_locations[3], texture_locations[2]); - - if (ui_position.y < border_size[1] && ui_position.x < border_size[0]) { // 1 - +// The window is arranged like this +// 0 | 1 | 2 +// ---+---+--- +// 3 | 4 | 5 +// ---+---+--- +// 6 | 7 | 8 +// + if (ui_position.y < border_size[1] && ui_position.x < border_size[0]) { // 0 ivec2 local_position = ivec2(ui_position.x, ui_position.y); - - texture_offset = local_position + position_1; - + texture_offset = local_position + positions[0]; } - else if (ui_position.y < border_size[1] && frame_size_px.x - ui_position.x - 1 < border_size[2]) { // 3 - + else if (ui_position.y < border_size[1] && frame_size_px.x - ui_position.x - 1 < border_size[2]) { // 2 ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size[2], ui_position.y); - - texture_offset = local_position + position_3; + texture_offset = local_position + positions[2]; } - else if ((frame_size_px.y - ui_position.y - 1 < border_size[3]) && ui_position.x < border_size[0]) { // 7 + else if ((frame_size_px.y - ui_position.y - 1 < border_size[3]) && ui_position.x < border_size[0]) { // 6 ivec2 local_position = ivec2(ui_position.x, ui_position.y - frame_size_px.y + border_size[3]); - - texture_offset = local_position + position_7; + texture_offset = local_position + positions[6]; } - else if ((frame_size_px.y - ui_position.y - 1 < border_size[3]) && (frame_size_px.x - ui_position.x - 1 < border_size[2])) { // 9 + else if ((frame_size_px.y - ui_position.y - 1 < border_size[3]) && (frame_size_px.x - ui_position.x - 1 < border_size[2])) { // 8 ivec2 local_position = ivec2(ui_position.x - frame_size_px.x + border_size[2], ui_position.y - frame_size_px.y + border_size[3]); - - texture_offset = local_position + position_9; + texture_offset = local_position + positions[8]; } - else if (ui_position.x < border_size[0]) { // 4 + else if (ui_position.x < border_size[0]) { // 3 ivec2 local_position = ivec2(ui_position.x, ui_position.y - border_size[1]); local_position.y = local_position.y % height_4; - - texture_offset = local_position + position_4; + texture_offset = local_position + positions[3]; } - else if (ui_position.y < border_size[1]) { // 2 + else if (ui_position.y < border_size[1]) { // 1 ivec2 local_position = ivec2(ui_position.x, ui_position.y); local_position.x = local_position.x % width_2; - - texture_offset = local_position + position_2; + texture_offset = local_position + positions[1]; } - else if ((frame_size_px.x - ui_position.x) <= border_size[3]) { // 6 - + else if ((frame_size_px.x - ui_position.x) <= border_size[3]) { // 5 ivec2 local_position = ivec2(border_size[2] - frame_size_px.x + ui_position.x, ui_position.y - border_size[3]); local_position.y = local_position.y % height_6; - - texture_offset = local_position + position_6; + texture_offset = local_position + positions[5]; } - else if ((frame_size_px.y - ui_position.y) <= border_size[3]) { // 8 idk - + else if ((frame_size_px.y - ui_position.y) <= border_size[3]) { // 7 ivec2 local_position = ivec2(ui_position.x - border_size[2], ui_position.y - frame_size_px.y + border_size[3]); local_position.x = local_position.x % width_8; - - texture_offset = local_position + position_8; - } else { // 5 + texture_offset = local_position + positions[7]; + } else { // 4 ivec2 local_position = ivec2(ui_position.x - border_size[0], ui_position.y - border_size[1]); local_position.x = local_position.x % width_5; local_position.y = local_position.y % height_5; - - texture_offset = position_5 + local_position; + texture_offset = positions[4] + local_position; } uvec4 color_int = texelFetch(window_texture, texture_offset, 0); @@ -104,16 +84,4 @@ main(){ } color = vec3(color_int.rgb)/255.0; -// uvec4 color_int = texelFetch(window_texture, texture_position, 0); - -// if (color_int.a == 0) { -// discard; -// } - -// vec3 color_float = vec3(color_int.rgba); - - //uvec3 color_int = texture(window_texture, vec2(0.5, 0.5)).rgb; - -// color = color_float / 255;//texelFetch(window_texture, ivec2(3, 3), 0).rgb; - } diff --git a/resources/shaders/overlay/TextWindow.frag b/resources/shaders/overlay/TextWindow.frag index 22a0e9b7..07d6eeb9 100644 --- a/resources/shaders/overlay/TextWindow.frag +++ b/resources/shaders/overlay/TextWindow.frag @@ -11,11 +11,9 @@ in vec2 UV; void main() { - //color = vec3(0.6,0.2,0.1); vec3 font_color = vec3(0.6,0.2,0.1); uint alpha = texelFetch(font_texture, ivec2(UV), 0).r; - //uint alpha = texelFetch(font_texture, ivec2(13, 0), 0).r; if (alpha > 0) { color = font_color; diff --git a/resources/shaders/overlay/TextWindow.vert b/resources/shaders/overlay/TextWindow.vert index 1cc61cb2..ce732887 100644 --- a/resources/shaders/overlay/TextWindow.vert +++ b/resources/shaders/overlay/TextWindow.vert @@ -1,8 +1,7 @@ #version 450 core -// Input vertex data, different for all executions of this shader. +// Screen and texture position of letter layout(location = 0) in ivec4 pos; -//layout(location = 1) in vec2 vertex_position_screenspace; // this is the size of the view // then switch to division @@ -15,8 +14,6 @@ out vec2 UV; void main() { - //vec2 projection_matrix = vec2(1/250, 1/250); - gl_Position = vec4(ui_scale * (vec2(pos.xy) / vec2(frame_size)) - 1, 1, 1); UV = vec2(pos.w, pos.z); //UV = vec2((pos.z - 304) * 20, pos.w * 2); diff --git a/resources/textures/GenericBorder.json b/resources/textures/GenericBorder.json index 0b043593..3e789fff 100644 --- a/resources/textures/GenericBorder.json +++ b/resources/textures/GenericBorder.json @@ -1,9 +1,57 @@ { - "texture_file" : "./GenericBorder.png", -"border_size" : [5,5,5,5], -"side_lengths" : [1,1,1,1], -"inner_pattern_size" : [1,1], -"texture_regions" : [[0, 0], [5, 0], [6, 0], - [0, 5], [5, 5], [6, 5], - [0, 6], [5, 6], [6, 6]] + "texture_file": "./GenericBorder.png", + "border_size": [ + 5, + 5, + 5, + 5 + ], + "side_lengths": [ + 1, + 1, + 1, + 1 + ], + "inner_pattern_size": [ + 1, + 1 + ], + "texture_regions": [ + [ + 0, + 0 + ], + [ + 5, + 0 + ], + [ + 6, + 0 + ], + [ + 0, + 5 + ], + [ + 5, + 5 + ], + [ + 6, + 5 + ], + [ + 0, + 6 + ], + [ + 5, + 6 + ], + [ + 6, + 6 + ] + ] } \ No newline at end of file diff --git a/resources/textures/GenericBorder_2.json b/resources/textures/GenericBorder_2.json index c93be282..1a5f8fb9 100644 --- a/resources/textures/GenericBorder_2.json +++ b/resources/textures/GenericBorder_2.json @@ -1,11 +1,57 @@ { - "texture_file" : "./GenericBorder_2.png", - "border_size" : [7,7,7,7], - "side_lengths" : [10,10,10,10], - "inner_pattern_size" : [10,10], - "texture_regions" : [ - [0, 0], [6, 0], [15, 0], - [0, 6], [6, 6], [15, 6], - [0, 15], [6, 15], [15, 15] + "texture_file": "./GenericBorder_2.png", + "border_size": [ + 7, + 7, + 7, + 7 + ], + "side_lengths": [ + 10, + 10, + 10, + 10 + ], + "inner_pattern_size": [ + 10, + 10 + ], + "texture_regions": [ + [ + 0, + 0 + ], + [ + 6, + 0 + ], + [ + 15, + 0 + ], + [ + 0, + 6 + ], + [ + 6, + 6 + ], + [ + 15, + 6 + ], + [ + 0, + 15 + ], + [ + 6, + 15 + ], + [ + 15, + 15 ] + ] } \ No newline at end of file diff --git a/resources/textures/GenericButton.json b/resources/textures/GenericButton.json index 0c083444..b6609fce 100644 --- a/resources/textures/GenericButton.json +++ b/resources/textures/GenericButton.json @@ -1,9 +1,57 @@ { - "texture_file" : "./GenericButton.png", -"border_size" : [5,5,5,5], -"side_lengths" : [1,1,1,1], -"inner_pattern_size" : [1,1], -"texture_regions" : [[0, 0], [5, 0], [6, 0], - [0, 5], [5, 5], [6, 5], - [0, 6], [5, 6], [6, 6]] + "texture_file": "./GenericButton.png", + "border_size": [ + 5, + 5, + 5, + 5 + ], + "side_lengths": [ + 1, + 1, + 1, + 1 + ], + "inner_pattern_size": [ + 1, + 1 + ], + "texture_regions": [ + [ + 0, + 0 + ], + [ + 5, + 0 + ], + [ + 6, + 0 + ], + [ + 0, + 5 + ], + [ + 5, + 5 + ], + [ + 6, + 5 + ], + [ + 0, + 6 + ], + [ + 5, + 6 + ], + [ + 6, + 6 + ] + ] } \ No newline at end of file diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index fc20a0d6..e09c60ee 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -21,14 +21,9 @@ #include -// create structure to pass game start data either from command line or from gui -/* -struct Options { - std::optional biome; - - std::optional save_file; -};*/ - +// result from loading +// will be modified to handel all events that must be returned from the loading +// screen. struct background_result { int result; std::unique_ptr world; @@ -59,7 +54,7 @@ graphics_main(intro_scene::result result) { // global context and logging are already initalized. - // read commands from file + // read settings from file // Things like screen size // full screen // all graphics/audio settings @@ -82,8 +77,10 @@ graphics_main(intro_scene::result result) { GLuint VertexArrayID; glGenVertexArrays(1, &VertexArrayID); gui::VertexBufferHandler::instance().bind_vertex_buffer(VertexArrayID); - // intro_scene::result result = intro_scene::IntroPage(); + // This is the top level game loop. This will handle switching between + // games, and starting new games. Should also have a settings page + // etc. while (true) { switch (result.index()) { case 0: // exiting @@ -94,13 +91,11 @@ graphics_main(intro_scene::result result) { break; case 2: // new world with settings { - // auto settings = std::get(result); result = start_game(result, window); } break; case 3: // from save with file path { - // auto path = std::get(result); result = start_game(result, window); } break; @@ -172,9 +167,7 @@ start_game(intro_scene::result result, GLFWwindow* window) { background_result result; int manifest_result = object_handler.load_all_manifests(); - result.result = manifest_result; - if (result.result == 1) { return result; } @@ -259,9 +252,6 @@ intro_window(GLFWwindow* window) { GlobalContext& global_context = GlobalContext::instance(); // don't forget ot load ScreenData onto gpu - // gui::the_buttons::UserInterface main_interface(temp_handler, 4); - // gui::setup(main_interface); - auto main_interface = std::make_shared(temp_handler, 4); gui::setup(*main_interface); diff --git a/src/gui/render/gpu_data/vertex_buffer_object.hpp b/src/gui/render/gpu_data/vertex_buffer_object.hpp index 6377c769..7b424dd8 100644 --- a/src/gui/render/gpu_data/vertex_buffer_object.hpp +++ b/src/gui/render/gpu_data/vertex_buffer_object.hpp @@ -561,6 +561,10 @@ VertexBufferObject::private_insert_( template void VertexBufferObject::bind() const { + GlobalContext& context = GlobalContext::instance(); + if (!context.is_main_thread()) { + LOG_ERROR(logging::opengl_logger, "Calling bind from nonmain thread."); + } constexpr GPUStructureType data_type = GPUStructureType::create(); LOG_BACKTRACE( diff --git a/src/gui/render/graphics_shaders/program_handler.cpp b/src/gui/render/graphics_shaders/program_handler.cpp index df8beeb2..e326a60d 100644 --- a/src/gui/render/graphics_shaders/program_handler.cpp +++ b/src/gui/render/graphics_shaders/program_handler.cpp @@ -273,8 +273,9 @@ Program::set_uniform(std::shared_ptr uex, std::string uniform_n "program \"{}\".", uniform_name, name_ ); - // do you mean... - // min less than 5 + + // Add a "do you mean..." suggestion. + // Consider Levenshtein distance less than 5 // https://en.wikipedia.org/wiki/Levenshtein_distance } } diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index d7f62f4c..37936330 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -1,5 +1,5 @@ #include "font.hpp" -// #include "../render/texture.hpp" + #include "logging.hpp" #include "util/files.hpp" #include "util/png_image.hpp" @@ -8,7 +8,6 @@ #include FT_FREETYPE_H // ^ what type of mad man write this? -// namespace gui { @@ -16,38 +15,25 @@ namespace render { namespace structures { -// FontHandler::FontHandler () { -// FT_Library ft; - -// if (FT_Init_FreeType(&ft)) { -// LOG_WARNING(logging::main_logger, "Could not initiate FreeType."); -// return; -// } -// } - -/// - FontTexture::FontTexture(std::filesystem::path font_file) { + LOG_BACKTRACE(logging::main_logger, "Loading font from {}.", font_file); + FT_Library ft; - if (FT_Init_FreeType(&ft)) { - LOG_WARNING(logging::main_logger, "Could not initiate FreeType."); + if (auto error = FT_Init_FreeType(&ft)) { + LOG_WARNING(logging::main_logger, "Could not initiate FreeType. {}", error); return; } FT_Face font_face; - if (FT_New_Face(ft, font_file.c_str(), 0, &font_face)) { - LOG_WARNING(logging::main_logger, "Could not load Pixelated Font"); + if (auto error = FT_New_Face(ft, font_file.c_str(), 0, &font_face)) { + LOG_WARNING(logging::main_logger, "Could not load font. {}", error); return; } + // 20 is the height in pixels FT_Set_Pixel_Sizes(font_face, 0, 20); - if (FT_Load_Char(font_face, 'a', FT_LOAD_RENDER)) { - LOG_WARNING(logging::main_logger, "Failed to load \"{}\" from font.", 'a'); - return; - } - auto settings = gpu_data::TextureSettings{ .internal_format = gpu_data::GPUPixelStorageFormat::RED, .read_format = gpu_data::GPUPixelReadFormat::RED, @@ -65,17 +51,17 @@ FontTexture::FontTexture(std::filesystem::path font_file) { ascender_height_ = -font_face->ascender; text_height_ = font_face->ascender + descender_height_; + LOG_BACKTRACE(logging::main_logger, "Creating images for each character."); for (unsigned char c = 0; c < 128; c++) { if (FT_Load_Char(font_face, c, FT_LOAD_RENDER | FT_LOAD_MONOCHROME)) { LOG_WARNING(logging::main_logger, "Failed to load \"{}\" from font.", c); - return; + continue; } auto char_size = glm::uvec2(font_face->glyph->bitmap.width, font_face->glyph->bitmap.rows); auto char_position = glm::uvec2(font_face->glyph->bitmap_left, font_face->glyph->bitmap_top); - // auto char_texture = gpu_data::Texture2D(char_size.x, char_size.y, settings); std::vector data; data.resize(char_size.x * char_size.y); @@ -89,9 +75,6 @@ FontTexture::FontTexture(std::filesystem::path font_file) { data[i * font_face->glyph->bitmap.rows + j] = (value & one) * 255; } } - // if (c == 'a' || c == 'b') { - // LOG_DEBUG(logging::main_logger, "{}", data); - // } images.emplace( c, util::image::ByteMonochromeImage( @@ -99,9 +82,6 @@ FontTexture::FontTexture(std::filesystem::path font_file) { ) ); - // image::write_image(images.at(c), files::get_log_path() / - // ("font_as_image_" + std::string(1, c) + ".png")); - font_textures_.emplace( c, Character{ @@ -119,8 +99,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { } } - // std::shared_ptr image(new char[max_height * total_width]); - + LOG_BACKTRACE(logging::main_logger, "Combining characters into single image."); auto image = std::make_shared( total_width, max_height, sizeof(char) ); @@ -132,38 +111,13 @@ FontTexture::FontTexture(std::filesystem::path font_file) { ); } - LOG_DEBUG(logging::main_logger, "saving fonts to file."); - /* auto result_1 = - image::write_image(*image, files::get_log_path() / "font_as_image.png"); - if (result_1 != image::write_result_t::WR_OK) { - image::log_result(result_1, files::get_log_path() / "font_as_image.png"); - }*/ + LOG_BACKTRACE(logging::main_logger, "Loading font to texture."); image->transpose(); texture_ = std::make_shared(image, settings); GlobalContext& global_context = GlobalContext::instance(); global_context.run_opengl_queue(); - - /* - auto font_image_from_gpu = texture_->get_image(); - - if (auto font_image_from_gpu_typed = - std::dynamic_pointer_cast( - font_image_from_gpu - )) { - font_image_from_gpu_typed->transpose(); - auto result_2 = image::write_image( - *font_image_from_gpu_typed, - files::get_log_path() / "font_as_image_from_texture.png" - ); - if (result_2 != image::write_result_t::WR_OK) { - image::log_result( - result_2, files::get_log_path() / "font_as_image_from_texture.png" - ); - } - } - */ } } // namespace structures diff --git a/src/gui/scene/controls.cpp b/src/gui/scene/controls.cpp index df58995f..5bd0dde6 100644 --- a/src/gui/scene/controls.cpp +++ b/src/gui/scene/controls.cpp @@ -94,13 +94,12 @@ Controls::handle_pooled_inputs(GLFWwindow* window) { ); // display range max // Camera matrix view_matrix_ = glm::lookAt( - position_, // Camera is here - position_ - + direction, // and looks here : at the same position_, plus "direction" - screen_up // Head is up (set to 0,-1,0 to look upside-down) + position_, // Camera is here + position_ + direction, // look along direction + screen_up // set up direction ); - // For the next frame, the "last time" will be "now" + // Update time glfw_previous_time_ = currentTime; } From 219bf6d5ed1aba90a844a67ebd96fa95088267c4 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 28 Feb 2026 17:02:19 -0500 Subject: [PATCH 47/56] Revert "maybe this will fix clang" This reverts commit 0785fdd4cdd12abdfdf356d5261907d766e812fa. --- .github/workflows/build-test.yml | 2 +- src/util/png_image.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index a81be54c..90975f65 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -25,7 +25,7 @@ jobs: # - macos-latest compiler: [ { cc: "gcc", cxx: "g++"}, - { cc: "clang-20", cxx: "clang++-20"} + { cc: "clang", cxx: "clang++"} ] build: - Release diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 4c824bee..3741809f 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace util { namespace image { From 68f8f4b2517e36cf7d591ad533add7f54e1a4cbd Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 3 Mar 2026 12:18:43 -0500 Subject: [PATCH 48/56] maybe clang 19 --- .github/workflows/build-test.yml | 2 +- src/util/png_image.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 90975f65..bb480f60 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -25,7 +25,7 @@ jobs: # - macos-latest compiler: [ { cc: "gcc", cxx: "g++"}, - { cc: "clang", cxx: "clang++"} + { cc: "clang-19", cxx: "clang++-19"} ] build: - Release diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 3741809f..4c824bee 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -31,7 +31,6 @@ #include #include #include -#include namespace util { namespace image { From 6b993fa8f1ec31412709e032ebd6f3e367c05fbe Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 3 Mar 2026 12:51:01 -0500 Subject: [PATCH 49/56] apt install --- .github/workflows/build-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index bb480f60..202a4387 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -44,10 +44,11 @@ jobs: with: submodules: 'recursive' - - name: Install Ninja + - name: Install Ninja & Clang-19 run: | sudo apt update sudo apt install ninja-build -y + sudo apt install clang-19 -y - name: Install Dependencies run: | From 2fbd53257ec5b5651c3a15bfffd11b6dc3f541ee Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Tue, 3 Mar 2026 13:04:30 -0500 Subject: [PATCH 50/56] Set Color with uniform --- resources/shaders/overlay/TextWindow.frag | 8 +++--- src/gui/render/structures/uniform_types.hpp | 27 ++++++++++++++++++++- src/gui/the_buttons/text_widget.hpp | 14 +++++++++-- src/gui/the_buttons/user_interface.cpp | 6 ++++- src/gui/the_buttons/user_interface.hpp | 2 +- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/resources/shaders/overlay/TextWindow.frag b/resources/shaders/overlay/TextWindow.frag index 07d6eeb9..30a92085 100644 --- a/resources/shaders/overlay/TextWindow.frag +++ b/resources/shaders/overlay/TextWindow.frag @@ -5,18 +5,18 @@ layout(location = 0) out vec3 color; uniform usampler2D font_texture; -//uniform vec3 font_color; +// right now only using the rgb components +// may in the future use the alpha component +uniform vec4 font_color; in vec2 UV; void main() { - vec3 font_color = vec3(0.6,0.2,0.1); - uint alpha = texelFetch(font_texture, ivec2(UV), 0).r; if (alpha > 0) { - color = font_color; + color = font_color.rgb; } else { discard; } diff --git a/src/gui/render/structures/uniform_types.hpp b/src/gui/render/structures/uniform_types.hpp index c0a8d4a5..9a32e1d9 100644 --- a/src/gui/render/structures/uniform_types.hpp +++ b/src/gui/render/structures/uniform_types.hpp @@ -105,7 +105,6 @@ class SpectralLight : public shader::UniformExecutor { sunlight_color.r, sunlight_color.g, sunlight_color.b ); - // here glUniform3f(uniform_ID, sunlight_color.r, sunlight_color.g, sunlight_color.b); } }; @@ -475,6 +474,32 @@ class TextureRegionsUniform : public shader::UniformExecutor { } }; +class FloatColorUniform : public shader::UniformExecutor { + private: + ColorFloat color_; + + public: + FloatColorUniform() : UniformExecutor(gpu_data::GPUArayType::FLOAT_VEC4) {} + + virtual ~FloatColorUniform() {}; + + inline virtual void + bind(GLint uniform_ID) const override { + LOG_BACKTRACE( + logging::opengl_logger, + "Uniform {}, value: ({}, {}, {}, {}), being initialized.", uniform_ID, + color_.r, color_.g, color_.b, color_.a + ); + + glUniform4f(uniform_ID, color_.r, color_.g, color_.b, color_.a); + } + + inline void + set_color(const ColorFloat&& color) { + color_ = color; + } +}; + } // namespace render } // namespace gui diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index ff1c4e5d..e6b2eff9 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -6,6 +6,7 @@ #include "gui/render/gpu_data/vertex_buffer_object.hpp" #include "gui/render/structures/font.hpp" #include "types.hpp" +#include "util/color.hpp" #include "widget.hpp" #include @@ -26,6 +27,9 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl std::string text_; uint32_t num_characters_; + // I guess all the text needs to be one color + ColorFloat text_color_; + bool wrap_text_; uint8_t text_scale_; @@ -58,7 +62,8 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl inline TextWidget( WidgetInterface* parent, std::shared_ptr font, glm::ivec2 position, glm::ivec2 widget_size, std::string text = std::string(""), - bool differed = true, bool wrap_text = true, uint8_t text_scale = 4 + bool differed = true, bool wrap_text = true, uint8_t text_scale = 4, + ColorFloat text_color = color::black ) : WidgetBase( parent, position, widget_size, @@ -68,7 +73,7 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl vertex_array_object_(differed), font_(font), text_(text), num_characters_(text_.length()), - wrap_text_(wrap_text), text_scale_(text_scale) { + wrap_text_(wrap_text), text_color_(text_color), text_scale_(text_scale) { if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { initialize(); }); @@ -95,6 +100,11 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl // return 12; } + inline ColorFloat + get_text_color() const { + return text_color_; + } + virtual gpu_data::GPUArayType get_element_type() const { return element_array_.get_opengl_numeric_type(); diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index dec7e1c0..ffce03f2 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -27,7 +27,8 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s border_sizes_(std::make_shared()), side_lengths_(std::make_shared()), inner_pattern_size_(std::make_shared()), - texture_regions_(std::make_shared()) { + texture_regions_(std::make_shared()), + font_color_uniform_(std::make_shared()) { shader::Program& window_render_program = shader_handler.load_program( "Windows", files::get_resources_path() / "shaders" / "overlay" / "Widget.vert", files::get_resources_path() / "shaders" / "overlay" / "FramedWindow.frag" @@ -70,6 +71,7 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s text_render_program.set_uniform(frame_size_uniform_, "frame_size"); text_render_program.set_uniform(ui_scale_uniform_, "ui_scale"); text_render_program.set_uniform(frame_texture_uniform_, "font_texture"); + text_render_program.set_uniform(font_color_uniform_, "font_color"); // vec3 font color_uniform // vec2 position @@ -189,6 +191,8 @@ UserInterface::render_frame( ); // set uniforms + font_color_uniform_->set_color(widget->get_text_color()); + text_pipeline_->render( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, widget diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index 070cd600..cc847392 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -26,7 +26,7 @@ class UserInterface : public virtual scene::Inputs { std::shared_ptr side_lengths_; std::shared_ptr inner_pattern_size_; std::shared_ptr texture_regions_; - // std::shared_ptr font_texture_uniform_; + std::shared_ptr font_color_uniform_; // widget renderer std::shared_ptr window_pipeline_; From 886d59ab5f03147d15e8515d1913c7b18018c441 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Fri, 6 Mar 2026 22:52:42 -0500 Subject: [PATCH 51/56] comments --- src/gui/render/graphics_shaders/render_types.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/render/graphics_shaders/render_types.hpp b/src/gui/render/graphics_shaders/render_types.hpp index 5d2ff51f..8e0e007b 100644 --- a/src/gui/render/graphics_shaders/render_types.hpp +++ b/src/gui/render/graphics_shaders/render_types.hpp @@ -43,7 +43,13 @@ class FrameBuffer { render(screen_size_t width, screen_size_t height, GLuint frame_buffer) = 0; }; -// TODO remove this class +/** + * @brief Render only to a section of the window + * + * @details Renders to the given section of the window. This is used for things + * that get rendered few times per frame, and have a specific location like a + * window. + */ class ScreenSection { public: virtual void render( @@ -52,8 +58,6 @@ class ScreenSection { ) = 0; }; -// blume - /** * @brief Defines virtual classes for writing data to object */ From fb88da7fb30519777f7d7c50532f6211f456abe5 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 20 May 2026 11:12:44 -0400 Subject: [PATCH 52/56] fixed ascender height --- src/gui/render/structures/font.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 37936330..b7c39030 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -48,7 +48,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { std::unordered_map images; descender_height_ = -font_face->descender; - ascender_height_ = -font_face->ascender; + ascender_height_ = font_face->ascender; text_height_ = font_face->ascender + descender_height_; LOG_BACKTRACE(logging::main_logger, "Creating images for each character."); From a31cc12d95119862d66b949ee6c3498741783bb5 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Wed, 20 May 2026 11:12:59 -0400 Subject: [PATCH 53/56] todos and warnings --- src/graphics_main.cpp | 2 +- src/gui/the_buttons/text_widget.hpp | 2 +- src/gui/the_buttons/user_interface.hpp | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/graphics_main.cpp b/src/graphics_main.cpp index e09c60ee..1938b105 100644 --- a/src/graphics_main.cpp +++ b/src/graphics_main.cpp @@ -64,13 +64,13 @@ graphics_main(intro_scene::result result) { screen_size_t window_height = 800; // init graphics + // TODO stream line this part and make sure to clean things up correctly std::optional opt_window = gui::setup_opengl(window_width, window_height); if (!opt_window) { LOG_CRITICAL(logging::opengl_logger, "No Window, Exiting."); return 1; } - // TODO stream line this part and make sure to clean things up correctly GLFWwindow* window = opt_window.value(); gui::setup_opengl_logging(); diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index e6b2eff9..a25479c9 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -73,7 +73,7 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl vertex_array_object_(differed), font_(font), text_(text), num_characters_(text_.length()), - wrap_text_(wrap_text), text_color_(text_color), text_scale_(text_scale) { + text_color_(text_color), wrap_text_(wrap_text), text_scale_(text_scale) { if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { initialize(); }); diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index cc847392..dbac7f85 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -65,6 +65,7 @@ class UserInterface : public virtual scene::Inputs { ui_scale_uniform_->set_ui_scale(ui_scale); } + // What types of frames do I need to add? inline void add(std::shared_ptr frame) { auto pos = frames_.begin(); From 5a5d09d86fea4030a5eecd25d71af2eaa5f6bdfc Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 6 Jun 2026 17:10:44 -0400 Subject: [PATCH 54/56] formatting and comments --- .../graphics_shaders/shader_program.cpp | 3 - .../graphics_shaders/shader_program.hpp | 52 ++++++- src/gui/render/structures/font.hpp | 72 ++++++++- src/gui/the_buttons/bordered_widget.hpp | 45 ++++++ src/gui/the_buttons/bordered_window.cpp | 2 +- src/gui/the_buttons/bordered_window.hpp | 54 +++++++ src/gui/the_buttons/button_widget.hpp | 88 ++++++++++- src/gui/the_buttons/frame.cpp | 2 +- src/gui/the_buttons/frame.hpp | 138 ++++++++++++++---- src/gui/the_buttons/frame_part.hpp | 56 ++++++- src/gui/the_buttons/text_widget.hpp | 92 +++++++++++- src/gui/the_buttons/user_interface.cpp | 3 - src/gui/the_buttons/user_interface.hpp | 88 ++++++++++- src/gui/the_buttons/widget.hpp | 70 ++++++++- 14 files changed, 696 insertions(+), 69 deletions(-) diff --git a/src/gui/render/graphics_shaders/shader_program.cpp b/src/gui/render/graphics_shaders/shader_program.cpp index ab58702b..d25e079d 100644 --- a/src/gui/render/graphics_shaders/shader_program.cpp +++ b/src/gui/render/graphics_shaders/shader_program.cpp @@ -81,11 +81,8 @@ ShaderProgramElements_Windows::render( if (!data->do_render()) { return; } - data->bind(); - // test if T inherits from Instancing or not - auto num_vertices = data->get_num_vertices(); auto element_type = data->get_element_type(); diff --git a/src/gui/render/graphics_shaders/shader_program.hpp b/src/gui/render/graphics_shaders/shader_program.hpp index 900db681..bde74a34 100644 --- a/src/gui/render/graphics_shaders/shader_program.hpp +++ b/src/gui/render/graphics_shaders/shader_program.hpp @@ -118,8 +118,6 @@ class Render_Base { logging::opengl_logger, "Program ID: {}, Name: {}", opengl_program_.get_program_ID(), opengl_program_.get_name() ); - // LOG_DEBUG(logging::opengl_logger, "Uniforms ID: {}", uniforms_.get_names()); - // log_uniforms(shader_program.get_detected_uniforms(), uniforms.get_names()); } void render( @@ -130,30 +128,74 @@ class Render_Base { inline virtual ~Render_Base() {} }; +/** + * @brief Program that renders UI windows + */ class ShaderProgram_Windows : public virtual Render_Base, public virtual render_to::ScreenSection { public: + /** + * @brief Construct a new ShaderProgram_Windows object + * + * @param gui::shader::Program& shader_program shader program to be run on data + * @param std::function setup_commands function to be run to initialize + * program + */ inline ShaderProgram_Windows( - shader::Program& shader_program, const std::function setup_commands + Program& shader_program, const std::function setup_commands ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgram_Windows() {} + /** + * @brief Render to given data to the given framebuffer at the given location + * + * @param screen_size_t x_start Distance from left of start of window + * @param screen_size_t y_start Distance from top of start of window + * @param screen_size_t width Width of window + * @param screen_size_t height Height of window + * @param GLuint framebuffer_ID Framebuffer to render to + * @param gui::gpu_data::GPUData* data OpenGL vertex array buffer data to be used by + * the program + */ void virtual render( - screen_size_t x_start, screen_size_t y_start, screen_size_t width, - screen_size_t height, GLuint framebuffer_ID, const gpu_data::GPUData* data + screen_size_t, screen_size_t y_start, screen_size_t width, screen_size_t height, + GLuint framebuffer_ID, const gpu_data::GPUData* data ) override; }; +/** + * @brief Program that renders UI many windows at the same time + * + * @details eg. Text + */ class ShaderProgramElements_Windows : public virtual Render_Base { public: + /** + * @brief Construct a new ShaderProgramElements_Windows object + * + * @param gui::shader::Program& shader_program shader program to be run on data + * @param std::function setup_commands function to be run to initialize + * program + */ inline ShaderProgramElements_Windows( shader::Program& shader_program, const std::function setup_commands ) : Render_Base(shader_program, setup_commands) {} inline virtual ~ShaderProgramElements_Windows() {} + /** + * @brief Render to given data to the given framebuffer at the given location + * + * @param screen_size_t x_start Distance from left of start of window + * @param screen_size_t y_start Distance from top of start of window + * @param screen_size_t width Width of window + * @param screen_size_t height Height of window + * @param GLuint framebuffer_ID Framebuffer to render to + * @param gui::gpu_data::GPUDataElements* data OpenGL vertex array buffer data to be + * used by the program + */ void virtual render( screen_size_t x_start, screen_size_t y_start, screen_size_t width, screen_size_t height, GLuint framebuffer_ID, diff --git a/src/gui/render/structures/font.hpp b/src/gui/render/structures/font.hpp index bb2b2c5b..9011018f 100644 --- a/src/gui/render/structures/font.hpp +++ b/src/gui/render/structures/font.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file font.hpp + * + * @author @AlemSnyder + * + * @brief Defines FontTexture Class + * + * @ingroup GUI RENDER STRUCTURES + * + */ + #pragma once #include "../gpu_data/texture.hpp" @@ -11,6 +34,9 @@ namespace render { namespace structures { +/** + * @brief Data that defines size and location in texture of a character. + */ struct Character { glm::uvec2 size; glm::ivec2 bearing; @@ -18,25 +44,52 @@ struct Character { glm::ivec4 position_in_texture; }; +/** + * @brief Font data saved as an OpenGL texture. + */ class FontTexture { private: std::shared_ptr texture_; + // map of char to location (represented as a Character) in texture of the rasterred + // font std::unordered_map font_textures_; + // Maximum height of any character in pixels. uint16_t text_height_; + // the distance from the baseline to the top of the character uint16_t ascender_height_; - uint16_t - descender_height_; // the distance from the baseline to the top of the character + // Distance from baseline to bottom or character + uint16_t descender_height_; public: + /** + * @brief Construct a new FontTexture Object from file. + * + * @param std::filesystem::path font_file file to read font from. + */ FontTexture(std::filesystem::path font_file); + /** + * @brief Bind to texture index + * + * @details texture_index is the input in a shader program ie. GL_TEXTURE#. + * + * @param GLuint texture_index index of texture + */ inline virtual void bind(GLuint texture_index) const { texture_->bind(texture_index); } + /** + * @brief Get pointer to Character for given char + * + * @param char character Character to quarry texture location of. + * + * @return const Character* pointer to location in texture of rasterred character or + * nullptr if not found. + */ [[nodiscard]] inline const Character* get_character(char character) const { const auto data = font_textures_.find(character); @@ -53,16 +106,31 @@ class FontTexture { } } + /** + * @brief Get the height of the font + * + * @return uint16_t height of text + */ [[nodiscard]] inline auto get_text_height() const { return text_height_; } + /** + * @brief Get the ascender height + * + * @return uint16_t ascender height + */ [[nodiscard]] inline auto get_ascender_height() const { return ascender_height_; } + /** + * @brief Get the descender height + * + * @return uint16_t descender height + */ [[nodiscard]] inline auto get_descender_height() const { return descender_height_; diff --git a/src/gui/the_buttons/bordered_widget.hpp b/src/gui/the_buttons/bordered_widget.hpp index 0b69336a..c5d31d95 100644 --- a/src/gui/the_buttons/bordered_widget.hpp +++ b/src/gui/the_buttons/bordered_widget.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file bordered_widget.hpp + * + * @author @AlemSnyder + * + * @brief Defines BorderedWidget Class + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once #include "bordered_widget.hpp" @@ -12,6 +35,9 @@ namespace gui { namespace the_buttons { +/** + * @brief A widget with a border. + */ class BorderedWidget : public virtual WidgetBase { private: std::shared_ptr data_; @@ -59,21 +85,40 @@ class BorderedWidget : public virtual WidgetBase { return data_->get_num_vertices(); } + /** + * @brief Bind OpenGL data to use in a program + */ inline virtual void bind() const { data_->bind(); }; + /** + * @brief Clears the OpenGL vertex array inputs + */ inline virtual void release() const { data_->release(); } + /** + * @brief If the widget should be rendered + * + * @return bool true if the widget should be rendered, false otherwise. + */ inline virtual bool do_render() const { return data_->do_render(); }; + /** + * @brief Called by the UI to render this widget to the screen + * + * @param UserInterface* user_interface The UserInterface that is rendering the + * widget + * @param screen_size_t x_position Position on the screen to render the widget + * @param screen_size_t y_position Position on the screen to render the widget + */ void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position diff --git a/src/gui/the_buttons/bordered_window.cpp b/src/gui/the_buttons/bordered_window.cpp index ad29dac7..559620d6 100644 --- a/src/gui/the_buttons/bordered_window.cpp +++ b/src/gui/the_buttons/bordered_window.cpp @@ -26,7 +26,7 @@ BorderedWindow::user_interface_render( ) const { user_interface->render_frame(this, x_position, y_position); - for (const auto& child : children) { + for (const auto& child : children_) { child->user_interface_render( user_interface, x_position + position_.x, y_position + position_.y ); diff --git a/src/gui/the_buttons/bordered_window.hpp b/src/gui/the_buttons/bordered_window.hpp index 8d01306b..95ec8748 100644 --- a/src/gui/the_buttons/bordered_window.hpp +++ b/src/gui/the_buttons/bordered_window.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file bordered_window.hpp + * + * @author @AlemSnyder + * + * @brief Defines BorderedWindow Class + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once #include "frame.hpp" @@ -42,31 +65,62 @@ class BorderedWindow : public virtual FrameBase { inline virtual ~BorderedWindow() {}; + /** + * @brief Get number of vertices on path that surrounds this widget. + * @return unsigned int the number of vertices + */ inline unsigned int get_num_vertices() const { return data_->get_num_vertices(); } + /** + * @brief Bind OpenGL data to use in a program + */ inline virtual void bind() const { data_->bind(); }; + /** + * @brief Clears the OpenGL vertex array inputs + */ inline virtual void release() const { data_->release(); } + /** + * @brief If the widget should be rendered + * + * @return bool true if the widget should be rendered, false otherwise. + */ inline virtual bool do_render() const { return data_->do_render(); }; + /** + * @brief Get the box that bounds of the widget. + * + * @details This should be the smallest rectangle that completely contains the + * widget. + * + * @return std::array [x position, y position, width, height] + */ inline virtual std::array get_bounding_box() const { return {position_.x, position_.y, frame_size_.x, frame_size_.y}; } + /** + * @brief Called by the UI to render this widget to the screen + * + * @param UserInterface* user_interface The UserInterface that is rendering the + * widget + * @param screen_size_t x_position Position on the screen to render the widget + * @param screen_size_t y_position Position on the screen to render the widget + */ virtual void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position diff --git a/src/gui/the_buttons/button_widget.hpp b/src/gui/the_buttons/button_widget.hpp index 3cccd668..bf99fe34 100644 --- a/src/gui/the_buttons/button_widget.hpp +++ b/src/gui/the_buttons/button_widget.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file button_widget.hpp + * + * @author @AlemSnyder + * + * @brief Defines ButtonWidget Class + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once #include "bordered_widget.hpp" @@ -13,6 +36,9 @@ namespace gui { namespace the_buttons { +/** + * + */ class ButtonWidget : public virtual WidgetBase { private: std::shared_ptr data_; @@ -27,22 +53,36 @@ class ButtonWidget : public virtual WidgetBase { ButtonWidget(const ButtonWidget& obj) = delete; /** - * @brief Deleted copy operator + * @brief Default copy operator */ - ButtonWidget& operator=(const ButtonWidget& obj) = delete; + ButtonWidget& operator=(const ButtonWidget& obj) = default; - // TODO reimplement - // https://stackoverflow.com/questions/64325516/move-assignment-operator-and-virtual-inheritance/64326111#64326111 /** * @brief Default move constructor */ ButtonWidget(ButtonWidget&& obj) = delete; + // TODO do this for all virtual classes + // ButtonWidget(ButtonWidget&& obj) { + // static_cast(*this) = std::move(static_cast(obj)); + // data_ = std::move(obj.data_); + // button_function_ = std::move(button_function_); + // } /** * @brief Default move constructor */ ButtonWidget& operator=(ButtonWidget&& obj) = delete; + /** + * @brief Construct a new ButtonWidget object. + * @param WidgetInterface* parent Parent Widget. Will be rendered on top of and + * relative to parent + * @param std::shared_ptr data OpenGL texture of the button + * @param glm::ivec2 position Position in parent widget + * @param glm::ivec2 widget_size size of widget + * @param std::function button_function Function called when button is + * pressed. + */ ButtonWidget( WidgetInterface* parent, std::shared_ptr data, glm::ivec2 position, glm::ivec2 widget_size, @@ -60,26 +100,49 @@ class ButtonWidget : public virtual WidgetBase { inline virtual ~ButtonWidget() {}; + /** + * @brief Get number of vertices on path that surrounds this widget. + * @return unsigned int the number of vertices + */ inline unsigned int get_num_vertices() const { return data_->get_num_vertices(); } + /** + * @brief Bind OpenGL data to use in a program + */ inline virtual void bind() const { data_->bind(); }; + /** + * @brief Clears the OpenGL vertex array inputs + */ inline virtual void release() const { data_->release(); } + /** + * @brief If the widget should be rendered + * + * @return bool true if the widget should be rendered, false otherwise. + */ inline virtual bool do_render() const { return data_->do_render(); }; + /** + * @brief Called by the UI to render this widget to the screen + * + * @param UserInterface* user_interface The UserInterface that is rendering the + * widget + * @param screen_size_t x_position Position on the screen to render the widget + * @param screen_size_t y_position Position on the screen to render the widget + */ inline void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, @@ -94,21 +157,33 @@ class ButtonWidget : public virtual WidgetBase { } } + /** + * @brief Size of the four borders. Used in uniforms + */ [[nodiscard]] inline virtual glm::ivec4 get_border_size() const { return data_->get_border_size(); } + /** + * @brief Size of the four side lengths. Used in uniforms + */ [[nodiscard]] inline virtual glm::ivec4 get_side_lengths() const { return data_->get_side_lengths(); } + /** + * @brief Size of the four borders. Used in uniforms + */ [[nodiscard]] inline virtual glm::ivec2 get_inner_pattern_size() const { return data_->get_inner_pattern_size(); } + /** + * @brief Size of the four borders. Used in uniforms + */ [[nodiscard]] inline virtual std::array get_texture_regions() const { return data_->get_texture_regions(); @@ -116,6 +191,11 @@ class ButtonWidget : public virtual WidgetBase { // rn this may work, but... // want to separate between has clickable and renderable children. + /** + * @brief Quarry if this widget has child widgets. + * + * @return true if there are child widgets, false otherwise. + */ inline bool has_children() const { return false; diff --git a/src/gui/the_buttons/frame.cpp b/src/gui/the_buttons/frame.cpp index 3a6c80df..ff3e8862 100644 --- a/src/gui/the_buttons/frame.cpp +++ b/src/gui/the_buttons/frame.cpp @@ -15,7 +15,7 @@ namespace the_buttons { std::weak_ptr FrameBase::get_child_at_position(screen_size_t x, screen_size_t y) const { - for (const auto& child : children) { + for (const auto& child : children_) { if (child->is_interior(x - position_.x, y - position_.y)) { if (child->has_children()) { return child->get_child_at_position(x - position_.x, y - position_.y); diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index 80253719..8653b20a 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file frame.hpp + * + * @author @AlemSnyder + * + * @brief Defines FrameInterface and FrameBase Classes + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once #include "../render/gpu_data/data_types.hpp" @@ -13,18 +36,45 @@ namespace gui { namespace the_buttons { +/** + * @brief Interface for Frame. Frames hare top level widgets in the UI system. They don't have parents and are rendered relative to the window. + */ class FrameInterface : public virtual WidgetInterface { public: - inline virtual ~FrameInterface() {}; // kill children + inline virtual ~FrameInterface() {}; + /** + * @brief Check if the position of the frame fixed on the screen + * + * @return true if fixed false if not. + */ virtual bool is_fixed() const = 0; + /** + * @brief Check if the window should be rendered + * + * @return false if should not be rendered true if should be + */ inline virtual bool is_visible() const = 0; + /** + * @brief Function called when the Frame is selected + */ virtual void on_select() = 0; + /** + * @brief Function called when any other frame is selected + */ virtual void on_end_select() = 0; + /** + * @brief Get the box that bounds of the widget. + * + * @details This should be the smallest rectangle that completely contains the + * widget. + * + * @return std::array [x position, y position, width, height] + */ virtual std::array get_bounding_box() const = 0; /** @@ -139,9 +189,8 @@ class FrameBase : public virtual FrameInterface { glm::ivec2 frame_size_; std::vector exterior_points_; - // Frame* parent_; bool fixed_; // fixed position in render queue - std::unordered_set> children; + std::unordered_set> children_; bool is_selected; @@ -153,16 +202,36 @@ class FrameBase : public virtual FrameInterface { position_(position), frame_size_(frame_size), exterior_points_(exterior_points), fixed_(fixed) {}; - inline virtual ~FrameBase() {}; // kill children + inline virtual ~FrameBase() {}; + /** + * @brief Test if the given location is within the region of the widget + * + * @param screen_size_t x screen position x coordinate + * @param screen_size_t y screen position y coordinate + */ bool is_interior(screen_size_t x, screen_size_t y) const; + /** + * @brief Get child widget if it exists at the given position. + * + * @param screen_size_t x screen position x coordinate + * @param screen_size_t y screen position y coordinate + * + * @return std::weak_ptr a week pointer to the child widget. + * It will exist if the given location has a child widget. + */ std::weak_ptr get_child_at_position(screen_size_t x, screen_size_t y) const; + /** + * @brief Quarry if this widget has child widgets. + * + * @return true if there are child widgets, false otherwise. + */ [[nodiscard]] inline virtual bool has_children() const override { - return !children.empty(); + return !children_.empty(); } // prevent overlapping children. @@ -174,44 +243,60 @@ class FrameBase : public virtual FrameInterface { // do this be checking if parent is set. // could also do the opposite and require that initialized with parent. + /** + * @brief Check if the position of the frame fixed on the screen + * + * @return true if fixed false if not. + */ inline virtual bool is_fixed() const override { return fixed_; } + /** + * @brief Check if the window should be rendered + * + * @return false if should not be rendered true if should be + */ inline virtual bool is_visible() const override { return true; } + /** + * @brief Function called when the Frame is selected + */ inline virtual void on_select() override {}; + /** + * @brief Function called when any other frame is selected + */ inline virtual void on_end_select() override {}; - // virtual void render_children( - // const UserInterface* user_interface, screen_size_t x_position, - // screen_size_t y_position - // ) const; - - [[nodiscard]] inline screen_size_t - get_x_position() const { - return position_.x; - } - - [[nodiscard]] inline screen_size_t - get_y_position() const { - return position_.y; - } - + /** + * @brief Get the box that bounds of the widget. + * + * @details This should be the smallest rectangle that completely contains the + * widget. + * + * @return std::array [x position, y position, width, height] + */ inline virtual std::array get_bounding_box() const { return {position_.x, position_.y, frame_size_.x, frame_size_.y}; } + /** + * @brief Construct a child widget of given type with given arguments. + * @tparam widget_type T Child widget type + * @tparam ...Args arguments for child widget + * @param ...args arguments for child widget + * @return std::shared_ptr shared_ptr to child widget + */ template [[nodiscard]] inline std::shared_ptr make(Args&&... args) { - auto new_widget = children.emplace(std::make_shared(this, args...)); + auto new_widget = children_.emplace(std::make_shared(this, args...)); if (new_widget.second) { if (auto new_widget_ptr = std::dynamic_pointer_cast(*new_widget.first)) { return new_widget_ptr; @@ -222,12 +307,12 @@ class FrameBase : public virtual FrameInterface { [[nodiscard]] inline auto begin() const { - return children.begin(); + return children_.begin(); } [[nodiscard]] inline auto end() const { - return children.end(); + return children_.end(); } /** @@ -345,13 +430,6 @@ class FrameBase : public virtual FrameInterface { cleanup([[maybe_unused]] GLFWwindow* window) {} }; -// class UI_Text : public virtual Frame { -// private: -// std::string text_; -// }; - -// class Button : public virtual Frame {}; - } // namespace the_buttons } // namespace gui diff --git a/src/gui/the_buttons/frame_part.hpp b/src/gui/the_buttons/frame_part.hpp index 718523a2..6be5e48d 100644 --- a/src/gui/the_buttons/frame_part.hpp +++ b/src/gui/the_buttons/frame_part.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file frame_part.hpp + * + * @author @AlemSnyder + * + * @brief Defines WidgetBase Class + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once #include "types.hpp" @@ -64,18 +87,41 @@ class WidgetBase : public virtual WidgetInterface { return nullptr; } + /** + * @brief Test if the given location is within the region of the widget + * + * @param screen_size_t x screen position x coordinate + * @param screen_size_t y screen position y coordinate + */ virtual bool is_interior(screen_size_t x, screen_size_t y) const override; - // virtual void user_interface_render( - // const UserInterface* user_interface, screen_size_t x_position, - // screen_size_t y_position - // ) const override; - + /** + * @brief Quarry if this widget has child widgets. + * + * @return true if there are child widgets, false otherwise. + */ [[nodiscard]] virtual bool has_children() const override; + /** + * @brief Get child widget if it exists at the given position. + * + * @param screen_size_t x screen position x coordinate + * @param screen_size_t y screen position y coordinate + * + * @return std::weak_ptr a week pointer to the child widget. + * It will exist if the given location has a child widget. + */ virtual std::weak_ptr get_child_at_position(screen_size_t x, screen_size_t y) const override; + /** + * @brief Get the box that bounds of the widget. + * + * @details This should be the smallest rectangle that completely contains the + * widget. + * + * @return std::array [x position, y position, width, height] + */ inline virtual std::array get_bounding_box() const override { return {position_.x, position_.y, frame_size_.x, frame_size_.y}; diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index a25479c9..33a1ffd7 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file text_widget.hpp + * + * @author @AlemSnyder + * + * @brief Defines TextWidget Class + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once #include "bordered_widget.hpp" @@ -15,6 +38,9 @@ namespace gui { namespace the_buttons { +/** + * @brief Widget for rendering text + */ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataElements { private: gpu_data::VertexArrayObject vertex_array_object_; @@ -37,6 +63,10 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl void initialize(); + protected: + // attaches text_data_ to the vertex_array_object_ + void attach_all(); + public: TextWidget() = delete; /** @@ -55,10 +85,22 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl TextWidget(TextWidget&& obj) = delete; /** - * @brief Default move constructor + * @brief Default move operator */ TextWidget& operator=(TextWidget&& obj) = delete; + /** + * @brief Construct a new TextWidget object + * @param WidgetInterface* parent Widget the be rendered relative to + * @param std::shared_ptr font + * @param glm::ivec2 position in parent widget to place text + * @param glm::ivec2 widget_size Size of widget. Text will stay within this region + * @param std::string text = "" + * @param bool differed = true + * @param bool wrap_text = true + * @param uint8_t text_scale = 4 + * @param ColorFloat text_color = color::black + */ inline TextWidget( WidgetInterface* parent, std::shared_ptr font, glm::ivec2 position, glm::ivec2 widget_size, std::string text = std::string(""), @@ -85,8 +127,11 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl inline virtual ~TextWidget() {}; - void attach_all(); - + /** + * @brief Set the display text to the given string + * + * @param std::string&& `text` text to display in the widget. + */ inline void set_text(std::string&& text) { text_ = text; @@ -94,22 +139,40 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl update_text_data(); } + /** + * @brief Get the number of vertices + * + * @return `unsigned int` the number of vertices. This is equal to six times the + * number of characters. + */ inline unsigned int get_num_vertices() const { return num_characters_ * 6; // four vertices per character - // return 12; } + /** + * @brief Get the text color + * + * @return ColorFloat color of the text + */ inline ColorFloat get_text_color() const { return text_color_; } + /** + * @brief Get the element type. In this case I think it's `uint16_t` + * + * @return `gpu_data::GPUArayType::UNSIGNED_SHORT` (to the best of my knownage) + */ virtual gpu_data::GPUArayType get_element_type() const { return element_array_.get_opengl_numeric_type(); } + /** + * @brief Bind OpenGL data to use in a program + */ inline virtual void bind() const { font_->bind(0); @@ -117,21 +180,42 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl element_array_.bind(); }; + /** + * @brief Clears the OpenGL vertex array inputs + */ inline virtual void release() const { vertex_array_object_.release(); } + /** + * @brief If the widget should be rendered + * + * @return bool true if the widget should be rendered, false otherwise. + */ inline virtual bool do_render() const { return true; }; + /** + * @brief Called by the UI to render this widget to the screen + * + * @param UserInterface* user_interface The UserInterface that is rendering the + * widget + * @param screen_size_t x_position Position on the screen to render the widget + * @param screen_size_t y_position Position on the screen to render the widget + */ void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position ) const override; + /** + * @brief Calculates the texture location to window space position for the given text. + * + * @return std::vector A vector of positions. The first two values in the uvec4 are the position in the widget, and the last two are the position in the texture. + */ [[nodiscard]] std::vector generate_data() const; }; diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index ffce03f2..3eef96b1 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -219,9 +219,6 @@ UserInterface::get_frame( return {}; } - // auto x_offset = (*frame_outer)->get_x_position(); - // auto y_offset = (*frame_outer)->get_y_position(); - std::weak_ptr new_frame_outer = *frame_outer; std::weak_ptr frame_inner = (*frame_outer)->get_child_at_position(mouse_position_x, mouse_position_y); diff --git a/src/gui/the_buttons/user_interface.hpp b/src/gui/the_buttons/user_interface.hpp index dbac7f85..f4b39c8e 100644 --- a/src/gui/the_buttons/user_interface.hpp +++ b/src/gui/the_buttons/user_interface.hpp @@ -1,3 +1,26 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file user_interface.hpp + * + * @author @AlemSnyder + * + * @brief Defines UserInterface Class + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once #include "../render/graphics_shaders/shader_program.hpp" @@ -9,6 +32,7 @@ #include namespace gui { + namespace the_buttons { class BorderedWidget; @@ -16,6 +40,9 @@ class BorderedWindow; class ButtonWidget; class TextWidget; +/** + * @brief Top leven UI. Handles inputs and forwards inputs to widgets. + */ class UserInterface : public virtual scene::Inputs { private: // uniform @@ -32,14 +59,17 @@ class UserInterface : public virtual scene::Inputs { std::shared_ptr window_pipeline_; std::shared_ptr text_pipeline_; + // set of all frames std::list> frames_; + // selected frame + std::shared_ptr selected_frame_; - std::shared_ptr selected_frame_; // widget? - + // get frame at given location [[nodiscard]] std::pair< std::weak_ptr, std::weak_ptr> get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) const; + // get frame at given location [[nodiscard]] inline std::pair< std::weak_ptr, std::weak_ptr> get_frame(screen_size_t mouse_position_x, screen_size_t mouse_position_y) { @@ -53,41 +83,91 @@ class UserInterface : public virtual scene::Inputs { ); } + // render to window void reselect_frame(GLFWwindow* window); public: + /** + * @brief Construct a new UserInterface object + * + * @param shader::ShaderHandler& shader_handler + * @param uint8_t ui_scale + */ UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_scale); + /** + * @brief Update the entire user interface using the given screen size. + * + * @param screen_size_t width width of screen + * @param screen_size_t height height of screen + */ void update(screen_size_t width, screen_size_t height); + /** + * @brief Set the ui scale + * + * @param uint8_t ui_scale Scale to set the ui. Number of screen pixels per UI pixel + */ inline void set_ui_scale(uint8_t ui_scale) { ui_scale_uniform_->set_ui_scale(ui_scale); } - // What types of frames do I need to add? + /** + * @brief Add new frame to the user interface + * + * @param std::shared_ptr frame frame to add + */ inline void add(std::shared_ptr frame) { auto pos = frames_.begin(); frames_.insert(pos, frame); } - // one of these for each + // Each type of widget and frame needs a different method to render. Visitor pattern + /** + * @brief Render a BorderedWindow + * + * @param const BorderedWindow* frame + * @param screen_size_t x_frame_position + * @param screen_size_t y_frame_position + */ void render_frame( const BorderedWindow* frame, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; + /** + * @brief Render a BorderedWidget + * + * @param const BorderedWidget* frame + * @param screen_size_t x_frame_position + * @param screen_size_t y_frame_position + */ void render_frame( const BorderedWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; + /** + * @brief Render a ButtonWidget + * + * @param const ButtonWidget* frame + * @param screen_size_t x_frame_position + * @param screen_size_t y_frame_position + */ void render_frame( const ButtonWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position ) const; + /** + * @brief Render a TextWidget + * + * @param const TextWidget* frame + * @param screen_size_t x_frame_position + * @param screen_size_t y_frame_position + */ void render_frame( const TextWidget* widget, screen_size_t x_frame_position, screen_size_t y_frame_position diff --git a/src/gui/the_buttons/widget.hpp b/src/gui/the_buttons/widget.hpp index 8e417f27..b7c44deb 100644 --- a/src/gui/the_buttons/widget.hpp +++ b/src/gui/the_buttons/widget.hpp @@ -1,6 +1,28 @@ +// -*- lsst-c++ -*- +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/** + * @file widget.hpp + * + * @author @AlemSnyder + * + * @brief Defines WidgetInterface Class + * + * @ingroup GUI THE_BUTTONS + * + */ + #pragma once -// #include "frame.hpp" #include "../render/gpu_data/data_types.hpp" #include "../scene/input.hpp" @@ -10,27 +32,61 @@ namespace the_buttons { class UserInterface; +/** + * @brief Interface for widget in UI + */ class WidgetInterface : public virtual scene::Inputs, public virtual gpu_data::GPUData { public: - inline virtual ~WidgetInterface() {}; // kill children + inline virtual ~WidgetInterface() {}; + /** + * @brief Test if the given location is within the region of the widget + * + * @param screen_size_t x screen position x coordinate + * @param screen_size_t y screen position y coordinate + */ virtual bool is_interior(screen_size_t x, screen_size_t y) const = 0; + /** + * @brief Called by the UI to render this widget to the screen + * + * @param UserInterface* user_interface The UserInterface that is rendering the + * widget + * @param screen_size_t x_position Position on the screen to render the widget + * @param screen_size_t y_position Position on the screen to render the widget + */ virtual void user_interface_render( const UserInterface* user_interface, screen_size_t x_position, screen_size_t y_position ) const = 0; - // inline virtual void render_children( - // const UserInterface* user_interface, screen_size_t x_position, - // screen_size_t y_position - // ) const = 0; - + /** + * @brief Quarry if this widget has child widgets. + * + * @return true if there are child widgets, false otherwise. + */ virtual bool has_children() const = 0; + /** + * @brief Get child widget if it exists at the given position. + * + * @param screen_size_t x screen position x coordinate + * @param screen_size_t y screen position y coordinate + * + * @return std::weak_ptr a week pointer to the child widget. + * It will exist if the given location has a child widget. + */ virtual std::weak_ptr get_child_at_position(screen_size_t x, screen_size_t y) const = 0; + /** + * @brief Get the box that bounds of the widget. + * + * @details This should be the smallest rectangle that completely contains the + * widget. + * + * @return std::array [x position, y position, width, height] + */ virtual std::array get_bounding_box() const = 0; /** From cccc931f6bef7002d5e34ff445093c632c396884 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 6 Jun 2026 17:18:33 -0400 Subject: [PATCH 55/56] comment for button widget --- src/gui/the_buttons/button_widget.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/the_buttons/button_widget.hpp b/src/gui/the_buttons/button_widget.hpp index bf99fe34..0116e9cd 100644 --- a/src/gui/the_buttons/button_widget.hpp +++ b/src/gui/the_buttons/button_widget.hpp @@ -37,7 +37,7 @@ namespace gui { namespace the_buttons { /** - * + * @brief Widget with the ability to call a function when it is "pressed" */ class ButtonWidget : public virtual WidgetBase { private: From 3cafaf64148f31d61ba79f38a3f730baee9c6f49 Mon Sep 17 00:00:00 2001 From: Alem Snyder Date: Sat, 6 Jun 2026 17:29:28 -0400 Subject: [PATCH 56/56] formatting --- src/gui/the_buttons/frame.hpp | 11 ++++++----- src/gui/the_buttons/text_widget.hpp | 9 ++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/gui/the_buttons/frame.hpp b/src/gui/the_buttons/frame.hpp index 8653b20a..7d8bf098 100644 --- a/src/gui/the_buttons/frame.hpp +++ b/src/gui/the_buttons/frame.hpp @@ -37,7 +37,8 @@ namespace gui { namespace the_buttons { /** - * @brief Interface for Frame. Frames hare top level widgets in the UI system. They don't have parents and are rendered relative to the window. + * @brief Interface for Frame. Frames hare top level widgets in the UI system. They + * don't have parents and are rendered relative to the window. */ class FrameInterface : public virtual WidgetInterface { public: @@ -45,14 +46,14 @@ class FrameInterface : public virtual WidgetInterface { /** * @brief Check if the position of the frame fixed on the screen - * + * * @return true if fixed false if not. */ virtual bool is_fixed() const = 0; /** * @brief Check if the window should be rendered - * + * * @return false if should not be rendered true if should be */ inline virtual bool is_visible() const = 0; @@ -245,7 +246,7 @@ class FrameBase : public virtual FrameInterface { /** * @brief Check if the position of the frame fixed on the screen - * + * * @return true if fixed false if not. */ inline virtual bool @@ -255,7 +256,7 @@ class FrameBase : public virtual FrameInterface { /** * @brief Check if the window should be rendered - * + * * @return false if should not be rendered true if should be */ inline virtual bool diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index 33a1ffd7..dac91fb1 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -212,9 +212,12 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl ) const override; /** - * @brief Calculates the texture location to window space position for the given text. - * - * @return std::vector A vector of positions. The first two values in the uvec4 are the position in the widget, and the last two are the position in the texture. + * @brief Calculates the texture location to window space position for the given + * text. + * + * @return std::vector A vector of positions. The first two values in + * the uvec4 are the position in the widget, and the last two are the position in + * the texture. */ [[nodiscard]] std::vector generate_data() const; };