From 0e4c55afd651a3e3ca8c4242569cc8fccdeae9b5 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sat, 25 Nov 2023 21:43:27 +0100 Subject: [PATCH] renderer: Add drag select in HUD renderer. --- libopenage/renderer/stages/hud/hud_object.cpp | 71 +++++++++++++++---- libopenage/renderer/stages/hud/hud_object.h | 48 +++++++++++-- .../renderer/stages/hud/hud_render_entity.cpp | 28 ++++++-- .../renderer/stages/hud/hud_render_entity.h | 46 ++++++++++-- .../renderer/stages/hud/hud_renderer.cpp | 53 ++++++++++---- libopenage/renderer/stages/hud/hud_renderer.h | 23 +++--- 6 files changed, 217 insertions(+), 52 deletions(-) diff --git a/libopenage/renderer/stages/hud/hud_object.cpp b/libopenage/renderer/stages/hud/hud_object.cpp index c923adbda02..87b5fc6ffbc 100644 --- a/libopenage/renderer/stages/hud/hud_object.cpp +++ b/libopenage/renderer/stages/hud/hud_object.cpp @@ -2,37 +2,43 @@ #include "hud_object.h" +#include "renderer/geometry.h" #include "renderer/stages/hud/hud_render_entity.h" namespace openage::renderer::hud { -HudObject::HudObject(const std::shared_ptr &asset_manager) : +HudDragObject::HudDragObject(const std::shared_ptr &asset_manager) : require_renderable{true}, changed{false}, camera{nullptr}, asset_manager{asset_manager}, render_entity{nullptr}, + drag_pos{nullptr, 0, "", nullptr, {0, 0}}, + drag_start{0, 0}, uniforms{nullptr}, + geometry{nullptr}, last_update{0.0} { } -void HudObject::set_render_entity(const std::shared_ptr &entity) { +void HudDragObject::set_render_entity(const std::shared_ptr &entity) { this->render_entity = entity; this->fetch_updates(); } -void HudObject::set_camera(const std::shared_ptr &camera) { +void HudDragObject::set_camera(const std::shared_ptr &camera) { this->camera = camera; } -void HudObject::fetch_updates(const time::time_t &time) { +void HudDragObject::fetch_updates(const time::time_t &time) { if (not this->render_entity->is_changed()) { // exit early because there is nothing to do return; } + // Get data from render entity - // TODO + this->drag_start = this->render_entity->get_drag_start(); + this->drag_pos.sync(this->render_entity->get_drag_pos(), this->last_update); // Set self to changed so that world renderer can update the renderable this->changed = true; @@ -40,32 +46,73 @@ void HudObject::fetch_updates(const time::time_t &time) { this->last_update = time; } -void HudObject::update_uniforms(const time::time_t &time) { +void HudDragObject::update_uniforms(const time::time_t & /* time */) { // TODO: Only update uniforms that changed since last update if (this->uniforms == nullptr) [[unlikely]] { return; } - // TODO + + // TODO: Do something with the uniforms } -bool HudObject::requires_renderable() { +void HudDragObject::update_geometry(const time::time_t &time) { + // TODO: Only update geometry that changed since last update + if (this->geometry == nullptr) [[unlikely]] { + return; + } + + auto drag_start_ndc = this->drag_start.to_viewport(this->camera).to_ndc_space(this->camera); + auto drag_pos_ndc = this->drag_pos.get(time).to_viewport(this->camera).to_ndc_space(this->camera); + + float top = std::max(drag_start_ndc.y(), drag_pos_ndc.y()); + float bottom = std::min(drag_start_ndc.y(), drag_pos_ndc.y()); + float left = std::min(drag_start_ndc.x(), drag_pos_ndc.x()); + float right = std::max(drag_start_ndc.x(), drag_pos_ndc.x()); + + std::array quad_vertices{ + top, left, 0.0f, 1.0f, // top left corner + bottom, + left, + 0.0f, + 0.0f, // bottom left corner + top, + right, + 1.0f, + 1.0f, // top right corner + bottom, + right, + 1.0f, + 0.0f // bottom right corner + }; + + std::vector vertex_data(quad_vertices.size() * sizeof(float)); + std::memcpy(vertex_data.data(), quad_vertices.data(), vertex_data.size()); + + this->geometry->update_verts(vertex_data); +} + +bool HudDragObject::requires_renderable() { return this->require_renderable; } -void HudObject::clear_requires_renderable() { +void HudDragObject::clear_requires_renderable() { this->require_renderable = false; } -bool HudObject::is_changed() { +bool HudDragObject::is_changed() { return this->changed; } -void HudObject::clear_changed_flag() { +void HudDragObject::clear_changed_flag() { this->changed = false; } -void HudObject::set_uniforms(const std::shared_ptr &uniforms) { +void HudDragObject::set_uniforms(const std::shared_ptr &uniforms) { this->uniforms = uniforms; } +void HudDragObject::set_geometry(const std::shared_ptr &geometry) { + this->geometry = geometry; +} + } // namespace openage::renderer::hud diff --git a/libopenage/renderer/stages/hud/hud_object.h b/libopenage/renderer/stages/hud/hud_object.h index 8de81df5919..0da212aa296 100644 --- a/libopenage/renderer/stages/hud/hud_object.h +++ b/libopenage/renderer/stages/hud/hud_object.h @@ -7,10 +7,13 @@ #include #include +#include "coord/pixel.h" +#include "curve/continuous.h" #include "time/time.h" namespace openage::renderer { +class Geometry; class UniformInput; namespace camera { @@ -23,19 +26,19 @@ class Animation2dInfo; } // namespace resources namespace hud { -class HudRenderEntity; +class HudDragRenderEntity; -class HudObject { +class HudDragObject { public: - HudObject(const std::shared_ptr &asset_manager); - ~HudObject() = default; + HudDragObject(const std::shared_ptr &asset_manager); + ~HudDragObject() = default; /** * Set the world render entity. * * @param entity New world render entity. */ - void set_render_entity(const std::shared_ptr &entity); + void set_render_entity(const std::shared_ptr &entity); /** * Set the current camera of the scene. @@ -58,6 +61,13 @@ class HudObject { */ void update_uniforms(const time::time_t &time = 0.0); + /** + * Update the geometry of the renderable associated with this object. + * + * @param time Current simulation time. + */ + void update_geometry(const time::time_t &time = 0.0); + /** * Check whether a new renderable needs to be created for this mesh. * @@ -95,6 +105,15 @@ class HudObject { */ void set_uniforms(const std::shared_ptr &uniforms); + /** + * Set the geometry of the renderable associated with this object. + * + * The geometry is updated when calling \p update(). + * + * @param geometry Geometry of this object's renderable. + */ + void set_geometry(const std::shared_ptr &geometry); + private: /** * Stores whether a new renderable for this object needs to be created @@ -120,13 +139,28 @@ class HudObject { /** * Source for positional and texture data. */ - std::shared_ptr render_entity; + std::shared_ptr render_entity; /** - * Shader uniforms for the renderable in the terrain render pass. + * Position of the dragged corner. + */ + curve::Continuous drag_pos; + + /** + * Position of the start corner. + */ + coord::input drag_start; + + /** + * Shader uniforms for the renderable in the HUD render pass. */ std::shared_ptr uniforms; + /** + * Geometry of the renderable in the HUD render pass. + */ + std::shared_ptr geometry; + /** * Time of the last update call. */ diff --git a/libopenage/renderer/stages/hud/hud_render_entity.cpp b/libopenage/renderer/stages/hud/hud_render_entity.cpp index b43f25bfa7a..b57e7f911e6 100644 --- a/libopenage/renderer/stages/hud/hud_render_entity.cpp +++ b/libopenage/renderer/stages/hud/hud_render_entity.cpp @@ -7,30 +7,44 @@ namespace openage::renderer::hud { -HudRenderEntity::HudRenderEntity() : +HudDragRenderEntity::HudDragRenderEntity(const coord::input drag_start) : changed{false}, - last_update{0.0} { + last_update{0.0}, + drag_pos{nullptr, 0, "", nullptr, drag_start}, + drag_start{drag_start} { } -void HudRenderEntity::update(const time::time_t time) { +void HudDragRenderEntity::update(const coord::input drag_pos, + const time::time_t time) { std::unique_lock lock{this->mutex}; - // TODO + this->drag_pos.set_insert(time, drag_pos); + + this->last_update = time; + this->changed = true; } -time::time_t HudRenderEntity::get_update_time() { +time::time_t HudDragRenderEntity::get_update_time() { std::shared_lock lock{this->mutex}; return this->last_update; } -bool HudRenderEntity::is_changed() { +const curve::Continuous &HudDragRenderEntity::get_drag_pos() { + return this->drag_pos; +} + +const coord::input &HudDragRenderEntity::get_drag_start() { + return this->drag_start; +} + +bool HudDragRenderEntity::is_changed() { std::shared_lock lock{this->mutex}; return this->changed; } -void HudRenderEntity::clear_changed_flag() { +void HudDragRenderEntity::clear_changed_flag() { std::unique_lock lock{this->mutex}; this->changed = false; diff --git a/libopenage/renderer/stages/hud/hud_render_entity.h b/libopenage/renderer/stages/hud/hud_render_entity.h index e5b227a944a..5b356909074 100644 --- a/libopenage/renderer/stages/hud/hud_render_entity.h +++ b/libopenage/renderer/stages/hud/hud_render_entity.h @@ -3,24 +3,34 @@ #pragma once #include -#include #include #include +#include "coord/pixel.h" +#include "curve/continuous.h" #include "time/time.h" namespace openage::renderer::hud { -class HudRenderEntity { +class HudDragRenderEntity { public: - HudRenderEntity(); - ~HudRenderEntity() = default; + /** + * Create a new render entity for drag selection in the HUD. + * + * @param drag_start Position of the start corner. + */ + HudDragRenderEntity(const coord::input drag_start); + ~HudDragRenderEntity() = default; /** - * TODO: Update the render entity with information from the gamestate. + * Update the render entity with information from the gamestate. + * + * @param drag_pos Position of the dragged corner. + * @param time Current simulation time. */ - void update(const time::time_t time = 0.0); + void update(const coord::input drag_pos, + const time::time_t time = 0.0); /** * Get the time of the last update. @@ -29,6 +39,20 @@ class HudRenderEntity { */ time::time_t get_update_time(); + /** + * Get the position of the dragged corner. + * + * @return Coordinates of the dragged corner. + */ + const curve::Continuous &get_drag_pos(); + + /** + * Get the position of the start corner. + * + * @return Coordinates of the start corner. + */ + const coord::input &get_drag_start(); + /** * Check whether the render entity has received new updates from the * gamestate. @@ -55,6 +79,16 @@ class HudRenderEntity { */ time::time_t last_update; + /** + * Position of the dragged corner. + */ + curve::Continuous drag_pos; + + /** + * Position of the start corner. + */ + coord::input drag_start; + /** * Mutex for protecting threaded access. */ diff --git a/libopenage/renderer/stages/hud/hud_renderer.cpp b/libopenage/renderer/stages/hud/hud_renderer.cpp index 295c2222302..6b8827339fc 100644 --- a/libopenage/renderer/stages/hud/hud_renderer.cpp +++ b/libopenage/renderer/stages/hud/hud_renderer.cpp @@ -25,7 +25,7 @@ HudRenderer::HudRenderer(const std::shared_ptr &window, renderer{renderer}, camera{camera}, asset_manager{asset_manager}, - render_objects{}, + drag_object{nullptr}, clock{clock} { renderer::opengl::GlContext::check_error(); @@ -43,20 +43,49 @@ std::shared_ptr HudRenderer::get_render_pass() { return this->render_pass; } -void HudRenderer::add_render_entity(const std::shared_ptr entity) { +void HudRenderer::add_drag_entity(const std::shared_ptr entity) { std::unique_lock lock{this->mutex}; - auto hud_object = std::make_shared(this->asset_manager); + auto hud_object = std::make_shared(this->asset_manager); hud_object->set_render_entity(entity); hud_object->set_camera(this->camera); - this->render_objects.push_back(hud_object); + this->drag_object = hud_object; +} + +void HudRenderer::remove_drag_entity() { + std::unique_lock lock{this->mutex}; + + this->drag_object = nullptr; + this->render_pass->clear_renderables(); } void HudRenderer::update() { std::unique_lock lock{this->mutex}; auto current_time = this->clock->get_real_time(); - for (auto &obj : this->render_objects) { - // TODO + + if (this->drag_object) { + this->drag_object->fetch_updates(current_time); + if (this->drag_object->requires_renderable()) { + auto geometry = this->renderer->add_bufferless_quad(); + auto transform_unifs = this->drag_select_shader->new_uniform_input( + "in_col", + Eigen::Vector4f{1.0f, 1.0f, 1.0f, 0.2f}); + + Renderable display_obj{ + transform_unifs, + geometry, + true, + true, + }; + + this->render_pass->add_renderables(display_obj); + this->drag_object->clear_requires_renderable(); + + this->drag_object->set_uniforms(transform_unifs); + this->drag_object->set_geometry(geometry); + } + this->drag_object->update_uniforms(current_time); + this->drag_object->update_geometry(current_time); } } @@ -71,27 +100,27 @@ void HudRenderer::resize(size_t width, size_t height) { void HudRenderer::initialize_render_pass(size_t width, size_t height, const util::Path &shaderdir) { - // ASDF: add vertex shader - auto vert_shader_file = (shaderdir / "world2d.vert.glsl").open(); + // Drag select shader + auto vert_shader_file = (shaderdir / "hud_drag_select.vert.glsl").open(); auto vert_shader_src = renderer::resources::ShaderSource( resources::shader_lang_t::glsl, resources::shader_stage_t::vertex, vert_shader_file.read()); vert_shader_file.close(); - // ASDF: add fragment shader - auto frag_shader_file = (shaderdir / "world2d.frag.glsl").open(); + auto frag_shader_file = (shaderdir / "hud_drag_select.frag.glsl").open(); auto frag_shader_src = renderer::resources::ShaderSource( resources::shader_lang_t::glsl, resources::shader_stage_t::fragment, frag_shader_file.read()); frag_shader_file.close(); + this->drag_select_shader = this->renderer->add_shader({vert_shader_src, frag_shader_src}); + + // Texture targets this->output_texture = renderer->add_texture(resources::Texture2dInfo(width, height, resources::pixel_format::rgba8)); this->depth_texture = renderer->add_texture(resources::Texture2dInfo(width, height, resources::pixel_format::depth24)); - this->display_shader = this->renderer->add_shader({vert_shader_src, frag_shader_src}); - auto fbo = this->renderer->create_texture_target({this->output_texture, this->depth_texture}); this->render_pass = this->renderer->add_render_pass({}, fbo); } diff --git a/libopenage/renderer/stages/hud/hud_renderer.h b/libopenage/renderer/stages/hud/hud_renderer.h index f085e825f87..0373757adb7 100644 --- a/libopenage/renderer/stages/hud/hud_renderer.h +++ b/libopenage/renderer/stages/hud/hud_renderer.h @@ -30,8 +30,8 @@ class AssetManager; } namespace hud { -class HudObject; -class HudRenderEntity; +class HudDragObject; +class HudDragRenderEntity; /** * Renderer for the "Heads-Up Display" (HUD). @@ -55,11 +55,18 @@ class HudRenderer { std::shared_ptr get_render_pass(); /** - * Add a new render entity of the HUD renderer. + * Add a new render entity for drag selection. * * @param render_entity New render entity. */ - void add_render_entity(const std::shared_ptr entity); + void add_drag_entity(const std::shared_ptr entity); + + /** + * Remove the render object for drag selection. + * + * @param render_entity Render entity to remove. + */ + void remove_drag_entity(); /** * Update the render entities and render positions. @@ -110,14 +117,14 @@ class HudRenderer { std::shared_ptr render_pass; /** - * Render entities requested by the game simulation or input system. + * Render object for the drag select rectangle. */ - std::vector> render_objects; + std::shared_ptr drag_object; /** - * Shader for rendering the HUD objects. + * Shader for rendering the drag select rectangle. */ - std::shared_ptr display_shader; + std::shared_ptr drag_select_shader; /** * Simulation clock for timing animations.