From e48e41c99ab9d3793478b4bc7e66fc9a0ce487eb Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 11 Nov 2023 15:35:27 +0300 Subject: [PATCH] Added pause menu, new F3 debug panel, fogCurve setting --- res/main.glslf | 3 +- src/definitions.cpp | 1 + src/engine.cpp | 160 +++++++++++++++++ src/engine.h | 67 +++++++ src/frontend/gui/GUI.cpp | 85 +++++++++ src/frontend/gui/GUI.h | 64 +++++++ src/frontend/gui/Panel.cpp | 24 +++ src/frontend/gui/Panel.h | 24 +++ src/frontend/gui/UINode.cpp | 134 ++++++++++++++ src/frontend/gui/UINode.h | 82 +++++++++ src/frontend/gui/controls.cpp | 133 ++++++++++++++ src/frontend/gui/controls.h | 72 ++++++++ src/frontend/gui/panels.cpp | 130 ++++++++++++++ src/frontend/gui/panels.h | 46 +++++ src/frontend/{hud_render.cpp => hud.cpp} | 197 +++++++++++++++------ src/frontend/hud.h | 43 +++++ src/frontend/hud_render.h | 22 --- src/frontend/world_render.cpp | 37 ++-- src/frontend/world_render.h | 4 +- src/objects/player_control.cpp | 33 ++-- src/objects/player_control.h | 2 +- src/voxel_engine.cpp | 211 +---------------------- src/voxels/Block.h | 1 - src/voxels/WorldGenerator.cpp | 2 +- src/window/Window.cpp | 6 + src/window/Window.h | 2 + src/world/Level.cpp | 4 +- src/world/Level.h | 2 +- 28 files changed, 1267 insertions(+), 324 deletions(-) create mode 100644 src/engine.cpp create mode 100644 src/engine.h create mode 100644 src/frontend/gui/GUI.cpp create mode 100644 src/frontend/gui/GUI.h create mode 100644 src/frontend/gui/Panel.cpp create mode 100644 src/frontend/gui/Panel.h create mode 100644 src/frontend/gui/UINode.cpp create mode 100644 src/frontend/gui/UINode.h create mode 100644 src/frontend/gui/controls.cpp create mode 100644 src/frontend/gui/controls.h create mode 100644 src/frontend/gui/panels.cpp create mode 100644 src/frontend/gui/panels.h rename src/frontend/{hud_render.cpp => hud.cpp} (51%) create mode 100644 src/frontend/hud.h delete mode 100644 src/frontend/hud_render.h diff --git a/res/main.glslf b/res/main.glslf index 9127e7ac..e37eedd4 100644 --- a/res/main.glslf +++ b/res/main.glslf @@ -8,6 +8,7 @@ out vec4 f_color; uniform sampler2D u_texture0; uniform vec3 u_fogColor; uniform float u_fogFactor; +uniform float u_fogCurve; void main(){ vec4 tex_color = texture(u_texture0, a_texCoord); @@ -16,6 +17,6 @@ void main(){ // anyway it's any alpha-test alternative required if (alpha < 0.1f) discard; - f_color = mix(a_color * tex_color, vec4(u_fogColor,1.0), min(1.0, depth*u_fogFactor)); + f_color = mix(a_color * tex_color, vec4(u_fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve))); f_color.a = alpha; } diff --git a/src/definitions.cpp b/src/definitions.cpp index 7475cdc9..469f4326 100644 --- a/src/definitions.cpp +++ b/src/definitions.cpp @@ -72,6 +72,7 @@ void setup_definitions() { block->lightPassing = true; block->obstacle = false; block->model = 2; + block->hitboxScale = 0.5f; Block::blocks[block->id] = block; block = new Block(BLOCK_FLOWER, 16); diff --git a/src/engine.cpp b/src/engine.cpp new file mode 100644 index 00000000..52d455d0 --- /dev/null +++ b/src/engine.cpp @@ -0,0 +1,160 @@ +#include "engine.h" + +#include +#include +#include + +#include "audio/Audio.h" +#include "assets/Assets.h" +#include "assets/AssetsLoader.h" +#include "window/Window.h" +#include "window/Events.h" +#include "window/Camera.h" +#include "window/input.h" +#include "graphics/Batch2D.h" +#include "world/World.h" +#include "world/Level.h" +#include "voxels/Chunk.h" +#include "voxels/Chunks.h" +#include "voxels/ChunksController.h" +#include "voxels/ChunksStorage.h" +#include "objects/Player.h" +#include "frontend/world_render.h" +#include "frontend/hud.h" +#include "frontend/gui/GUI.h" + +#include "coders/json.h" +#include "files/files.h" + +using std::shared_ptr; +using glm::vec3; +using gui::GUI; + +void load_settings(EngineSettings& settings, std::string filename) { + std::string source = files::read_string(filename); + std::unique_ptr obj(json::parse(filename, source)); + obj->num("display-width", settings.displayWidth); + obj->num("display-height", settings.displayHeight); + obj->num("display-samples", settings.displaySamples); + obj->num("display-swap-interval", settings.displaySwapInterval); + obj->num("chunks-load-distance", settings.chunksLoadDistance); + obj->num("chunks-load-speed", settings.chunksLoadSpeed); + obj->num("chunks-padding", settings.chunksPadding); + obj->num("fog-curve", settings.fogCurve); +} + +void save_settings(EngineSettings& settings, std::string filename) { + json::JObject obj; + obj.put("display-width", settings.displayWidth); + obj.put("display-height", settings.displayHeight); + obj.put("display-samples", settings.displaySamples); + obj.put("display-swap-interval", settings.displaySwapInterval); + obj.put("chunks-load-distance", settings.chunksLoadDistance); + obj.put("chunks-load-speed", settings.chunksLoadSpeed); + obj.put("chunks-padding", settings.chunksPadding); + obj.put("fog-curve", settings.fogCurve); + files::write_string(filename, json::stringify(&obj, true, " ")); +} + +Engine::Engine(const EngineSettings& settings) { + this->settings = settings; + + Window::initialize(settings.displayWidth, + settings.displayHeight, + settings.displayTitle, + settings.displaySamples); + Window::swapInterval(settings.displaySwapInterval); + + assets = new Assets(); + std::cout << "-- loading assets" << std::endl; + AssetsLoader loader(assets); + AssetsLoader::createDefaults(loader); + AssetsLoader::addDefaults(loader); + while (loader.hasNext()) { + if (!loader.loadNext()) { + delete assets; + Window::terminate(); + throw initialize_error("could not to initialize assets"); + } + } + std::cout << "-- loading world" << std::endl; + vec3 playerPosition = vec3(0, 64, 0); + Camera* camera = new Camera(playerPosition, radians(90.0f)); + World* world = new World("world-1", "world/", 42); + Player* player = new Player(playerPosition, 4.0f, camera); + level = world->loadLevel(player, settings.chunksLoadDistance, settings.chunksPadding); + + std::cout << "-- initializing finished" << std::endl; + + Audio::initialize(); + + gui = new GUI(); +} + +void Engine::updateTimers() { + frame++; + double currentTime = Window::time(); + delta = currentTime - lastTime; + lastTime = currentTime; +} + +void Engine::updateHotkeys() { + if (Events::jpressed(keycode::O)) { + occlusion = !occlusion; + } + if (Events::jpressed(keycode::F3)) { + level->player->debug = !level->player->debug; + } + if (Events::jpressed(keycode::F5)) { + for (uint i = 0; i < level->chunks->volume; i++) { + shared_ptr chunk = level->chunks->chunks[i]; + if (chunk != nullptr && chunk->isReady()) { + chunk->setModified(true); + } + } + } +} + +void Engine::mainloop() { + Camera* camera = level->player->camera; + std::cout << "-- preparing systems" << std::endl; + WorldRenderer worldRenderer(level, assets); + HudRenderer hud(gui, level, assets); + Batch2D batch(1024); + lastTime = Window::time(); + + while (!Window::isShouldClose()){ + updateTimers(); + updateHotkeys(); + + level->update(delta, Events::_cursor_locked, Events::_cursor_locked); + level->chunksController->update(settings.chunksLoadSpeed); + + worldRenderer.draw(camera, occlusion, 1.6f / (float)settings.chunksLoadDistance, settings.fogCurve); + hud.draw(); + if (level->player->debug) { + hud.drawDebug( 1 / delta, occlusion); + } + gui->act(); + gui->draw(&batch, assets); + + Window::swapBuffers(); + Events::pullEvents(); + } +} + +Engine::~Engine() { + Audio::finalize(); + + World* world = level->world; + + std::cout << "-- saving world" << std::endl; + world->write(level); + + delete level; + delete world; + + std::cout << "-- shutting down" << std::endl; + delete assets; + Window::terminate(); +} \ No newline at end of file diff --git a/src/engine.h b/src/engine.h new file mode 100644 index 00000000..4d1ff5a6 --- /dev/null +++ b/src/engine.h @@ -0,0 +1,67 @@ +#ifndef SRC_ENGINE_H_ +#define SRC_ENGINE_H_ + +#include +#include +#include +#include "typedefs.h" + +class Assets; +class Level; + +namespace gui { + class GUI; +} + +struct EngineSettings { + /* Window width (pixels) */ + int displayWidth; + /* Window height (pixels) */ + int displayHeight; + /* Anti-aliasing samples */ + int displaySamples; + /* GLFW swap interval value, 0 - unlimited fps, 1 - vsync*/ + int displaySwapInterval; + /* Window title */ + const char* displayTitle; + /* Max milliseconds that engine uses for chunks loading only */ + uint chunksLoadSpeed; + /* Radius of chunks loading zone (chunk is unit) */ + uint chunksLoadDistance; + /* Buffer zone where chunks are not unloading (chunk is unit)*/ + uint chunksPadding; + /* Fog opacity is calculated as `pow(depth*k, fogCurve)` where k depends on chunksLoadDistance. + Use values in range [1.0 - 2.0] where 1.0 is linear, 2.0 is quadratic + */ + float fogCurve; +}; + +void load_settings(EngineSettings& settings, std::string filename); +void save_settings(EngineSettings& settings, std::string filename); + +class initialize_error : public std::runtime_error { +public: + initialize_error(const std::string& message) : std::runtime_error(message) {} +}; + +class Engine { + Assets* assets; + Level* level; + EngineSettings settings; + + uint64_t frame = 0; + double lastTime = 0.0; + double delta = 0.0; + bool occlusion = true; + + gui::GUI* gui; +public: + Engine(const EngineSettings& settings); + ~Engine(); + + void updateTimers(); + void updateHotkeys(); + void mainloop(); +}; + +#endif // SRC_ENGINE_H_ \ No newline at end of file diff --git a/src/frontend/gui/GUI.cpp b/src/frontend/gui/GUI.cpp new file mode 100644 index 00000000..dc80d7f8 --- /dev/null +++ b/src/frontend/gui/GUI.cpp @@ -0,0 +1,85 @@ +#include "GUI.h" +#include "UINode.h" +#include "panels.h" + +#include + +#include "../../assets/Assets.h" +#include "../../graphics/Batch2D.h" +#include "../../window/Events.h" +#include "../../window/input.h" + +using std::shared_ptr; +using namespace gui; + +GUI::GUI() { + container = new Container(vec2(0, 0), vec2(Window::width, Window::height)); +} + +GUI::~GUI() { + delete container; +} + +void GUI::act() { + container->size(vec2(Window::width, Window::height)); + int mx = Events::x; + int my = Events::y; + + auto hover = container->getAt(vec2(mx, my), nullptr); + if (this->hover && this->hover != hover) { + this->hover->hover(false); + } + if (hover) { + hover->hover(true); + } + this->hover = hover; + + if (Events::clicked(0)) { + if (pressed == nullptr && this->hover) { + pressed = hover; + pressed->click(this, mx, my); + if (focus) { + focus->defocus(); + } + focus = pressed; + } + if (this->hover == nullptr && focus) { + focus->defocus(); + focus = nullptr; + } + } else if (pressed) { + pressed->mouseRelease(this, mx, my); + pressed = nullptr; + } + if (focus) { + if (!focus->isfocused()){ + focus = nullptr; + } else if (Events::jpressed(keycode::ESCAPE)) { + focus->defocus(); + focus = nullptr; + } else { + for (auto codepoint : Events::codepoints) { + focus->typed(codepoint); + } + for (auto key : Events::pressedKeys) { + focus->keyPressed(key); + } + } + } +} + +void GUI::draw(Batch2D* batch, Assets* assets) { + container->draw(batch, assets); +} + +shared_ptr GUI::getFocused() const { + return focus; +} + +bool GUI::isFocusCaught() const { + return focus && focus->isfocuskeeper(); +} + +void GUI::add(shared_ptr panel) { + container->add(panel); +} diff --git a/src/frontend/gui/GUI.h b/src/frontend/gui/GUI.h new file mode 100644 index 00000000..6cc5bb11 --- /dev/null +++ b/src/frontend/gui/GUI.h @@ -0,0 +1,64 @@ +#ifndef FRONTEND_GUI_GUI_H_ +#define FRONTEND_GUI_GUI_H_ + +#include +#include +#include + +class Batch2D; +class Assets; + +/* + Some info about padding and margin. + Padding is element inner space, margin is outer + glm::vec4 usage: + x - left + y - top + z - right + w - bottom + + Outer element + +======================================================================+ + | . . . . | + | .padding.y . . . | + | padding.x . . . . padding.z | + |- - - - - - + - - - - - + - - - - - - - - - -+- - - - - + - - - - - - | + | . . . . | + | . .margin.y . . | + | .margin.x . . margin.z. | + |- - - - - - + - - - - - +====================+- - - - - + - - - - - - | + | . | Inner element | . | + |- - - - - - + - - - - - +====================+- - - - - + - - - - - - | + | . . . . | + | . .margin.w . . | + | . . . . | + |- - - - - - + - - - - - + - - - - - - - - - -+- - - - - + - - - - - - | + | . . . . | + | .padding.w . . . | + | . . . . | + +======================================================================+ +*/ + +namespace gui { + class UINode; + class Container; + + class GUI { + Container* container; + std::shared_ptr hover = nullptr; + std::shared_ptr pressed = nullptr; + std::shared_ptr focus = nullptr; + public: + GUI(); + ~GUI(); + + std::shared_ptr getFocused() const; + bool isFocusCaught() const; + + void act(); + void draw(Batch2D* batch, Assets* assets); + void add(std::shared_ptr panel); + }; +} + +#endif // FRONTEND_GUI_GUI_H_ \ No newline at end of file diff --git a/src/frontend/gui/Panel.cpp b/src/frontend/gui/Panel.cpp new file mode 100644 index 00000000..61ea914a --- /dev/null +++ b/src/frontend/gui/Panel.cpp @@ -0,0 +1,24 @@ +#include "Panel.h" + +#include "../../graphics/Batch2D.h" + +using gui::Panel; + +Panel::Panel(glm::vec2 coord, glm::vec2 size, glm::vec4 color) + : coord(coord), size(size), color(color) { + +} + +void Panel::draw(Batch2D* batch) { + batch->texture(nullptr); + batch->color = color; + batch->rect(coord.x, coord.y, size.x, size.y); +} + +bool Panel::isVisible() const { + return visible; +} + +void Panel::setVisible(bool flag) { + visible = flag; +} \ No newline at end of file diff --git a/src/frontend/gui/Panel.h b/src/frontend/gui/Panel.h new file mode 100644 index 00000000..8cbd9621 --- /dev/null +++ b/src/frontend/gui/Panel.h @@ -0,0 +1,24 @@ +#ifndef FRONTEND_GUI_PANEL_H_ +#define FRONTEND_GUI_PANEL_H_ + +#include + +class Batch2D; + +namespace gui { + class Panel { + glm::vec2 coord; + glm::vec2 size; + glm::vec4 color; + bool visible = true; + public: + Panel(glm::vec2 coord, glm::vec2 size, glm::vec4 color); + + void draw(Batch2D* batch); + + void setVisible(bool flag); + bool isVisible() const; + }; +} + +#endif // FRONTEND_GUI_PANEL_H_ \ No newline at end of file diff --git a/src/frontend/gui/UINode.cpp b/src/frontend/gui/UINode.cpp new file mode 100644 index 00000000..cd4c9477 --- /dev/null +++ b/src/frontend/gui/UINode.cpp @@ -0,0 +1,134 @@ +#include "UINode.h" + +#include "../../graphics/Batch2D.h" + +using std::shared_ptr; + +using gui::UINode; +using gui::Align; + +using glm::vec2; +using glm::vec4; + +#include + +UINode::UINode(vec2 coord, vec2 size) : coord(coord), size_(size) { +} + +UINode::~UINode() { +} + +bool UINode::visible() const { + return isvisible; +} + +void UINode::visible(bool flag) { + isvisible = flag; +} + +Align UINode::align() const { + return align_; +} + +void UINode::align(Align align) { + align_ = align; +} + +void UINode::hover(bool flag) { + hover_ = flag; +} + +bool UINode::hover() const { + return hover_; +} + +void UINode::setParent(UINode* node) { + parent = node; +} + +UINode* UINode::getParent() const { + return parent; +} + +void UINode::click(GUI*, int x, int y) { + pressed_ = true; + focused_ = true; +} + +void UINode::mouseRelease(GUI*, int x, int y) { + pressed_ = false; +} + +bool UINode::ispressed() const { + return pressed_; +} + +void UINode::defocus() { + focused_ = false; +} + +bool UINode::isfocused() const { + return focused_; +} + +bool UINode::isInside(glm::vec2 pos) { + vec2 coord = calcCoord(); + vec2 size = this->size(); + return (pos.x >= coord.x && pos.y >= coord.y && + pos.x < coord.x + size.x && pos.y < coord.y + size.y); +} + +shared_ptr UINode::getAt(vec2 pos, shared_ptr self) { + return isInside(pos) ? self : nullptr; +} + +vec2 UINode::calcCoord() const { + if (parent) { + return coord + parent->calcCoord(); + } + return coord; +} + +void UINode::setCoord(vec2 coord) { + this->coord = coord; +} + +vec2 UINode::size() const { + return size_; +} + +void UINode::size(vec2 size) { + if (sizelock) + return; + this->size_ = size; + if (parent) { + sizelock = true; + parent->refresh(); + sizelock = false; + } +} + +void UINode::_size(vec2 size) { + if (sizelock) + return; + this->size_ = size; +} + +void UINode::color(vec4 color) { + this->color_ = color; +} + +vec4 UINode::color() const { + return color_; +} + +void UINode::margin(vec4 margin) { + this->margin_ = margin; +} + +vec4 UINode::margin() const { + return margin_; +} + +void UINode::lock() { +} \ No newline at end of file diff --git a/src/frontend/gui/UINode.h b/src/frontend/gui/UINode.h new file mode 100644 index 00000000..7a2aa74c --- /dev/null +++ b/src/frontend/gui/UINode.h @@ -0,0 +1,82 @@ +#ifndef FRONTEND_GUI_UINODE_H_ +#define FRONTEND_GUI_UINODE_H_ + +#include +#include +#include +#include + +class Batch2D; +class Assets; + +namespace gui { + class UINode; + class GUI; + + typedef std::function onaction; + typedef std::function onnumberchange; + + enum class Align { + left, center, right + }; + class UINode { + protected: + glm::vec2 coord; + glm::vec2 size_; + glm::vec4 color_ {1.0f}; + glm::vec4 margin_ {1.0f}; + bool isvisible = true; + bool sizelock = false; + bool hover_ = false; + bool pressed_ = false; + bool focused_ = false; + Align align_ = Align::left; + UINode* parent = nullptr; + UINode(glm::vec2 coord, glm::vec2 size); + public: + virtual ~UINode(); + virtual void draw(Batch2D* batch, Assets* assets) = 0; + + virtual void visible(bool flag); + bool visible() const; + + virtual void align(Align align); + Align align() const; + + virtual void hover(bool flag); + bool hover() const; + + virtual void setParent(UINode* node); + UINode* getParent() const; + + virtual void color(glm::vec4 newColor); + glm::vec4 color() const; + + virtual void margin(glm::vec4 margin); + glm::vec4 margin() const; + + virtual void click(GUI*, int x, int y); + virtual void mouseRelease(GUI*, int x, int y); + + bool ispressed() const; + void defocus(); + bool isfocused() const; + virtual bool isfocuskeeper() const {return false;} + + virtual void typed(unsigned int codepoint) {}; + virtual void keyPressed(int key) {}; + + virtual bool isInside(glm::vec2 pos); + virtual std::shared_ptr getAt(glm::vec2 pos, std::shared_ptr self); + + glm::vec2 calcCoord() const; + void setCoord(glm::vec2 coord); + glm::vec2 size() const; + virtual void size(glm::vec2 size); + void _size(glm::vec2 size); + virtual void refresh() {}; + virtual void lock(); + }; +} + +#endif // FRONTEND_GUI_UINODE_H_ \ No newline at end of file diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp new file mode 100644 index 00000000..d01c33d8 --- /dev/null +++ b/src/frontend/gui/controls.cpp @@ -0,0 +1,133 @@ +#include "controls.h" + +#include + +#include "../../assets/Assets.h" +#include "../../graphics/Batch2D.h" +#include "../../graphics/Font.h" + +using std::string; +using std::wstring; +using std::shared_ptr; +using glm::vec2; + +#define KEY_ESCAPE 256 +#define KEY_ENTER 257 +#define KEY_BACKSPACE 259 + +using namespace gui; + +Label::Label(wstring text, string fontName) + : UINode(vec2(), vec2(text.length() * 8, 15)), text_(text), fontName_(fontName) { +} + +Label& Label::text(wstring text) { + this->text_ = text; + return *this; +} + +wstring Label::text() const { + return text_; +} + +void Label::draw(Batch2D* batch, Assets* assets) { + if (supplier) { + text(supplier()); + } + batch->color = color_; + Font* font = assets->getFont(fontName_); + vec2 size = this->size(); + vec2 newsize = vec2(font->calcWidth(text_), font->lineHeight()); + if (newsize.x > size.x) { + this->size(newsize); + size = newsize; + } + vec2 coord = calcCoord(); + font->draw(batch, text_, coord.x, coord.y); +} + +void Label::textSupplier(wstringsupplier supplier) { + this->supplier = supplier; +} + +Button::Button(shared_ptr content, glm::vec4 padding) : Panel(vec2(32,32), padding, 0) { + add(content); +} + +Button::Button(wstring text, glm::vec4 padding) : Panel(vec2(32,32), padding, 0) { + Label* label = new Label(text); + label->align(Align::center); + add(shared_ptr(label)); +} + +void Button::drawBackground(Batch2D* batch, Assets* assets) { + vec2 coord = calcCoord(); + batch->texture(nullptr); + batch->color = (ispressed() ? pressedColor : (hover_ ? hoverColor : color_)); + batch->rect(coord.x, coord.y, size_.x, size_.y); +} + +shared_ptr Button::getAt(vec2 pos, shared_ptr self) { + return UINode::getAt(pos, self); +} + +void Button::mouseRelease(GUI* gui, int x, int y) { + UINode::mouseRelease(gui, x, y); + if (isInside(vec2(x, y))) { + for (auto callback : actions) { + callback(gui); + } + } +} + +void Button::listenAction(onaction action) { + actions.push_back(action); +} + +TextBox::TextBox(wstring text, vec4 padding) : Panel(vec2(200,32), padding, 0, false) { + label = new Label(text); + label->align(Align::center); + add(shared_ptr(label)); +} + +void TextBox::drawBackground(Batch2D* batch, Assets* assets) { + vec2 coord = calcCoord(); + batch->texture(nullptr); + batch->color = (isfocused() ? focusedColor : (hover_ ? hoverColor : color_)); + batch->rect(coord.x, coord.y, size_.x, size_.y); + if (!focused_ && supplier) { + label->text(supplier()); + } +} + +void TextBox::typed(unsigned int codepoint) { + label->text(label->text() + wstring({(wchar_t)codepoint})); +} + +void TextBox::keyPressed(int key) { + wstring src = label->text(); + switch (key) { + case KEY_BACKSPACE: + if (src.length()) + label->text(src.substr(0, src.length()-1)); + break; + case KEY_ENTER: + if (consumer) { + consumer(label->text()); + } + defocus(); + break; + } +} + +shared_ptr TextBox::getAt(vec2 pos, shared_ptr self) { + return UINode::getAt(pos, self); +} + +void TextBox::textSupplier(wstringsupplier supplier) { + this->supplier = supplier; +} + +void TextBox::textConsumer(wstringconsumer consumer) { + this->consumer = consumer; +} \ No newline at end of file diff --git a/src/frontend/gui/controls.h b/src/frontend/gui/controls.h new file mode 100644 index 00000000..209013fb --- /dev/null +++ b/src/frontend/gui/controls.h @@ -0,0 +1,72 @@ +#ifndef FRONTEND_GUI_CONTROLS_H_ +#define FRONTEND_GUI_CONTROLS_H_ + +#include +#include +#include +#include +#include +#include "UINode.h" +#include "panels.h" + +class Batch2D; +class Assets; + +namespace gui { + typedef std::function wstringsupplier; + typedef std::function wstringconsumer; + + class Label : public UINode { + protected: + std::wstring text_; + std::string fontName_; + wstringsupplier supplier = nullptr; + public: + Label(std::wstring text, std::string fontName="normal"); + + virtual Label& text(std::wstring text); + std::wstring text() const; + + virtual void draw(Batch2D* batch, Assets* assets); + + virtual void textSupplier(wstringsupplier supplier); + }; + class Button : public Panel { + protected: + glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f}; + glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f}; + std::vector actions; + public: + Button(std::shared_ptr content, glm::vec4 padding=glm::vec4(2.0f)); + Button(std::wstring text, glm::vec4 padding=glm::vec4(2.0f)); + + virtual void drawBackground(Batch2D* batch, Assets* assets); + + virtual std::shared_ptr getAt(glm::vec2 pos, std::shared_ptr self) override; + + virtual void mouseRelease(GUI*, int x, int y) override; + virtual void listenAction(onaction action); + }; + + class TextBox : public Panel { + protected: + glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f}; + glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f}; + Label* label; + wstringsupplier supplier = nullptr; + wstringconsumer consumer = nullptr; + public: + TextBox(std::wstring text, glm::vec4 padding=glm::vec4(2.0f)); + + virtual std::shared_ptr getAt(glm::vec2 pos, std::shared_ptr self) override; + + virtual void drawBackground(Batch2D* batch, Assets* assets) override; + virtual void typed(unsigned int codepoint) override; + virtual void keyPressed(int key) override; + virtual void textSupplier(wstringsupplier supplier); + virtual void textConsumer(wstringconsumer consumer); + virtual bool isfocuskeeper() const override {return true;} + }; +} + +#endif // FRONTEND_GUI_CONTROLS_H_ \ No newline at end of file diff --git a/src/frontend/gui/panels.cpp b/src/frontend/gui/panels.cpp new file mode 100644 index 00000000..e1a30c1a --- /dev/null +++ b/src/frontend/gui/panels.cpp @@ -0,0 +1,130 @@ +#include "panels.h" + +#include "../../window/Window.h" +#include "../../assets/Assets.h" +#include "../../graphics/Batch2D.h" + +using std::shared_ptr; + +using gui::UINode; +using gui::Container; +using gui::Panel; +using gui::Orientation; + +using glm::vec2; +using glm::vec4; + +Container::Container(vec2 coord, vec2 size) : UINode(coord, size) { +} + +shared_ptr Container::getAt(vec2 pos, shared_ptr self) { + for (auto node : nodes) { + if (!node->visible()) + continue; + auto hover = node->getAt(pos, node); + if (hover != nullptr) { + return hover; + } + } + return UINode::getAt(pos, self); +} + +void Container::draw(Batch2D* batch, Assets* assets) { + vec2 coord = calcCoord(); + vec2 size = this->size(); + drawBackground(batch, assets); + batch->texture(nullptr); + batch->render(); + Window::pushScissor(vec4(coord.x, coord.y, size.x, size.y)); + for (auto node : nodes) { + if (node->visible()) + node->draw(batch, assets); + } + batch->render(); + Window::popScissor(); +} + +void Container::add(shared_ptr node) { + nodes.push_back(node); + node->setParent(this); + refresh(); +} + +Panel::Panel(vec2 size, glm::vec4 padding, float interval, bool resizing) + : Container(vec2(), size), padding(padding), interval(interval), resizing_(resizing) { + color_ = vec4(0.0f, 0.0f, 0.0f, 0.75f); +} + +Panel::~Panel() { +} + +void Panel::drawBackground(Batch2D* batch, Assets* assets) { + vec2 coord = calcCoord(); + batch->texture(nullptr); + batch->color = color_; + batch->rect(coord.x, coord.y, size_.x, size_.y); +} + +void Panel::refresh() { + float x = padding.x; + float y = padding.y; + vec2 size = this->size(); + if (orientation_ == Orientation::vertical) { + float maxw = size.x; + for (auto node : nodes) { + vec2 nodesize = node->size(); + const vec4 margin = node->margin(); + y += margin.y; + + float ex; + + switch (node->align()) { + case Align::center: + ex = x + fmax(0.0f, (size.x - margin.z - padding.z) - node->size().x) / 2.0f; + break; + case Align::right: + ex = x + size.x - margin.z - padding.z - node->size().x; + break; + default: + ex = x + margin.x; + } + node->setCoord(vec2(ex, y)); + y += nodesize.y + margin.w + interval; + node->size(vec2(size.x - padding.x - padding.z - margin.x - margin.z, nodesize.y)); + maxw = fmax(maxw, ex+node->size().x+margin.z+padding.z); + } + if (resizing_) + this->size(vec2(maxw, y+padding.w)); + } else { + float maxh = size.y; + for (auto node : nodes) { + vec2 nodesize = node->size(); + const vec4 margin = node->margin(); + x += margin.x; + node->setCoord(vec2(x, y+margin.y)); + x += nodesize.x + margin.z + interval; + node->size(vec2(nodesize.x, size.y - padding.y - padding.w - margin.y - margin.w)); + maxh = fmax(maxh, y+margin.y+node->size().y+margin.w+padding.w); + } + bool increased = maxh > size.y; + if (resizing_) + this->size(vec2(x+padding.z, maxh)); + if (increased) + refresh(); + } +} + +void Panel::orientation(Orientation orientation) { + this->orientation_ = orientation; +} + +Orientation Panel::orientation() const { + return orientation_; +} + +void Panel::lock(){ + for (auto node : nodes) { + node->lock(); + } + resizing_ = false; +} \ No newline at end of file diff --git a/src/frontend/gui/panels.h b/src/frontend/gui/panels.h new file mode 100644 index 00000000..f7ec7334 --- /dev/null +++ b/src/frontend/gui/panels.h @@ -0,0 +1,46 @@ +#ifndef FRONTEND_GUI_PANELS_H_ +#define FRONTEND_GUI_PANELS_H_ + +#include +#include +#include +#include "UINode.h" + +class Batch2D; +class Assets; + +namespace gui { + enum class Orientation { vertical, horizontal }; + + class Container : public UINode { + protected: + std::vector> nodes; + public: + Container(glm::vec2 coord, glm::vec2 size); + + virtual void drawBackground(Batch2D* batch, Assets* assets) {}; + virtual void draw(Batch2D* batch, Assets* assets); + virtual std::shared_ptr getAt(glm::vec2 pos, std::shared_ptr self) override; + virtual void add(std::shared_ptr node); + }; + + class Panel : public Container { + protected: + Orientation orientation_ = Orientation::vertical; + glm::vec4 padding {2.0f}; + float interval = 2.0f; + bool resizing_; + public: + Panel(glm::vec2 size, glm::vec4 padding=glm::vec4(2.0f), float interval=2.0f, bool resizing=true); + virtual ~Panel(); + + virtual void drawBackground(Batch2D* batch, Assets* assets) override; + + virtual void orientation(Orientation orientation); + Orientation orientation() const; + + virtual void refresh() override; + virtual void lock() override; + }; +} +#endif // FRONTEND_GUI_PANELS_H_ \ No newline at end of file diff --git a/src/frontend/hud_render.cpp b/src/frontend/hud.cpp similarity index 51% rename from src/frontend/hud_render.cpp rename to src/frontend/hud.cpp index e81a48f4..ccaedc1c 100644 --- a/src/frontend/hud_render.cpp +++ b/src/frontend/hud.cpp @@ -1,10 +1,14 @@ -#include "hud_render.h" +#include "hud.h" +#include #include +#include +#include #include #include #include "../typedefs.h" +#include "../util/stringutil.h" #include "../assets/Assets.h" #include "../graphics/Shader.h" #include "../graphics/Batch2D.h" @@ -13,59 +17,132 @@ #include "../window/Camera.h" #include "../window/Window.h" #include "../window/Events.h" +#include "../window/input.h" #include "../voxels/Chunks.h" #include "../voxels/Block.h" #include "../world/World.h" #include "../world/Level.h" #include "../objects/Player.h" +#include "../physics/Hitbox.h" +#include "gui/controls.h" +#include "gui/panels.h" +#include "gui/UINode.h" +#include "gui/GUI.h" +using std::wstring; +using std::shared_ptr; +using glm::vec2; +using glm::vec3; +using glm::vec4; +using gui::GUI; +using gui::UINode; +using gui::Panel; +using gui::Label; +using gui::Button; +using gui::TextBox; -HudRenderer::HudRenderer(Assets* assets) : assets(assets) { +inline Label* create_label(gui::wstringsupplier supplier) { + Label* label = new Label(L"-"); + label->textSupplier(supplier); + return label; +} + +HudRenderer::HudRenderer(GUI* gui, Level* level, Assets* assets) : level(level), assets(assets), guiController(gui) { batch = new Batch2D(1024); uicamera = new Camera(glm::vec3(), Window::height); uicamera->perspective = false; uicamera->flipped = true; + + Panel* panel = new Panel(vec2(200, 200), vec4(5.0f), 1.0f); + panel->setCoord(vec2(10, 10)); + panel->add(shared_ptr