mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(ui): add Rect widget with fill, color, and parent-relative sizing
This commit is contained in:
9
assets/shaders/rect_f_shader.glsl
Normal file
9
assets/shaders/rect_f_shader.glsl
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
uniform vec4 inColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
color = inColor;
|
||||||
|
}
|
||||||
11
assets/shaders/rect_v_shader.glsl
Normal file
11
assets/shaders/rect_v_shader.glsl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 pos;
|
||||||
|
|
||||||
|
|
||||||
|
uniform mat4 model_matrix;
|
||||||
|
uniform mat4 proj_matrix;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
gl_Position = proj_matrix * model_matrix * vec4(pos, 0.0, 1.0);
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "Cubed/shader.hpp"
|
#include "Cubed/shader.hpp"
|
||||||
#include "Cubed/ui/image.hpp"
|
#include "Cubed/ui/image.hpp"
|
||||||
#include "Cubed/ui/label.hpp"
|
#include "Cubed/ui/label.hpp"
|
||||||
|
#include "Cubed/ui/rect.hpp"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -33,7 +34,7 @@ public:
|
|||||||
void render_world(ClientWorld& world);
|
void render_world(ClientWorld& world);
|
||||||
void render_lable(const Label& label);
|
void render_lable(const Label& label);
|
||||||
void render_image(const Image& image);
|
void render_image(const Image& image);
|
||||||
|
void render_rect(const Rect& rect);
|
||||||
void begin_render_ui();
|
void begin_render_ui();
|
||||||
void end_render_ui();
|
void end_render_ui();
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ public:
|
|||||||
} else if constexpr (is_same_v<dT, glm::mat4>) {
|
} else if constexpr (is_same_v<dT, glm::mat4>) {
|
||||||
glUniformMatrix4fv(loc(location), 1, GL_FALSE,
|
glUniformMatrix4fv(loc(location), 1, GL_FALSE,
|
||||||
glm::value_ptr(value));
|
glm::value_ptr(value));
|
||||||
|
|
||||||
|
} else if constexpr (is_same_v<dT, glm::vec4>) {
|
||||||
|
glUniform4fv(loc(location), 1, glm::value_ptr(value));
|
||||||
} else {
|
} else {
|
||||||
static_assert(always_false<dT>::value, "Unknown Type");
|
static_assert(always_false<dT>::value, "Unknown Type");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ public:
|
|||||||
|
|
||||||
void update(float dt) override;
|
void update(float dt) override;
|
||||||
|
|
||||||
|
float width() const override;
|
||||||
|
float height() const override;
|
||||||
|
|
||||||
void set_spacing(int spacing);
|
void set_spacing(int spacing);
|
||||||
// No need for parent node pointer; do not modify children's anchors and
|
// No need for parent node pointer; do not modify children's anchors and
|
||||||
// scale.
|
// scale.
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
MainMenuScene& m_scene;
|
MainMenuScene& m_scene;
|
||||||
std::unordered_map<std::string, std::unique_ptr<Widget>> m_widgets;
|
std::unique_ptr<Widget> m_root_widget;
|
||||||
|
std::unordered_map<std::string, Widget*> m_widgets;
|
||||||
bool handle_mouse_move_event(const MouseMoveEvent& e);
|
bool handle_mouse_move_event(const MouseMoveEvent& e);
|
||||||
bool handle_mouse_button_event(const MouseButtonEvent& e);
|
bool handle_mouse_button_event(const MouseButtonEvent& e);
|
||||||
bool handle_window_resize_event(const WindowResizeEvent& e);
|
bool handle_window_resize_event(const WindowResizeEvent& e);
|
||||||
|
|||||||
41
include/Cubed/ui/rect.hpp
Normal file
41
include/Cubed/ui/rect.hpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/ui/color.hpp"
|
||||||
|
#include "Cubed/ui/widget.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
class Rect : public Widget {
|
||||||
|
public:
|
||||||
|
Rect(const Rect&) = delete;
|
||||||
|
Rect(Rect&&) = delete;
|
||||||
|
Rect& operator=(const Rect&) = delete;
|
||||||
|
Rect& operator=(Rect&&) = delete;
|
||||||
|
Rect(Widget* parent);
|
||||||
|
~Rect();
|
||||||
|
|
||||||
|
void update(float dt) override;
|
||||||
|
void render(Renderer& renderer) override;
|
||||||
|
|
||||||
|
float width() const override;
|
||||||
|
float height() const override;
|
||||||
|
float alpha() const;
|
||||||
|
|
||||||
|
Rect& set_width(float width);
|
||||||
|
Rect& set_height(float height);
|
||||||
|
|
||||||
|
Rect& set_fill(bool fill);
|
||||||
|
|
||||||
|
Rect& set_scale(float scale);
|
||||||
|
Rect& set_color(Color color);
|
||||||
|
Rect& set_alpha(float alpha);
|
||||||
|
|
||||||
|
Color color() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Color m_color = Color::WHITE;
|
||||||
|
float m_width = 0.0f;
|
||||||
|
float m_height = 0.0f;
|
||||||
|
float m_scale = 1.0f;
|
||||||
|
float m_alpha = 1.0f;
|
||||||
|
bool m_fill = false;
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
@@ -21,8 +21,8 @@ public:
|
|||||||
virtual Widget& set_offset(glm::ivec2 offset);
|
virtual Widget& set_offset(glm::ivec2 offset);
|
||||||
virtual void set_window_size(int width, int height);
|
virtual void set_window_size(int width, int height);
|
||||||
// Returns the final display size
|
// Returns the final display size
|
||||||
virtual float width() const;
|
virtual float width() const = 0;
|
||||||
virtual float height() const;
|
virtual float height() const = 0;
|
||||||
virtual glm::vec2 pos() const;
|
virtual glm::vec2 pos() const;
|
||||||
|
|
||||||
virtual bool handle_key_event(const KeyEvent& e);
|
virtual bool handle_key_event(const KeyEvent& e);
|
||||||
|
|||||||
@@ -68,4 +68,5 @@ target_sources(${PROJECT_NAME}
|
|||||||
ui/main_menu_ui_manager.cpp
|
ui/main_menu_ui_manager.cpp
|
||||||
scene/main_menu_scene.cpp
|
scene/main_menu_scene.cpp
|
||||||
ui/column_layout.cpp
|
ui/column_layout.cpp
|
||||||
|
ui/rect.cpp
|
||||||
)
|
)
|
||||||
@@ -157,6 +157,26 @@ void Renderer::render_world(ClientWorld& world) {
|
|||||||
m_world_renderer.render(world);
|
m_world_renderer.render(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::render_rect(const Rect& rect) {
|
||||||
|
|
||||||
|
auto& shader = get_shader("rect");
|
||||||
|
shader.use();
|
||||||
|
shader.set_loc("proj_matrix", m_ui_proj_matrix);
|
||||||
|
auto pos = rect.pos();
|
||||||
|
glm::mat4 model_matrix =
|
||||||
|
glm::translate(glm::mat4(1.0f), glm::vec3(pos.x, pos.y, 0.0f)) *
|
||||||
|
glm::scale(glm::mat4(1.0f),
|
||||||
|
glm::vec3(rect.width(), rect.height(), 1.0f));
|
||||||
|
shader.set_loc("model_matrix", model_matrix);
|
||||||
|
|
||||||
|
auto color = color_value(rect.color());
|
||||||
|
shader.set_loc("inColor",
|
||||||
|
glm::vec4(color.x, color.y, color.z, rect.alpha()));
|
||||||
|
|
||||||
|
m_vao[3].bind();
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::render_lable(const Label& label) {
|
void Renderer::render_lable(const Label& label) {
|
||||||
|
|
||||||
const auto& shader = get_shader("text");
|
const auto& shader = get_shader("text");
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ void ShaderManager::init() {
|
|||||||
"shaders/player_f_shader.glsl");
|
"shaders/player_f_shader.glsl");
|
||||||
register_shader("player_depth", "shaders/depth_player_shader.glsl",
|
register_shader("player_depth", "shaders/depth_player_shader.glsl",
|
||||||
"shaders/depth_player_fragment_shader.glsl");
|
"shaders/depth_player_fragment_shader.glsl");
|
||||||
|
register_shader("rect", "shaders/rect_v_shader.glsl",
|
||||||
|
"shaders/rect_f_shader.glsl");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderManager::register_shader(const std::string& name,
|
void ShaderManager::register_shader(const std::string& name,
|
||||||
|
|||||||
@@ -9,6 +9,19 @@ void ColumnLayout::update(float dt) {
|
|||||||
layout();
|
layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float ColumnLayout::width() const {
|
||||||
|
if (m_parent) {
|
||||||
|
return m_parent->width();
|
||||||
|
}
|
||||||
|
return m_window_width;
|
||||||
|
}
|
||||||
|
float ColumnLayout::height() const {
|
||||||
|
if (m_parent) {
|
||||||
|
return m_parent->height();
|
||||||
|
}
|
||||||
|
return m_window_height;
|
||||||
|
}
|
||||||
|
|
||||||
void ColumnLayout::set_spacing(int spacing) { m_spacing = spacing; }
|
void ColumnLayout::set_spacing(int spacing) { m_spacing = spacing; }
|
||||||
|
|
||||||
void ColumnLayout::layout() {
|
void ColumnLayout::layout() {
|
||||||
|
|||||||
@@ -12,13 +12,21 @@ MainMenuUIManager::MainMenuUIManager(MainMenuScene& scene) : m_scene(scene) {}
|
|||||||
MainMenuUIManager::~MainMenuUIManager() {}
|
MainMenuUIManager::~MainMenuUIManager() {}
|
||||||
|
|
||||||
void MainMenuUIManager::init() {
|
void MainMenuUIManager::init() {
|
||||||
|
|
||||||
|
auto rect = std::make_unique<Rect>(nullptr);
|
||||||
|
|
||||||
|
rect->set_fill(true);
|
||||||
|
rect->set_anchor(Anchor::TOP_LEFT);
|
||||||
|
rect->set_color(Color::WHITE);
|
||||||
auto& renderer = m_scene.scene_manager().app().renderer();
|
auto& renderer = m_scene.scene_manager().app().renderer();
|
||||||
auto layout = std::make_unique<ColumnLayout>(nullptr);
|
rect->set_window_size(renderer.window_width(), renderer.window_height());
|
||||||
layout->set_spacing(20);
|
|
||||||
layout->set_anchor(Anchor::CENTER);
|
auto& layout = rect->add_child<ColumnLayout>();
|
||||||
layout->set_window_size(renderer.window_width(), renderer.window_height());
|
layout.set_spacing(20);
|
||||||
|
layout.set_anchor(Anchor::CENTER);
|
||||||
|
layout.set_window_size(renderer.window_width(), renderer.window_height());
|
||||||
{
|
{
|
||||||
auto& start_game_button = layout->add_child<Button>();
|
auto& start_game_button = layout.add_child<Button>();
|
||||||
|
|
||||||
auto& back = start_game_button.set_background<Image>();
|
auto& back = start_game_button.set_background<Image>();
|
||||||
back.set_image("texture/ui/button001.png",
|
back.set_image("texture/ui/button001.png",
|
||||||
@@ -32,7 +40,7 @@ void MainMenuUIManager::init() {
|
|||||||
start_game_button.set_scale(4.0f);
|
start_game_button.set_scale(4.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& exit_game = layout->add_child<Button>();
|
auto& exit_game = layout.add_child<Button>();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& back = exit_game.set_background<Image>();
|
auto& back = exit_game.set_background<Image>();
|
||||||
@@ -45,22 +53,17 @@ void MainMenuUIManager::init() {
|
|||||||
m_scene.scene_manager().app().window().should_close_window();
|
m_scene.scene_manager().app().window().should_close_window();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
m_widgets.try_emplace("background", rect.get());
|
||||||
m_widgets.try_emplace("main menu layout", std::move(layout));
|
m_widgets.try_emplace("main menu layout", &layout);
|
||||||
|
m_root_widget = std::move(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenuUIManager::update(float dt) {
|
void MainMenuUIManager::update(float dt) { m_root_widget->update(dt); }
|
||||||
for (auto& w : m_widgets) {
|
|
||||||
w.second->update(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainMenuUIManager::render(Renderer& renderer) {
|
void MainMenuUIManager::render(Renderer& renderer) {
|
||||||
renderer.begin_render_ui();
|
renderer.begin_render_ui();
|
||||||
|
|
||||||
for (auto& widget : m_widgets) {
|
m_root_widget->render(renderer);
|
||||||
widget.second->render(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer.end_render_ui();
|
renderer.end_render_ui();
|
||||||
}
|
}
|
||||||
@@ -101,43 +104,40 @@ bool MainMenuUIManager::handle_event(const Event& e) {
|
|||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
bool MainMenuUIManager::handle_mouse_move_event(const MouseMoveEvent& e) {
|
bool MainMenuUIManager::handle_mouse_move_event(const MouseMoveEvent& e) {
|
||||||
for (auto& w : m_widgets) {
|
if (m_root_widget->handle_mouse_move_event(e)) {
|
||||||
if (w.second->handle_mouse_move_event(e)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool MainMenuUIManager::handle_mouse_button_event(const MouseButtonEvent& e) {
|
bool MainMenuUIManager::handle_mouse_button_event(const MouseButtonEvent& e) {
|
||||||
for (auto& w : m_widgets) {
|
|
||||||
if (w.second->handle_mouse_button_event(e)) {
|
if (m_root_widget->handle_mouse_button_event(e)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool MainMenuUIManager::handle_window_resize_event(const WindowResizeEvent& e) {
|
bool MainMenuUIManager::handle_window_resize_event(const WindowResizeEvent& e) {
|
||||||
for (auto& w : m_widgets) {
|
|
||||||
if (w.second->handle_window_resize_event(e)) {
|
if (m_root_widget->handle_window_resize_event(e)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool MainMenuUIManager::handle_mouse_wheel_event(const MouseWheelEvent& e) {
|
bool MainMenuUIManager::handle_mouse_wheel_event(const MouseWheelEvent& e) {
|
||||||
for (auto& w : m_widgets) {
|
|
||||||
if (w.second->handle_mouse_wheel_event(e)) {
|
if (m_root_widget->handle_mouse_wheel_event(e)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool MainMenuUIManager::handle_key_event(const KeyEvent& e) {
|
bool MainMenuUIManager::handle_key_event(const KeyEvent& e) {
|
||||||
for (auto& w : m_widgets) {
|
|
||||||
if (w.second->handle_key_event(e)) {
|
if (m_root_widget->handle_key_event(e)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/ui/rect.cpp
Normal file
58
src/ui/rect.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include "Cubed/ui/rect.hpp"
|
||||||
|
|
||||||
|
#include "Cubed/render/renderer.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
Rect::Rect(Widget* parent)
|
||||||
|
: Widget(parent) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Rect::~Rect() {}
|
||||||
|
void Rect::update(float dt) {
|
||||||
|
if (m_fill) {
|
||||||
|
if (!m_parent) {
|
||||||
|
m_width = m_window_width;
|
||||||
|
m_height = m_window_height;
|
||||||
|
} else {
|
||||||
|
m_width = m_parent->width();
|
||||||
|
m_height = m_parent->height();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Widget::update(dt);
|
||||||
|
}
|
||||||
|
void Rect::render(Renderer& renderer) {
|
||||||
|
renderer.render_rect(*this);
|
||||||
|
Widget::render(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Rect::width() const { return m_width * m_scale; }
|
||||||
|
float Rect::height() const { return m_height * m_scale; }
|
||||||
|
float Rect::alpha() const { return m_alpha; }
|
||||||
|
Rect& Rect::set_width(float width) {
|
||||||
|
m_width = width;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Rect& Rect::set_height(float height) {
|
||||||
|
m_height = height;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect& Rect::set_fill(bool fill) {
|
||||||
|
m_fill = fill;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect& Rect::set_scale(float scale) {
|
||||||
|
m_scale = scale;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Rect& Rect::set_color(Color color) {
|
||||||
|
m_color = color;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Rect& Rect::set_alpha(float alpha) {
|
||||||
|
m_alpha = std::clamp(alpha, 0.0f, 1.0f);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Color Rect::color() const { return m_color; }
|
||||||
|
} // namespace Cubed
|
||||||
@@ -103,8 +103,18 @@ void Widget::set_window_size(int width, int height) {
|
|||||||
m_window_height = height;
|
m_window_height = height;
|
||||||
m_window_width = width;
|
m_window_width = width;
|
||||||
}
|
}
|
||||||
float Widget::width() const { return m_window_width; }
|
float Widget::width() const {
|
||||||
float Widget::height() const { return m_window_height; }
|
if (m_parent) {
|
||||||
|
return m_parent->width();
|
||||||
|
}
|
||||||
|
return m_window_width;
|
||||||
|
}
|
||||||
|
float Widget::height() const {
|
||||||
|
if (m_parent) {
|
||||||
|
return m_parent->height();
|
||||||
|
}
|
||||||
|
return m_window_height;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec2 Widget::pos() const { return compute_position(); }
|
glm::vec2 Widget::pos() const { return compute_position(); }
|
||||||
const std::string& Widget::id() const { return m_id; }
|
const std::string& Widget::id() const { return m_id; }
|
||||||
|
|||||||
Reference in New Issue
Block a user