From cc006e7469e266f73ae4a05c2c586a45a258dcb5 Mon Sep 17 00:00:00 2001 From: MrLetsplay2003 Date: Tue, 1 Nov 2022 15:55:23 +0100 Subject: [PATCH] Clean up UI stuff, More UI elements (WIP) --- src/kekengine/cpp/defaults.cpp | 22 +++- src/kekengine/cpp/engine.cpp | 4 +- src/kekengine/cpp/ui.cpp | 25 ++-- src/kekengine/cpp/uielements.cpp | 119 +++++++++++++++--- src/kekengine/include/input.h | 8 +- src/kekengine/include/internal.h | 2 + src/kekengine/include/ui.h | 32 ++--- src/kekengine/include/uielements.h | 57 ++++++++- src/kekengine/include/utils.h | 13 +- .../res/shader/rectangle/fragment.glsl | 9 ++ .../res/shader/rectangle/vertex.glsl | 10 ++ src/kekgame/cpp/kekgame.cpp | 9 ++ 12 files changed, 242 insertions(+), 68 deletions(-) create mode 100644 src/kekengine/res/shader/rectangle/fragment.glsl create mode 100644 src/kekengine/res/shader/rectangle/vertex.glsl diff --git a/src/kekengine/cpp/defaults.cpp b/src/kekengine/cpp/defaults.cpp index 2c11c46..57a4a28 100644 --- a/src/kekengine/cpp/defaults.cpp +++ b/src/kekengine/cpp/defaults.cpp @@ -1,17 +1,22 @@ #include "input.h" +#include "ui.h" +#include "uielements.h" #include "internal.h" namespace kek::Defaults { -static int +static KeyBinding keyForward, keyBackward, keyLeft, keyRight, keyUp, - keyDown; + keyDown, + keyOptions; -void defaultInput(GLFWwindow *window, void *data) { +static ButtonElement *options; + +static void defaultInput(GLFWwindow *window, void *data) { if(Input::getKeyState(keyForward) == GLFW_PRESS) { kekData.activeCamera->translate(kekData.activeCamera->direction * KEK_NOCLIP_SPEED * kekData.lastFrameTime); } @@ -39,6 +44,12 @@ void defaultInput(GLFWwindow *window, void *data) { } } +static void defaultKey(GLFWwindow *window, int key, int scancode, int action, int mods, void *data) { + if(key == Input::getKeyBinding(keyOptions).key && action == GLFW_PRESS) { + options->visible = !options->visible; + } +} + void init() { keyForward = Input::createKeyBinding("Forward", GLFW_KEY_W); keyBackward = Input::createKeyBinding("Backward", GLFW_KEY_S); @@ -46,8 +57,13 @@ void init() { keyRight = Input::createKeyBinding("Right", GLFW_KEY_D); keyUp = Input::createKeyBinding("Up", GLFW_KEY_SPACE); keyDown = Input::createKeyBinding("Down", GLFW_KEY_LEFT_CONTROL); + keyOptions = Input::createKeyBinding("Options", GLFW_KEY_Q); Input::addPeriodicCallback(PeriodicCallback(defaultInput, nullptr)); + Input::addKeyListener(KeyCallback(defaultKey, nullptr)); + + options = new ButtonElement(px(0), px(100), px(100), px(50)); + UI::addElement(options); } } diff --git a/src/kekengine/cpp/engine.cpp b/src/kekengine/cpp/engine.cpp index 237e8f2..200920e 100644 --- a/src/kekengine/cpp/engine.cpp +++ b/src/kekengine/cpp/engine.cpp @@ -180,9 +180,9 @@ int init() { return KEK_ERROR; } - UIElement::init(); - + UI::init(); Defaults::init(); + fpsText = new TextElement(px(0), px(0)); UI::addElement(fpsText); diff --git a/src/kekengine/cpp/ui.cpp b/src/kekengine/cpp/ui.cpp index 9ff0337..e92a097 100644 --- a/src/kekengine/cpp/ui.cpp +++ b/src/kekengine/cpp/ui.cpp @@ -32,8 +32,6 @@ constexpr UIValue operator-(const UIValue& lhs, const UIValue& rhs) { return UIValue(lhs) -= rhs; } -Font *UIElement::defaultFont = nullptr; - UIElement::UIElement(UIValue x, UIValue y): x(x), y(y) { } @@ -70,7 +68,7 @@ void UIElement::removeChild(UIElement *child) { std::remove(children.begin(), children.end(), child); } -inline int UIElement::uiToScreen(UIValue val) { +int UIElement::uiToScreen(UIValue val) { float px = 0; px += val.pixels; if(parent) px += (int) (val.parentWidth * parent->getBounds().w); @@ -92,11 +90,11 @@ void UIElement::drawAll(UIPoint screenPos, glm::mat4 projection) { } } -void UIElement::hoverAll(UIPoint pos, UIPoint screenPos) { +bool UIElement::hoverAll(UIPoint pos, UIPoint screenPos) { UIBounds bounds = getBounds(); if(!bounds.contains(pos)) { // Only used by topmost parent UIElement if(hovering) hoverExitAll(); - return; + return false; } UIElement *hoveredChild = NULL; @@ -121,6 +119,7 @@ void UIElement::hoverAll(UIPoint pos, UIPoint screenPos) { if(!hovering) hoverEnter(pos, screenPos); hovering = true; hover(pos, screenPos); + return true; } void UIElement::hoverExitAll() { @@ -132,9 +131,9 @@ void UIElement::hoverExitAll() { hoverExit(); } -void UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) { +bool UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) { UIBounds bounds = getBounds(); - if(!bounds.contains(pos)) return; // Only used by topmost parent UIElement + if(!bounds.contains(pos)) return false; // Only used by topmost parent UIElement UIElement *clickedChild = NULL; for(UIElement *child : children) { @@ -153,6 +152,8 @@ void UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) }else { click(pos, screenPos, button); } + + return true; } bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) { @@ -208,8 +209,14 @@ UIElement *UIElement::dragEnterAll(UIPoint pos, UIPoint screenPos) { return nullptr; } -void UIElement::init() { - defaultFont = new Font(KEK_DEFAULT_FONT); +void UI::init() { + kekData.uiDefaultFont = new Font(KEK_DEFAULT_FONT); + kekData.uiRectangleShader = new Shader("shader/rectangle/vertex.glsl", "shader/rectangle/fragment.glsl"); +} + +void UI::destroy() { + delete kekData.uiDefaultFont; + delete kekData.uiRectangleShader; } void UI::addElement(UIElement *element) { diff --git a/src/kekengine/cpp/uielements.cpp b/src/kekengine/cpp/uielements.cpp index 8669b1c..81c9ee8 100644 --- a/src/kekengine/cpp/uielements.cpp +++ b/src/kekengine/cpp/uielements.cpp @@ -1,5 +1,9 @@ #include "uielements.h" +#include + +#include "internal.h" + namespace kek { static inline int offsetX(int w, Origin origin) { @@ -56,7 +60,7 @@ TextElement::TextElement(UIValue x, UIValue y, Font *font): UIElement(x, y) { this->textBounds = TextBounds::SMALLEST; } -TextElement::TextElement(UIValue x, UIValue y): TextElement(x, y, UIElement::defaultFont) {} +TextElement::TextElement(UIValue x, UIValue y): TextElement(x, y, kekData.uiDefaultFont) {} TextElement::~TextElement() { delete text; @@ -97,22 +101,6 @@ void TextElement::setText(std::string text) { this->text->setText(text); } -void TextElement::setSizePixels(int sizePixels) { - this->sizePixels = sizePixels; -} - -void TextElement::setColor(Color color) { - this->color = color; -} - -void TextElement::setTextMode(TextMode textMode) { - this->textMode = textMode; -} - -void TextElement::setTextBounds(TextBounds textBounds) { - this->textBounds = textBounds; -} - void TextElement::draw(UIPoint screenPos, glm::mat4 projection) { UIBounds offset = getBounds(); @@ -153,4 +141,101 @@ void UIWindow::draw(UIPoint screenPos, glm::mat4 projection) { } +static float rectangleVerts[] = { + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 0.0f, + 0.0f, 1.0f, +}; + +RectangleElement::RectangleElement(UIValue x, UIValue y, UIValue w, UIValue h): UIElement(x, y) { + this->w = w; + this->h = h; + this->color = Colors::BLACK; + + glGenVertexArrays(1, &vao); + glGenBuffers(1, &vbo); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(rectangleVerts), rectangleVerts, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0); + glEnableVertexAttribArray(0); + + glBindVertexArray(0); +} + +RectangleElement::~RectangleElement() { + glDeleteVertexArrays(1, &vao); + glDeleteBuffers(1, &vbo); +} + +UIElementType RectangleElement::getType() { + return UIElementType::RECTANGLE; +} + +UIBounds RectangleElement::getBounds() { + return offsetUIBounds(uiToScreen(w), uiToScreen(h), origin); +} + +void RectangleElement::setColor(Color color) { + this->color = color; +} + +void RectangleElement::draw(UIPoint screenPos, glm::mat4 projection) { + kekData.uiRectangleShader->use(); + + UIBounds offset = getBounds(); + + glUniformMatrix4fv(glGetUniformLocation(kekData.uiRectangleShader->id, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glm::vec4 bounds = glm::vec4(offset.x + screenPos.x, offset.y + screenPos.y, uiToScreen(w), uiToScreen(h)); + glUniform4fv(glGetUniformLocation(kekData.uiRectangleShader->id, "bounds"), 1, glm::value_ptr(bounds)); + glUniform4fv(glGetUniformLocation(kekData.uiRectangleShader->id, "rectColor"), 1, color.valuePointer()); + + glBindVertexArray(vao); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +ButtonElement::ButtonElement(UIValue x, UIValue y, UIValue w, UIValue h): RectangleElement(x, y, w, h) { + this->text = new TextElement(px(0), px(0)); +} + +ButtonElement::~ButtonElement() { + delete text; +} + +UIElementType ButtonElement::getType() { + return UIElementType::BUTTON; +} + +TextElement *ButtonElement::getText() { + return text; +} + +void ButtonElement::setColor(Color color) { + +} + +void ButtonElement::setOnClickCallback(Callable onClick) { + this->onClick = onClick; +} + +void ButtonElement::hover(UIPoint pos, UIPoint screenPos) { + +} + +void ButtonElement::hoverEnter() { + RectangleElement::setColor(Colors::RED); +} + +void ButtonElement::hoverExit() { + +} + +void ButtonElement::click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) { + +} + } diff --git a/src/kekengine/include/input.h b/src/kekengine/include/input.h index c8c7697..def5b69 100644 --- a/src/kekengine/include/input.h +++ b/src/kekengine/include/input.h @@ -7,10 +7,10 @@ namespace kek { -typedef generic_callable_t PeriodicCallback; // periodicCallback(GLFWwindow *window) -typedef generic_callable_t KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) -typedef generic_callable_t MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y) -typedef generic_callable_t MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +typedef GenericCallable PeriodicCallback; // periodicCallback(GLFWwindow *window) +typedef GenericCallable KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) +typedef GenericCallable MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y) +typedef GenericCallable MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) typedef unsigned int InputListener; typedef int GLFWKey; diff --git a/src/kekengine/include/internal.h b/src/kekengine/include/internal.h index 5d938c6..6e8bf50 100644 --- a/src/kekengine/include/internal.h +++ b/src/kekengine/include/internal.h @@ -36,6 +36,8 @@ struct KekData { FT_Library freetype; std::vector uiElements; + Font *uiDefaultFont; + Shader *uiRectangleShader; }; extern KekData kekData; diff --git a/src/kekengine/include/ui.h b/src/kekengine/include/ui.h index f10cec8..ac2bf63 100644 --- a/src/kekengine/include/ui.h +++ b/src/kekengine/include/ui.h @@ -120,8 +120,6 @@ struct UIValue { class UIElement { protected: - static Font *defaultFont; - UIElement *parent = nullptr; std::vector children; @@ -147,62 +145,50 @@ public: UIPoint getScreenPosition(); std::vector getChildren(); - void addChild(UIElement *child); - void removeChild(UIElement *child); protected: - inline int uiToScreen(UIValue val); + int uiToScreen(UIValue val); public: // Returns the bounds of the element relative to its origin (as returned by getX() and getY()) virtual UIBounds getBounds() = 0; void drawAll(UIPoint screenPos, glm::mat4 projection); - virtual void draw(UIPoint screenPos, glm::mat4 projection) = 0; - void hoverAll(UIPoint pos, UIPoint screenPos); - + bool hoverAll(UIPoint pos, UIPoint screenPos); void hoverExitAll(); - virtual void hoverEnter(UIPoint pos, UIPoint screenPos) {}; - virtual void hover(UIPoint pos, UIPoint screenPos) {}; - virtual void hoverExit() {}; - void clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button); - + bool clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button); virtual void click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) {}; bool focusEnterAll(UIPoint pos, UIPoint screenPos); - virtual void focusEnter(UIPoint pos, UIPoint screenPos) {}; - virtual void focusExit() {}; UIElement *dragEnterAll(UIPoint pos, UIPoint screenPos); - virtual void dragEnter(UIPoint pos, UIPoint screenPos) {}; - virtual void drag(UIPoint pos, UIPoint screenPos) {}; - virtual void dragExit(UIPoint pos, UIPoint screenPos) {}; - static void init(); - }; namespace UI { -void addElement(UIElement *element); - -void removeElement(UIElement *element); +void init(); +void destroy(); std::vector getElements(); +void addElement(UIElement *element); +void removeElement(UIElement *element); }; } + +#include "uielements.h" diff --git a/src/kekengine/include/uielements.h b/src/kekengine/include/uielements.h index 295a1b8..6a58332 100644 --- a/src/kekengine/include/uielements.h +++ b/src/kekengine/include/uielements.h @@ -20,12 +20,13 @@ class TextElement: public UIElement { protected: TextObject *text; + +public: int sizePixels; Color color; TextMode textMode; TextBounds textBounds; -public: TextElement(UIValue x, UIValue y, Font *font); TextElement(UIValue x, UIValue y); @@ -38,16 +39,62 @@ public: void setText(std::string text); - void setSizePixels(int sizePixels); + virtual void draw(UIPoint screenPos, glm::mat4 projection); - void setColor(Color color); +}; - void setTextMode(TextMode textMode); +class RectangleElement: public UIElement { - void setTextBounds(TextBounds textBounds); +protected: + UIValue w, h; + Color color; + + unsigned int vao; + unsigned int vbo; + +public: + RectangleElement(UIValue x, UIValue y, UIValue w, UIValue h); + + virtual ~RectangleElement(); + + virtual UIElementType getType(); + + virtual UIBounds getBounds(); + + virtual void setColor(Color color); virtual void draw(UIPoint screenPos, glm::mat4 projection); }; +class ButtonElement: public RectangleElement { + +protected: + TextElement *text; + Color color; + Callable onClick; + +public: + ButtonElement(UIValue x, UIValue y, UIValue w, UIValue h); + + virtual ~ButtonElement(); + + virtual UIElementType getType(); + + TextElement *getText(); + + virtual void setColor(Color color); + + void setOnClickCallback(Callable onClick); + + virtual void hover(UIPoint pos, UIPoint screenPos); + + virtual void hoverEnter(); + + virtual void hoverExit(); + + virtual void click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button); + +}; + } diff --git a/src/kekengine/include/utils.h b/src/kekengine/include/utils.h index 2254596..ea3562d 100644 --- a/src/kekengine/include/utils.h +++ b/src/kekengine/include/utils.h @@ -9,21 +9,24 @@ namespace kek { template -using generic_function_t = void(*)(Args... args); +using GenericFunction = void(*)(Args... args); template -struct generic_callable_t { - generic_function_t function; +struct GenericCallable { + GenericFunction function; void *data; - generic_callable_t(generic_function_t function, void *data): function(function), data(data) {} + GenericCallable(): function(nullptr), data(nullptr) {} + + GenericCallable(GenericFunction function, void *data): function(function), data(data) {} void operator()(Args... args) { + if(function == nullptr) return; function(args..., data); } }; -typedef generic_callable_t<> callable_t; +typedef GenericCallable<> Callable; float clampCyclic(float value, float min, float max); diff --git a/src/kekengine/res/shader/rectangle/fragment.glsl b/src/kekengine/res/shader/rectangle/fragment.glsl new file mode 100644 index 0000000..bb08b1f --- /dev/null +++ b/src/kekengine/res/shader/rectangle/fragment.glsl @@ -0,0 +1,9 @@ +#version 330 core + +out vec4 color; + +uniform vec4 rectColor; + +void main() { + color = rectColor; +} \ No newline at end of file diff --git a/src/kekengine/res/shader/rectangle/vertex.glsl b/src/kekengine/res/shader/rectangle/vertex.glsl new file mode 100644 index 0000000..33e457a --- /dev/null +++ b/src/kekengine/res/shader/rectangle/vertex.glsl @@ -0,0 +1,10 @@ +#version 330 core + +layout (location = 0) in vec2 position; + +uniform mat4 projection; +uniform vec4 bounds; + +void main() { + gl_Position = projection * vec4(position * bounds.zw + bounds.xy, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/kekgame/cpp/kekgame.cpp b/src/kekgame/cpp/kekgame.cpp index f524927..3f37986 100644 --- a/src/kekgame/cpp/kekgame.cpp +++ b/src/kekgame/cpp/kekgame.cpp @@ -17,6 +17,11 @@ void periodicCallback(GLFWwindow *window, void *data){ void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods, void *data){ if(key == Input::getKeyBinding(keyWow).key && action == GLFW_PRESS) { std::cout << "WOW" << std::endl; + if(glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + }else { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } } } @@ -61,5 +66,9 @@ int main(int argc, char **argv) { Input::addKeyListener(KeyCallback(keyCallback, nullptr)); Input::addMouseButtonListener(MouseButtonCallback(mouseButtonCallback, nullptr)); + ButtonElement *btn = new ButtonElement(px(0), px(100), px(200), px(50)); + btn->getText()->setText("Hello There!"); + UI::addElement(btn); + Engine::start(); }