From a9fbb909acde4754dd0b36acc812157a09ebcb44 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Fri, 12 Apr 2024 15:27:40 +0300 Subject: [PATCH 1/6] tmp --- CMakeLists.txt | 4 +- GeometryEditor2D/CMakeLists.txt | 22 +++++ GeometryEditor2D/applications/Entry.cpp | 39 +++++++++ GeometryEditor2D/private/Geometry.cpp | 0 GeometryEditor2D/private/Render.cpp | 76 ++++++++++++++++++ GeometryEditor2D/public/EditorWidget.hpp | 68 ++++++++++++++++ GeometryEditor2D/public/Geometry.hpp | 8 ++ GeometryEditor2D/public/Render.hpp | 23 ++++++ GeometryEditor2D/rsc/Font.ttf | Bin 0 -> 42624 bytes GeometryEditor2D/rsc/shaders/default.frag | 9 +++ GeometryEditor2D/rsc/shaders/default.vert | 22 +++++ Graphics/public/Graphics.hpp | 12 +-- RasterRender/CMakeLists.txt | 15 ++++ .../private/FrameBuffer.cpp | 41 ++++++---- {Sketch3D => RasterRender}/private/Shader.cpp | 0 .../private/Texture.cpp | 0 .../public/FrameBuffer.hpp | 0 .../public/GraphicsApi.hpp | 0 {Sketch3D => RasterRender}/public/Shader.hpp | 5 +- {Sketch3D => RasterRender}/public/Texture.hpp | 0 Sketch3D/CMakeLists.txt | 8 +- 21 files changed, 322 insertions(+), 30 deletions(-) create mode 100644 GeometryEditor2D/CMakeLists.txt create mode 100644 GeometryEditor2D/applications/Entry.cpp create mode 100644 GeometryEditor2D/private/Geometry.cpp create mode 100644 GeometryEditor2D/private/Render.cpp create mode 100644 GeometryEditor2D/public/EditorWidget.hpp create mode 100644 GeometryEditor2D/public/Geometry.hpp create mode 100644 GeometryEditor2D/public/Render.hpp create mode 100644 GeometryEditor2D/rsc/Font.ttf create mode 100644 GeometryEditor2D/rsc/shaders/default.frag create mode 100644 GeometryEditor2D/rsc/shaders/default.vert create mode 100644 RasterRender/CMakeLists.txt rename {Sketch3D => RasterRender}/private/FrameBuffer.cpp (71%) rename {Sketch3D => RasterRender}/private/Shader.cpp (100%) rename {Sketch3D => RasterRender}/private/Texture.cpp (100%) rename {Sketch3D => RasterRender}/public/FrameBuffer.hpp (100%) rename {Sketch3D => RasterRender}/public/GraphicsApi.hpp (100%) rename {Sketch3D => RasterRender}/public/Shader.hpp (99%) rename {Sketch3D => RasterRender}/public/Texture.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61301a1..18cea82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,4 +22,6 @@ add_subdirectory(DataAnalysis) add_subdirectory(Objects) add_subdirectory(Widgets) add_subdirectory(LibraryViewer) -add_subdirectory(Sketch3D) \ No newline at end of file +add_subdirectory(RasterRender) +add_subdirectory(Sketch3D) +add_subdirectory(GeometryEditor2D) \ No newline at end of file diff --git a/GeometryEditor2D/CMakeLists.txt b/GeometryEditor2D/CMakeLists.txt new file mode 100644 index 0000000..1cc6125 --- /dev/null +++ b/GeometryEditor2D/CMakeLists.txt @@ -0,0 +1,22 @@ +project(GeometryEditor2D) + +### ---------------------- Externals --------------------- ### +set(BINDINGS_INCLUDE ../Externals/glfw/include) +set(BINDINGS_LIBS glfw Imgui) + +### ---------------------- Static Library --------------------- ### +file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") +file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp") + +add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) + +target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ${BINDINGS_INCLUDE} ./ext/) +target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets Math RasterRender) +target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS}) + +### -------------------------- Applications -------------------------- ### +add_executable(geomEdit2d ./applications/Entry.cpp) +target_link_libraries(geomEdit2d ${PROJECT_NAME}) + +file(COPY "rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") +file(COPY "rsc/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") diff --git a/GeometryEditor2D/applications/Entry.cpp b/GeometryEditor2D/applications/Entry.cpp new file mode 100644 index 0000000..6062084 --- /dev/null +++ b/GeometryEditor2D/applications/Entry.cpp @@ -0,0 +1,39 @@ + +#include "EditorWidget.hpp" + +#include "GraphicApplication.hpp" + +using namespace tp; + +class EditorGUI : public Application { +public: + EditorGUI() { + Vec2F renderResolution = { 1000, 1000 }; + auto canvas = this->mGraphics->getCanvas(); + mGui = new EditorWidget(canvas, &geometry, renderResolution); + // + } + + ~EditorGUI() override { delete mGui; } + + void processFrame(EventHandler* eventHandler) override { + auto rec = RectF({ 0, 0 }, mWindow->getSize()); + mGui->proc(*eventHandler, rec, rec); + } + + void drawFrame(Canvas* canvas) override { mGui->draw(*canvas); } + +private: + Geometry geometry; + EditorWidget* mGui; +}; + +int main() { + GlobalGUIConfig mConfig; + gGlobalGUIConfig = &mConfig; + + { + EditorGUI gui; + gui.run(); + } +} diff --git a/GeometryEditor2D/private/Geometry.cpp b/GeometryEditor2D/private/Geometry.cpp new file mode 100644 index 0000000..e69de29 diff --git a/GeometryEditor2D/private/Render.cpp b/GeometryEditor2D/private/Render.cpp new file mode 100644 index 0000000..5d18f1c --- /dev/null +++ b/GeometryEditor2D/private/Render.cpp @@ -0,0 +1,76 @@ +#include "Render.hpp" + +#include "GraphicsApi.hpp" + +using namespace tp; + +struct Shape { + float buffer[6] = { + 0, 0, 1, 0, 0, 1, + }; + + GLuint vbo_id = 0; + GLuint vbo_len = 6; + + Shape() { + glGenBuffers(1, &vbo_id); + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_COPY); + } + + void drawCall() { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr); + glEnableVertexAttribArray(0); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(0); + glBindVertexArray(0); + } + + ~Shape() { glDeleteBuffers(1, &vbo_id); } +}; + +Render::Render(Vec2F renderResolution) : + mRenderBuffer(renderResolution) { + + mDefaultShader.load("rsc/shaders/default.vert", nullptr, "rsc/shaders/default.frag", true); +} + +Render::~Render() {} + +uint4 Render::getRenderBuffer() { return mRenderBuffer.texId(); } + +Vec2F Render::getBufferSize() { return mRenderBuffer.getSize(); } + +void Render::render(const Geometry& geometry, Vec2F size) { + + static Shape shape; + + mRenderBuffer.mClearCol = { 0.1f, 0.1f, 0.1f, 1.f }; + + mRenderBuffer.beginDraw(); + mRenderBuffer.clear(); + + { + mDefaultShader.bind(); + + static auto uniform_color = mDefaultShader.getu("Color"); + static auto uniform_scale = mDefaultShader.getu("Viewport"); + + RGBA col = { 0, 0, 1.f, 1.f }; + RectF viewport = { 0.0f, 0.0f, 1.f, 1.f }; + viewport.w = viewport.z * (size.y / size.x); + + glUniform4fv(uniform_color, 1, &col.r); + glUniform4fv(uniform_scale, 1, &viewport.x); + + shape.drawCall(); + + mDefaultShader.unbind(); + } + + mRenderBuffer.endDraw(); +} diff --git a/GeometryEditor2D/public/EditorWidget.hpp b/GeometryEditor2D/public/EditorWidget.hpp new file mode 100644 index 0000000..1288b32 --- /dev/null +++ b/GeometryEditor2D/public/EditorWidget.hpp @@ -0,0 +1,68 @@ +#include "Widgets.hpp" +#include "Render.hpp" + +namespace tp { + template + class ViewportWidget : public Widget { + public: + explicit ViewportWidget(Canvas* canvas, Geometry* geometry, Vec2F renderResolution) : + mRender(renderResolution) { + this->createConfig("ViewportWidget"); + mImage = canvas->createImageFromTextId(mRender.getRenderBuffer(), mRender.getBufferSize()); + mCanvas = canvas; + } + + ~ViewportWidget() { mCanvas->deleteImageHandle(mImage); } + + void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { + this->mArea = aArea; + this->mVisible = areaParent.isOverlap(aArea); + if (!this->mVisible) return; + + mRender.render(*mGeometry, this->mArea.size); + } + + void draw(Canvas& canvas) override { + if (!this->mVisible) return; + + canvas.drawImage(this->mArea, &mImage); + } + + public: + Render mRender; + Geometry* mGeometry = nullptr; + Canvas* mCanvas = nullptr; + Canvas::ImageHandle mImage; + }; + + template + class EditorWidget : public Widget { + public: + EditorWidget(Canvas* canvas, Geometry* geometry, Vec2F renderResolution) : + mViewport(canvas, geometry, renderResolution) { + this->createConfig("EditorWidget"); + this->addColor("Base", "Base"); + } + + void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { + this->mArea = aArea; + this->mVisible = areaParent.isOverlap(aArea); + if (!this->mVisible) return; + + mSplitView.proc(events, aArea, aArea); + mViewport.proc(events, aArea, mSplitView.getFirst()); + } + + void draw(Canvas& canvas) override { + if (!this->mVisible) return; + + canvas.rect(this->mArea, this->getColor("Base")); + mSplitView.draw(canvas); + mViewport.draw(canvas); + } + + public: + ViewportWidget mViewport; + SplitView mSplitView; + }; +} \ No newline at end of file diff --git a/GeometryEditor2D/public/Geometry.hpp b/GeometryEditor2D/public/Geometry.hpp new file mode 100644 index 0000000..13f4571 --- /dev/null +++ b/GeometryEditor2D/public/Geometry.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace tp { + class Geometry { + public: + Geometry() = default; + }; +} \ No newline at end of file diff --git a/GeometryEditor2D/public/Render.hpp b/GeometryEditor2D/public/Render.hpp new file mode 100644 index 0000000..310e9ed --- /dev/null +++ b/GeometryEditor2D/public/Render.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "Geometry.hpp" +#include "Rect.hpp" + +#include "FrameBuffer.hpp" +#include "Shader.hpp" + +namespace tp { + class Render { + public: + explicit Render(Vec2F renderResolution); + ~Render(); + + void render(const Geometry& geometry, Vec2F size); + uint4 getRenderBuffer(); + Vec2F getBufferSize(); + + private: + RenderBuffer mRenderBuffer; + RenderShader mDefaultShader; + }; +} \ No newline at end of file diff --git a/GeometryEditor2D/rsc/Font.ttf b/GeometryEditor2D/rsc/Font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8a630544c99ec9956153ebd9509abeac421c6d75 GIT binary patch literal 42624 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 mScissors; @@ -71,7 +71,9 @@ namespace tp { class Graphics { public: - explicit Graphics(Window* window) : mGui(window), mCanvas(window) {} + explicit Graphics(Window* window) : + mGui(window), + mCanvas(window) {} void procBegin() { mCanvas.procBegin(); @@ -88,14 +90,12 @@ namespace tp { mGui.drawBegin(); } - void drawEnd() { + void drawEnd() { mCanvas.drawEnd(); mGui.drawEnd(); } - Canvas* getCanvas() { - return &mCanvas; - } + Canvas* getCanvas() { return &mCanvas; } private: Canvas mCanvas; diff --git a/RasterRender/CMakeLists.txt b/RasterRender/CMakeLists.txt new file mode 100644 index 0000000..fd8c89c --- /dev/null +++ b/RasterRender/CMakeLists.txt @@ -0,0 +1,15 @@ +project(RasterRender) + +### ---------------------- Externals --------------------- ### +set(BINDINGS_INCLUDE ${GLEW_INCLUDE_DIR}) +set(BINDINGS_LIBS ${GLEW_LIB}) + +### ---------------------- Static Library --------------------- ### +file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") +file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp") + +add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) + +target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ${BINDINGS_INCLUDE} ./ext/) +target_link_libraries(${PROJECT_NAME} PUBLIC Math Connection) +target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS}) \ No newline at end of file diff --git a/Sketch3D/private/FrameBuffer.cpp b/RasterRender/private/FrameBuffer.cpp similarity index 71% rename from Sketch3D/private/FrameBuffer.cpp rename to RasterRender/private/FrameBuffer.cpp index 0804fae..a500e5e 100644 --- a/Sketch3D/private/FrameBuffer.cpp +++ b/RasterRender/private/FrameBuffer.cpp @@ -5,20 +5,26 @@ #include void glerr(GLenum type) { printf("GL ERROR\n"); } -#define AssertGL(x) { x; GLenum __gle = glGetError(); if (__gle != GL_NO_ERROR) glerr(__gle); } +#define AssertGL(x) \ + { \ + x; \ + GLenum __gle = glGetError(); \ + if (__gle != GL_NO_ERROR) glerr(__gle); \ + } using namespace tp; RenderBuffer::RenderBuffer(const Vec2F& size) : mSize(size) { - mDrawBuffers[0] = {GL_COLOR_ATTACHMENT0}; + mDrawBuffers[0] = { GL_COLOR_ATTACHMENT0 }; // --------- texture --------- AssertGL(glGenTextures(1, &mTextureId)); AssertGL(glBindTexture(GL_TEXTURE_2D, mTextureId)); // Give an empty image to OpenGL ( the last "0" ) - AssertGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); + AssertGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) size.x, (GLsizei) size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0) + ); // Poor filtering. Needed AssertGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); AssertGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); @@ -26,7 +32,7 @@ RenderBuffer::RenderBuffer(const Vec2F& size) : // --------- depth --------- AssertGL(glGenRenderbuffers(1, &mDepthBufferID)); AssertGL(glBindRenderbuffer(GL_RENDERBUFFER, mDepthBufferID)); - AssertGL(glRenderbufferStorage(GL_RENDERBUFFER, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei)size.x, (GLsizei)size.y)); + AssertGL(glRenderbufferStorage(GL_RENDERBUFFER, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei) size.x, (GLsizei) size.y)); // ------------ framebuffer ------------ AssertGL(glGenFramebuffers(1, &mFrameBufferID)); @@ -49,18 +55,24 @@ RenderBuffer::RenderBuffer(const Vec2F& size, tp::uint1 samples) : AssertGL(glGenTextures(1, &mTextureId)); AssertGL(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextureId)); #ifdef ENV_OS_ANDROID - AssertGL(glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, GL_TRUE)); + AssertGL( + glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei) size.x, (GLsizei) size.y, GL_TRUE) + ); #else - AssertGL(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, GL_TRUE)); + AssertGL( + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei) size.x, (GLsizei) size.y, GL_TRUE) + ); #endif // !? - //AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - //AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + // AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + // AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); // ------- depth ------- AssertGL(glGenRenderbuffers(1, &mDepthBufferID)); AssertGL(glBindRenderbuffer(GL_RENDERBUFFER, mDepthBufferID)); - AssertGL(glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei)size.x, (GLsizei)size.y)); + AssertGL(glRenderbufferStorageMultisample( + GL_RENDERBUFFER, samples, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei) size.x, (GLsizei) size.y + )); // ------- fbuff ------- AssertGL(glGenFramebuffers(1, &mFrameBufferID)); @@ -72,9 +84,7 @@ RenderBuffer::RenderBuffer(const Vec2F& size, tp::uint1 samples) : glBindFramebuffer(GL_FRAMEBUFFER, 0); } -uint4 RenderBuffer::buffId() const { - return mFrameBufferID; -} +uint4 RenderBuffer::buffId() const { return mFrameBufferID; } void RenderBuffer::beginDraw() { AssertGL(glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID)); @@ -82,7 +92,7 @@ void RenderBuffer::beginDraw() { } void RenderBuffer::setViewport(const RectF& viewport) { - AssertGL(glViewport((GLsizei)viewport.x, (GLsizei)viewport.y, (GLsizei)viewport.z, (GLsizei)viewport.w)); + AssertGL(glViewport((GLsizei) viewport.x, (GLsizei) viewport.y, (GLsizei) viewport.z, (GLsizei) viewport.w)); } void RenderBuffer::clear() { @@ -102,9 +112,6 @@ RenderBuffer::~RenderBuffer() { glDeleteRenderbuffers(1, &mDepthBufferID); } -uint4 RenderBuffer::texId() const { - return mTextureId; -} +uint4 RenderBuffer::texId() const { return mTextureId; } const Vec2F& RenderBuffer::getSize() const { return mSize; } - diff --git a/Sketch3D/private/Shader.cpp b/RasterRender/private/Shader.cpp similarity index 100% rename from Sketch3D/private/Shader.cpp rename to RasterRender/private/Shader.cpp diff --git a/Sketch3D/private/Texture.cpp b/RasterRender/private/Texture.cpp similarity index 100% rename from Sketch3D/private/Texture.cpp rename to RasterRender/private/Texture.cpp diff --git a/Sketch3D/public/FrameBuffer.hpp b/RasterRender/public/FrameBuffer.hpp similarity index 100% rename from Sketch3D/public/FrameBuffer.hpp rename to RasterRender/public/FrameBuffer.hpp diff --git a/Sketch3D/public/GraphicsApi.hpp b/RasterRender/public/GraphicsApi.hpp similarity index 100% rename from Sketch3D/public/GraphicsApi.hpp rename to RasterRender/public/GraphicsApi.hpp diff --git a/Sketch3D/public/Shader.hpp b/RasterRender/public/Shader.hpp similarity index 99% rename from Sketch3D/public/Shader.hpp rename to RasterRender/public/Shader.hpp index 8442e4d..253cdba 100644 --- a/Sketch3D/public/Shader.hpp +++ b/RasterRender/public/Shader.hpp @@ -13,14 +13,15 @@ namespace tp { void geom_bind_source(const char* geom_src); void compile(); - + void bind(); uint4 getu(const char* uid); void unbind(); + void load(const char* vert, const char* geom, const char* frag, bool paths); + private: bool compile_shader(const char* ShaderCode, uint4 ShaderID); - void load(const char* vert, const char* geom, const char* frag, bool paths); private: uint4 programm; diff --git a/Sketch3D/public/Texture.hpp b/RasterRender/public/Texture.hpp similarity index 100% rename from Sketch3D/public/Texture.hpp rename to RasterRender/public/Texture.hpp diff --git a/Sketch3D/CMakeLists.txt b/Sketch3D/CMakeLists.txt index 21fef33..248c80d 100644 --- a/Sketch3D/CMakeLists.txt +++ b/Sketch3D/CMakeLists.txt @@ -1,8 +1,8 @@ project(Sketch3D) ### ---------------------- Externals --------------------- ### -set(BINDINGS_INCLUDE ../Externals/glfw/include ${GLEW_INCLUDE_DIR}) -set(BINDINGS_LIBS glfw Imgui ${GLEW_LIB}) +set(BINDINGS_INCLUDE ../Externals/glfw/include) +set(BINDINGS_LIBS glfw Imgui) ### ---------------------- Static Library --------------------- ### file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") @@ -11,12 +11,12 @@ file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp") add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ${BINDINGS_INCLUDE} ./ext/) -target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets Math) +target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets Math RasterRender) target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS}) ### -------------------------- Applications -------------------------- ### add_executable(Sketch3DApp ./applications/Entry.cpp) target_link_libraries(Sketch3DApp ${PROJECT_NAME}) - + file(COPY "rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") file(COPY "applications/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") From e161fffc0cec8f516a8091186fbed4489361e2e8 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Fri, 12 Apr 2024 16:27:21 +0300 Subject: [PATCH 2/6] tmp --- GeometryEditor2D/private/Render.cpp | 56 ++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/GeometryEditor2D/private/Render.cpp b/GeometryEditor2D/private/Render.cpp index 5d18f1c..b1aee47 100644 --- a/GeometryEditor2D/private/Render.cpp +++ b/GeometryEditor2D/private/Render.cpp @@ -5,32 +5,56 @@ using namespace tp; struct Shape { - float buffer[6] = { - 0, 0, 1, 0, 0, 1, + float buffer[8] = { + 1, 1, 1, 0, 0, 0, // + 0, 1, // 1, 1, 0, 0, }; - GLuint vbo_id = 0; - GLuint vbo_len = 6; + unsigned int indices[6] = { 0, 1, 3, 1, 2, 3 }; + + GLuint VAO = 0; + GLuint VBO = 0; + GLuint EBO = 0; Shape() { - glGenBuffers(1, &vbo_id); - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_COPY); - } + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); - void drawCall() { - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr); glEnableVertexAttribArray(0); - glDrawArrays(GL_TRIANGLES, 0, 3); - - glDisableVertexAttribArray(0); + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } - ~Shape() { glDeleteBuffers(1, &vbo_id); } + void drawCall() { + const auto numPoints = sizeof(buffer) / (2 * sizeof(float)); + + glBindVertexArray(VAO); + + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + auto num = sizeof(indices) / sizeof(indices[0]); + glDrawElements(GL_TRIANGLES, num, GL_UNSIGNED_INT, nullptr); + + // glDrawArrays(GL_TRIANGLES, 0, sizeof(buffer) / (2 * sizeof(float))); + + // glBindVertexArray(0); + } + + ~Shape() { + glDeleteBuffers(1, &VBO); + glDeleteVertexArrays(1, &VAO); + } }; Render::Render(Vec2F renderResolution) : @@ -61,14 +85,14 @@ void Render::render(const Geometry& geometry, Vec2F size) { static auto uniform_scale = mDefaultShader.getu("Viewport"); RGBA col = { 0, 0, 1.f, 1.f }; - RectF viewport = { 0.0f, 0.0f, 1.f, 1.f }; + RectF viewport = { -1.0f, -1.0f, 3.f, 3.f }; viewport.w = viewport.z * (size.y / size.x); glUniform4fv(uniform_color, 1, &col.r); glUniform4fv(uniform_scale, 1, &viewport.x); shape.drawCall(); - + mDefaultShader.unbind(); } From 2160dfca34cdad9bd4dd5a5400340fca89ceaa0c Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Sat, 13 Apr 2024 12:28:46 +0300 Subject: [PATCH 3/6] tmp --- {GeometryEditor2D => 3DEditor}/CMakeLists.txt | 8 +- .../applications/Entry.cpp | 9 +- 3DEditor/applications/SceneLoad.cpp | 41 +++++++ 3DEditor/private/Render.cpp | 110 +++++++++++++++++ .../public/EditorWidget.hpp | 12 +- .../public/Render.hpp | 4 +- 3DEditor/public/Scene.hpp | 34 ++++++ {GeometryEditor2D => 3DEditor}/rsc/Font.ttf | Bin 3DEditor/rsc/scene.obj | 112 ++++++++++++++++++ 3DEditor/rsc/shaders/default.frag | 7 ++ 3DEditor/rsc/shaders/default.vert | 11 ++ CMakeLists.txt | 2 +- .../obj}/OBJ_LOADER_LICENSE.txt | 0 .../obj}/OBJ_Loader.h | 0 GeometryEditor2D/private/Geometry.cpp | 0 GeometryEditor2D/private/Render.cpp | 100 ---------------- GeometryEditor2D/public/Geometry.hpp | 8 -- GeometryEditor2D/rsc/shaders/default.frag | 9 -- GeometryEditor2D/rsc/shaders/default.vert | 22 ---- Math/public/Topology.hpp | 2 +- RayTracer/CMakeLists.txt | 2 +- RayTracer/applications/SceneLoad.cpp | 3 +- 22 files changed, 339 insertions(+), 157 deletions(-) rename {GeometryEditor2D => 3DEditor}/CMakeLists.txt (79%) rename {GeometryEditor2D => 3DEditor}/applications/Entry.cpp (79%) create mode 100644 3DEditor/applications/SceneLoad.cpp create mode 100644 3DEditor/private/Render.cpp rename {GeometryEditor2D => 3DEditor}/public/EditorWidget.hpp (84%) rename {GeometryEditor2D => 3DEditor}/public/Render.hpp (80%) create mode 100644 3DEditor/public/Scene.hpp rename {GeometryEditor2D => 3DEditor}/rsc/Font.ttf (100%) create mode 100644 3DEditor/rsc/scene.obj create mode 100644 3DEditor/rsc/shaders/default.frag create mode 100644 3DEditor/rsc/shaders/default.vert rename {RayTracer/applications => Externals/obj}/OBJ_LOADER_LICENSE.txt (100%) rename {RayTracer/applications => Externals/obj}/OBJ_Loader.h (100%) delete mode 100644 GeometryEditor2D/private/Geometry.cpp delete mode 100644 GeometryEditor2D/private/Render.cpp delete mode 100644 GeometryEditor2D/public/Geometry.hpp delete mode 100644 GeometryEditor2D/rsc/shaders/default.frag delete mode 100644 GeometryEditor2D/rsc/shaders/default.vert diff --git a/GeometryEditor2D/CMakeLists.txt b/3DEditor/CMakeLists.txt similarity index 79% rename from GeometryEditor2D/CMakeLists.txt rename to 3DEditor/CMakeLists.txt index 1cc6125..4ade195 100644 --- a/GeometryEditor2D/CMakeLists.txt +++ b/3DEditor/CMakeLists.txt @@ -1,7 +1,7 @@ -project(GeometryEditor2D) +project(3DEditor) ### ---------------------- Externals --------------------- ### -set(BINDINGS_INCLUDE ../Externals/glfw/include) +set(BINDINGS_INCLUDE ../Externals/glfw/include ../Externals) set(BINDINGS_LIBS glfw Imgui) ### ---------------------- Static Library --------------------- ### @@ -15,8 +15,8 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets Math Ra target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS}) ### -------------------------- Applications -------------------------- ### -add_executable(geomEdit2d ./applications/Entry.cpp) -target_link_libraries(geomEdit2d ${PROJECT_NAME}) +add_executable(edit3d ./applications/Entry.cpp ./applications/SceneLoad.cpp) +target_link_libraries(edit3d ${PROJECT_NAME} Lua ImageIO) file(COPY "rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") file(COPY "rsc/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") diff --git a/GeometryEditor2D/applications/Entry.cpp b/3DEditor/applications/Entry.cpp similarity index 79% rename from GeometryEditor2D/applications/Entry.cpp rename to 3DEditor/applications/Entry.cpp index 6062084..db5cfbf 100644 --- a/GeometryEditor2D/applications/Entry.cpp +++ b/3DEditor/applications/Entry.cpp @@ -5,13 +5,18 @@ using namespace tp; +bool loadMeshes(tp::Scene& scene, const std::string& objetsPath); + class EditorGUI : public Application { public: EditorGUI() { Vec2F renderResolution = { 1000, 1000 }; auto canvas = this->mGraphics->getCanvas(); mGui = new EditorWidget(canvas, &geometry, renderResolution); - // + + loadMeshes(geometry, "rsc/scene.obj"); + + geometry.mCamera.lookAtPoint({ 0, 0, 0 }, { 3, 3, 2 }, { 0, 0, 1 }); } ~EditorGUI() override { delete mGui; } @@ -24,7 +29,7 @@ public: void drawFrame(Canvas* canvas) override { mGui->draw(*canvas); } private: - Geometry geometry; + Scene geometry; EditorWidget* mGui; }; diff --git a/3DEditor/applications/SceneLoad.cpp b/3DEditor/applications/SceneLoad.cpp new file mode 100644 index 0000000..bc03e0c --- /dev/null +++ b/3DEditor/applications/SceneLoad.cpp @@ -0,0 +1,41 @@ +#include "Scene.hpp" + +#include "obj/OBJ_Loader.h" +#include + +bool loadMeshes(tp::Scene& scene, const std::string& objetsPath) { + using namespace tp; + + objl::Loader Loader; + + if (!Loader.LoadFile(objetsPath.c_str())) { + std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n"; + return false; + } + + for (auto& curMesh : Loader.LoadedMeshes) { + scene.mObjects.append(Object()); + + auto object = &scene.mObjects.last(); + + for (auto& vertex : curMesh.Vertices) { + // printf("{ %f, %f, %f }, \n", vertex.Position.X, vertex.Position.Y, vertex.Position.Z); + object->mTopology.Points.append(Vec3F{ vertex.Position.X, vertex.Position.Y, vertex.Position.Z }); + object->mTopology.Normals.append(Vec3F{ vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z }); + } + + for (int j = 0; j < curMesh.Indices.size(); j += 3) { + uint idx1 = (int) curMesh.Indices[j]; + uint idx2 = (int) curMesh.Indices[j + 1]; + uint idx3 = (int) curMesh.Indices[j + 2]; + // printf("{ %i, %i, %i },\n", idx1, idx2, idx3); + object->mTopology.Indexes.append({ idx1, idx2, idx3 }); + } + + if (object->mTopology.Normals.size() != object->mTopology.Points.size()) { + printf("Logic error loading normals\n"); + } + } + + return scene.mObjects.size(); +} diff --git a/3DEditor/private/Render.cpp b/3DEditor/private/Render.cpp new file mode 100644 index 0000000..ec98be5 --- /dev/null +++ b/3DEditor/private/Render.cpp @@ -0,0 +1,110 @@ +#include "Render.hpp" + +#include "GraphicsApi.hpp" + +using namespace tp; + +class ObjectBuffers { +public: + ObjectBuffers(Object* object) { + mObject = (object); + + auto& buff = mObject->mTopology.Points; + auto& indices = mObject->mTopology.Indexes; + + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(Vec3F) * buff.size(), buff.getBuff(), GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Vec3) * indices.size(), indices.getBuff(), GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); + glEnableVertexAttribArray(0); + + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + } + + Object* mObject = nullptr; + + GLuint VAO = 0; + GLuint VBO = 0; + GLuint EBO = 0; + + void drawCall() { + auto& indices = mObject->mTopology.Indexes; + + glBindVertexArray(VAO); + + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glDrawElements(GL_TRIANGLES, indices.size() * 3, GL_UNSIGNED_INT, nullptr); + + // glDrawArrays(GL_TRIANGLES, 0, sizeof(buffer) / (2 * sizeof(float))); + + // glBindVertexArray(0); + } + + ~ObjectBuffers() { + glDeleteBuffers(1, &VBO); + glDeleteVertexArrays(1, &VAO); + } +}; + +Render::Render(Vec2F renderResolution) : + mRenderBuffer(renderResolution) { + + mDefaultShader.load("rsc/shaders/default.vert", nullptr, "rsc/shaders/default.frag", true); +} + +Render::~Render() {} + +uint4 Render::getRenderBuffer() { return mRenderBuffer.texId(); } + +Vec2F Render::getBufferSize() { return mRenderBuffer.getSize(); } + +void Render::render(const Scene& geometry, Vec2F size) { + + for (auto object : geometry.mObjects) { + if (!object->mBuffers) { + object->mBuffers = std::make_shared(&object.data()); + } + } + + mRenderBuffer.mClearCol = { 0.0f, 0.0f, 0.0f, 0.f }; + + mRenderBuffer.beginDraw(); + mRenderBuffer.clear(); + + mDefaultShader.bind(); + + Mat4F cameraMat = geometry.mCamera.calculateTransformationMatrix(); + + glEnable(GL_DEPTH_TEST); + + for (auto object : geometry.mObjects) { + + static auto origin = (GLint) mDefaultShader.getu("Origin"); + static auto basis = (GLint) mDefaultShader.getu("Basis"); + static auto camera = (GLint) mDefaultShader.getu("Camera"); + + Mat4F basisMat; + Vec4F originPoint; + + glUniform4fv(origin, 1, &originPoint[0]); + glUniformMatrix4fv(basis, 1, false, &basisMat[0][0]); + glUniformMatrix4fv(camera, 1, true, &cameraMat[0][0]); + + object->mBuffers->drawCall(); + } + + mDefaultShader.unbind(); + + mRenderBuffer.endDraw(); +} diff --git a/GeometryEditor2D/public/EditorWidget.hpp b/3DEditor/public/EditorWidget.hpp similarity index 84% rename from GeometryEditor2D/public/EditorWidget.hpp rename to 3DEditor/public/EditorWidget.hpp index 1288b32..76650d2 100644 --- a/GeometryEditor2D/public/EditorWidget.hpp +++ b/3DEditor/public/EditorWidget.hpp @@ -5,8 +5,9 @@ namespace tp { template class ViewportWidget : public Widget { public: - explicit ViewportWidget(Canvas* canvas, Geometry* geometry, Vec2F renderResolution) : + explicit ViewportWidget(Canvas* canvas, Scene* geometry, Vec2F renderResolution) : mRender(renderResolution) { + mGeometry = geometry; this->createConfig("ViewportWidget"); mImage = canvas->createImageFromTextId(mRender.getRenderBuffer(), mRender.getBufferSize()); mCanvas = canvas; @@ -19,18 +20,19 @@ namespace tp { this->mVisible = areaParent.isOverlap(aArea); if (!this->mVisible) return; - mRender.render(*mGeometry, this->mArea.size); + mGeometry->mCamera.rotate(0.01f, 0.0); } void draw(Canvas& canvas) override { if (!this->mVisible) return; - canvas.drawImage(this->mArea, &mImage); + mRender.render(*mGeometry, this->mArea.size); + canvas.drawImage(this->mArea, &mImage, PI); } public: Render mRender; - Geometry* mGeometry = nullptr; + Scene* mGeometry = nullptr; Canvas* mCanvas = nullptr; Canvas::ImageHandle mImage; }; @@ -38,7 +40,7 @@ namespace tp { template class EditorWidget : public Widget { public: - EditorWidget(Canvas* canvas, Geometry* geometry, Vec2F renderResolution) : + EditorWidget(Canvas* canvas, Scene* geometry, Vec2F renderResolution) : mViewport(canvas, geometry, renderResolution) { this->createConfig("EditorWidget"); this->addColor("Base", "Base"); diff --git a/GeometryEditor2D/public/Render.hpp b/3DEditor/public/Render.hpp similarity index 80% rename from GeometryEditor2D/public/Render.hpp rename to 3DEditor/public/Render.hpp index 310e9ed..818ffe8 100644 --- a/GeometryEditor2D/public/Render.hpp +++ b/3DEditor/public/Render.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Geometry.hpp" +#include "Scene.hpp" #include "Rect.hpp" #include "FrameBuffer.hpp" @@ -12,7 +12,7 @@ namespace tp { explicit Render(Vec2F renderResolution); ~Render(); - void render(const Geometry& geometry, Vec2F size); + void render(const Scene& geometry, Vec2F size); uint4 getRenderBuffer(); Vec2F getBufferSize(); diff --git a/3DEditor/public/Scene.hpp b/3DEditor/public/Scene.hpp new file mode 100644 index 0000000..9b995ba --- /dev/null +++ b/3DEditor/public/Scene.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "Topology.hpp" +#include + +class ObjectBuffers; + +namespace tp { + + class Object { + public: + Object() = default; + + public: + Topology mTopology; + std::shared_ptr mBuffers; + }; + + struct PointLight { + Vec3F pos; + halnf fallOut = 1.f; + halnf intensity = 1.f; + }; + + class Scene { + public: + Scene() = default; + + public: + Buffer mObjects; + Buffer mLights; + Camera mCamera; + }; +} \ No newline at end of file diff --git a/GeometryEditor2D/rsc/Font.ttf b/3DEditor/rsc/Font.ttf similarity index 100% rename from GeometryEditor2D/rsc/Font.ttf rename to 3DEditor/rsc/Font.ttf diff --git a/3DEditor/rsc/scene.obj b/3DEditor/rsc/scene.obj new file mode 100644 index 0000000..4368e9e --- /dev/null +++ b/3DEditor/rsc/scene.obj @@ -0,0 +1,112 @@ +# Blender v3.0.1 OBJ File: 'scene.blend' +# www.blender.org +mtllib meshes.mtl +o Cube +v -1.039076 1.039076 1.792917 +v -1.039076 1.039076 -1.285234 +v 1.039076 1.039076 1.792917 +v 1.039076 1.039076 -1.285234 +v -1.039076 -1.039076 1.792917 +v -1.039076 -1.039076 -1.285234 +v 1.039076 -1.039076 1.792917 +v 1.039076 -1.039076 -1.285234 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.875000 0.750000 +vt 0.875000 0.500000 +vt 0.375000 0.750000 +vt 0.375000 1.000000 +vt 0.625000 1.000000 +vt 0.375000 0.000000 +vt 0.375000 0.250000 +vt 0.625000 0.250000 +vt 0.625000 0.000000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.375000 0.500000 +vn 0.0000 0.0000 -1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 1.0000 0.0000 0.0000 +usemtl Material +s off +f 1/1/1 3/2/1 7/3/1 5/4/1 +f 4/5/2 8/6/2 7/7/2 3/2/2 +f 8/8/3 6/9/3 5/10/3 7/11/3 +f 6/12/4 8/13/4 4/5/4 2/14/4 +f 6/9/5 2/14/5 1/1/5 5/10/5 +o Cube.001 +v 0.411013 -0.208216 -1.264212 +v 0.411013 -0.208216 -0.612621 +v -0.208216 -0.411013 -1.264212 +v -0.208216 -0.411013 -0.612621 +v 0.208216 0.411013 -1.264212 +v 0.208216 0.411013 -0.612621 +v -0.411013 0.208216 -1.264212 +v -0.411013 0.208216 -0.612621 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vn 0.3112 -0.9503 0.0000 +vn -0.9503 -0.3112 0.0000 +vn -0.3112 0.9503 0.0000 +vn 0.9503 0.3112 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 0.0000 1.0000 +usemtl None +s off +f 9/15/6 10/16/6 12/17/6 11/18/6 +f 11/18/7 12/17/7 16/19/7 15/20/7 +f 15/20/8 16/19/8 14/21/8 13/22/8 +f 13/22/9 14/21/9 10/23/9 9/24/9 +f 11/25/10 15/20/10 13/22/10 9/26/10 +f 16/19/11 12/27/11 10/28/11 14/21/11 +o Cube.002 +v -0.351718 -0.467100 -0.602050 +v -0.351718 -0.467100 0.049542 +v -0.800825 0.004996 -0.602050 +v -0.800825 0.004996 0.049542 +v 0.120377 -0.017993 -0.602050 +v 0.120377 -0.017993 0.049542 +v -0.328730 0.454103 -0.602050 +v -0.328730 0.454103 0.049542 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vn -0.7245 -0.6892 0.0000 +vn -0.6892 0.7245 0.0000 +vn 0.7245 0.6892 0.0000 +vn 0.6892 -0.7245 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 0.0000 1.0000 +usemtl None +s off +f 17/29/12 18/30/12 20/31/12 19/32/12 +f 19/32/13 20/31/13 24/33/13 23/34/13 +f 23/34/14 24/33/14 22/35/14 21/36/14 +f 21/36/15 22/35/15 18/37/15 17/38/15 +f 19/39/16 23/34/16 21/36/16 17/40/16 +f 24/33/17 20/41/17 18/42/17 22/35/17 diff --git a/3DEditor/rsc/shaders/default.frag b/3DEditor/rsc/shaders/default.frag new file mode 100644 index 0000000..e142a37 --- /dev/null +++ b/3DEditor/rsc/shaders/default.frag @@ -0,0 +1,7 @@ +#version 330 core + +out vec4 FragColor; + +void main() { + FragColor = vec4(gl_FragCoord.z, gl_FragCoord.z, gl_FragCoord.z, 1.f); +} \ No newline at end of file diff --git a/3DEditor/rsc/shaders/default.vert b/3DEditor/rsc/shaders/default.vert new file mode 100644 index 0000000..7d1fd94 --- /dev/null +++ b/3DEditor/rsc/shaders/default.vert @@ -0,0 +1,11 @@ +#version 330 core + +layout(location = 0) in vec3 Point; + +uniform vec4 Origin; +uniform mat4 Basis; +uniform mat4 Camera; + +void main() { + gl_Position = Camera * vec4(Point.xyz, 1.0); +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 18cea82..85f36c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,4 +24,4 @@ add_subdirectory(Widgets) add_subdirectory(LibraryViewer) add_subdirectory(RasterRender) add_subdirectory(Sketch3D) -add_subdirectory(GeometryEditor2D) \ No newline at end of file +add_subdirectory(3DEditor) \ No newline at end of file diff --git a/RayTracer/applications/OBJ_LOADER_LICENSE.txt b/Externals/obj/OBJ_LOADER_LICENSE.txt similarity index 100% rename from RayTracer/applications/OBJ_LOADER_LICENSE.txt rename to Externals/obj/OBJ_LOADER_LICENSE.txt diff --git a/RayTracer/applications/OBJ_Loader.h b/Externals/obj/OBJ_Loader.h similarity index 100% rename from RayTracer/applications/OBJ_Loader.h rename to Externals/obj/OBJ_Loader.h diff --git a/GeometryEditor2D/private/Geometry.cpp b/GeometryEditor2D/private/Geometry.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/GeometryEditor2D/private/Render.cpp b/GeometryEditor2D/private/Render.cpp deleted file mode 100644 index b1aee47..0000000 --- a/GeometryEditor2D/private/Render.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "Render.hpp" - -#include "GraphicsApi.hpp" - -using namespace tp; - -struct Shape { - float buffer[8] = { - 1, 1, 1, 0, 0, 0, // - 0, 1, // 1, 1, 0, 0, - }; - - unsigned int indices[6] = { 0, 1, 3, 1, 2, 3 }; - - GLuint VAO = 0; - GLuint VBO = 0; - GLuint EBO = 0; - - Shape() { - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &VBO); - glGenBuffers(1, &EBO); - - glBindVertexArray(VAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr); - glEnableVertexAttribArray(0); - - // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - - void drawCall() { - const auto numPoints = sizeof(buffer) / (2 * sizeof(float)); - - glBindVertexArray(VAO); - - // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); - auto num = sizeof(indices) / sizeof(indices[0]); - glDrawElements(GL_TRIANGLES, num, GL_UNSIGNED_INT, nullptr); - - // glDrawArrays(GL_TRIANGLES, 0, sizeof(buffer) / (2 * sizeof(float))); - - // glBindVertexArray(0); - } - - ~Shape() { - glDeleteBuffers(1, &VBO); - glDeleteVertexArrays(1, &VAO); - } -}; - -Render::Render(Vec2F renderResolution) : - mRenderBuffer(renderResolution) { - - mDefaultShader.load("rsc/shaders/default.vert", nullptr, "rsc/shaders/default.frag", true); -} - -Render::~Render() {} - -uint4 Render::getRenderBuffer() { return mRenderBuffer.texId(); } - -Vec2F Render::getBufferSize() { return mRenderBuffer.getSize(); } - -void Render::render(const Geometry& geometry, Vec2F size) { - - static Shape shape; - - mRenderBuffer.mClearCol = { 0.1f, 0.1f, 0.1f, 1.f }; - - mRenderBuffer.beginDraw(); - mRenderBuffer.clear(); - - { - mDefaultShader.bind(); - - static auto uniform_color = mDefaultShader.getu("Color"); - static auto uniform_scale = mDefaultShader.getu("Viewport"); - - RGBA col = { 0, 0, 1.f, 1.f }; - RectF viewport = { -1.0f, -1.0f, 3.f, 3.f }; - viewport.w = viewport.z * (size.y / size.x); - - glUniform4fv(uniform_color, 1, &col.r); - glUniform4fv(uniform_scale, 1, &viewport.x); - - shape.drawCall(); - - mDefaultShader.unbind(); - } - - mRenderBuffer.endDraw(); -} diff --git a/GeometryEditor2D/public/Geometry.hpp b/GeometryEditor2D/public/Geometry.hpp deleted file mode 100644 index 13f4571..0000000 --- a/GeometryEditor2D/public/Geometry.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace tp { - class Geometry { - public: - Geometry() = default; - }; -} \ No newline at end of file diff --git a/GeometryEditor2D/rsc/shaders/default.frag b/GeometryEditor2D/rsc/shaders/default.frag deleted file mode 100644 index 0850bdc..0000000 --- a/GeometryEditor2D/rsc/shaders/default.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 330 core - -uniform vec4 Color; - -out vec4 FragColor; - -void main() { - FragColor = vec4(1.f); -} \ No newline at end of file diff --git a/GeometryEditor2D/rsc/shaders/default.vert b/GeometryEditor2D/rsc/shaders/default.vert deleted file mode 100644 index 2ba27d7..0000000 --- a/GeometryEditor2D/rsc/shaders/default.vert +++ /dev/null @@ -1,22 +0,0 @@ -#version 330 core - -layout(location = 0) in vec2 point; - -uniform vec4 Viewport; - -void main() { - vec2 transformedPoint = point; - - transformedPoint.x = transformedPoint.x - Viewport.x; - transformedPoint.y = transformedPoint.y - Viewport.y; - - transformedPoint.x = transformedPoint.x / Viewport.z; - transformedPoint.y = transformedPoint.y / Viewport.w; - - transformedPoint.y = -transformedPoint.y; - - transformedPoint.y = transformedPoint.y * 2; - transformedPoint.x = transformedPoint.x * 2; - - gl_Position = vec4(transformedPoint.x - 1, transformedPoint.y + 1, 1.0, 1.0); -} \ No newline at end of file diff --git a/Math/public/Topology.hpp b/Math/public/Topology.hpp index f29fb36..92cb1a0 100644 --- a/Math/public/Topology.hpp +++ b/Math/public/Topology.hpp @@ -34,7 +34,7 @@ namespace tp { Buffer Points; Buffer Normals; - Buffer Indexes; + Buffer> Indexes; }; struct TopologyCache { diff --git a/RayTracer/CMakeLists.txt b/RayTracer/CMakeLists.txt index d40c663..ae8c52b 100644 --- a/RayTracer/CMakeLists.txt +++ b/RayTracer/CMakeLists.txt @@ -4,7 +4,7 @@ project(RayTracer) file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp" "./applications/*.hpp") add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) -target_include_directories(${PROJECT_NAME} PUBLIC ./public/) +target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ../Externals/) target_link_libraries(${PROJECT_NAME} PUBLIC Math Connection) ### -------------------------- Applications -------------------------- ### diff --git a/RayTracer/applications/SceneLoad.cpp b/RayTracer/applications/SceneLoad.cpp index 724e62b..a1f53da 100644 --- a/RayTracer/applications/SceneLoad.cpp +++ b/RayTracer/applications/SceneLoad.cpp @@ -6,7 +6,7 @@ extern "C" { #include "lualib.h" } -#include "OBJ_Loader.h" +#include "obj/OBJ_Loader.h" #include @@ -139,7 +139,6 @@ void loadScene(tp::Scene& scene, const std::string& scenePath, tp::RayTracer::Re // Remove the filename from the path fs::path directoryPath = fullPath.remove_filename(); - if (luaL_dofile(L, scenePath.c_str()) != 0) { lua_close(L); printf("Cant open scene script.\n"); From 8171ba03daa196f2c5b94a13e544cf8c4367e0f0 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Thu, 18 Apr 2024 12:54:37 +0300 Subject: [PATCH 4/6] tmp --- 3DEditor/applications/Entry.cpp | 15 ++++---- 3DEditor/public/EditorWidget.hpp | 36 ++++++++++++++++++- Containers/public/Map.hpp | 16 +++++++-- Widgets/examples/Entry.cpp | 11 ++---- Widgets/private/WidgetConfig.cpp | 4 +-- Widgets/public/WidgetBase.hpp | 48 +++++++++++++++++-------- Widgets/public/WidgetConfig.hpp | 61 ++++++++++++++++++++++---------- 7 files changed, 135 insertions(+), 56 deletions(-) diff --git a/3DEditor/applications/Entry.cpp b/3DEditor/applications/Entry.cpp index db5cfbf..fdd62de 100644 --- a/3DEditor/applications/Entry.cpp +++ b/3DEditor/applications/Entry.cpp @@ -12,8 +12,10 @@ public: EditorGUI() { Vec2F renderResolution = { 1000, 1000 }; auto canvas = this->mGraphics->getCanvas(); - mGui = new EditorWidget(canvas, &geometry, renderResolution); + // mGui = new EditorWidget(canvas, &geometry, renderResolution); + mGui = new ShortcutsTest(); + loadMeshes(geometry, "rsc/scene.obj"); geometry.mCamera.lookAtPoint({ 0, 0, 0 }, { 3, 3, 2 }, { 0, 0, 1 }); @@ -30,15 +32,10 @@ public: private: Scene geometry; - EditorWidget* mGui; + ShortcutsTest* mGui; }; int main() { - GlobalGUIConfig mConfig; - gGlobalGUIConfig = &mConfig; - - { - EditorGUI gui; - gui.run(); - } + EditorGUI gui; + gui.run(); } diff --git a/3DEditor/public/EditorWidget.hpp b/3DEditor/public/EditorWidget.hpp index 76650d2..cabd207 100644 --- a/3DEditor/public/EditorWidget.hpp +++ b/3DEditor/public/EditorWidget.hpp @@ -2,14 +2,48 @@ #include "Render.hpp" namespace tp { + + template + class ShortcutsTest : public Widget { + public: + ShortcutsTest() { this->createConfig("ShortcutsTest"); } + + void action(const Events&) { + // + } + + void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { + this->mArea = aArea; + this->mVisible = areaParent.isOverlap(aArea); + if (!this->mVisible) return; + } + + void draw(Canvas& canvas) override { + if (!this->mVisible) return; + canvas.rect(this->mArea, this->getColor("Base")); + } + + void populateConfig() override { + this->addColor("Base", "Base"); + + this->addOperator("OperatorName", { this, [](void* self, const Events& events) { + ((ShortcutsTest*) self)->action(events); + } }); + + this->getShortcuts("OperatorName").append({ { "Alt", "Hold" }, { "Mouse1", "Hold" } }); + this->getShortcuts("OperatorName").append({ { "Alt", "Hold" }, { "Mouse1", "Hold" } }); + } + }; + template class ViewportWidget : public Widget { public: explicit ViewportWidget(Canvas* canvas, Scene* geometry, Vec2F renderResolution) : mRender(renderResolution) { - mGeometry = geometry; this->createConfig("ViewportWidget"); + mImage = canvas->createImageFromTextId(mRender.getRenderBuffer(), mRender.getBufferSize()); + mGeometry = geometry; mCanvas = canvas; } diff --git a/Containers/public/Map.hpp b/Containers/public/Map.hpp index 642a6d9..fd50491 100644 --- a/Containers/public/Map.hpp +++ b/Containers/public/Map.hpp @@ -11,7 +11,12 @@ namespace tp { return hash(key); } - template ) = DefaultHashFunc, int tTableInitialSize = 4> + template < + typename tKey, + typename tVal, + class tAllocator = DefaultAllocator, + ualni (*tHashFunc)(SelectValueOrReference) = DefaultHashFunc, + int tTableInitialSize = 4> class Map { enum { @@ -223,6 +228,13 @@ namespace tp { return mTable[slot]->val; } + tVal& operator[](KeyArg key) { + auto idx = presents(key); + if (idx.isValid()) return getSlotVal(idx); + put(key, {}); + return get(key); + } + tVal& getSlotVal(ualni slot) { DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error") return mTable[slot]->val; @@ -242,7 +254,7 @@ namespace tp { if (this == &in) { return *this; } - + for (ualni i = 0; i < mNSlots; i++) { if (mTable[i] && !isDeletedNode(mTable[i])) { deleteNode(mTable[i]); diff --git a/Widgets/examples/Entry.cpp b/Widgets/examples/Entry.cpp index c7fc1d1..17a643b 100644 --- a/Widgets/examples/Entry.cpp +++ b/Widgets/examples/Entry.cpp @@ -9,23 +9,18 @@ class ExampleGUI : public Application { public: ExampleGUI() = default; - void processFrame(EventHandler* eventHandler) override { - auto rec = RectF( { 0, 0 }, mWindow->getSize() ); + void processFrame(EventHandler* eventHandler) override { + auto rec = RectF({ 0, 0 }, mWindow->getSize()); mGui.proc(*eventHandler, rec, rec); } - void drawFrame(Canvas* canvas) override { - mGui.draw(*canvas); - } + void drawFrame(Canvas* canvas) override { mGui.draw(*canvas); } private: ComplexWidget mGui; }; int main() { - GlobalGUIConfig mConfig; - gGlobalGUIConfig = &mConfig; - { ExampleGUI gui; gui.run(); diff --git a/Widgets/private/WidgetConfig.cpp b/Widgets/private/WidgetConfig.cpp index 8984b72..5a2cf39 100644 --- a/Widgets/private/WidgetConfig.cpp +++ b/Widgets/private/WidgetConfig.cpp @@ -3,6 +3,4 @@ #include "Graphics.hpp" -namespace tp { - GlobalGUIConfig* gGlobalGUIConfig = nullptr; -} \ No newline at end of file +namespace tp {} \ No newline at end of file diff --git a/Widgets/public/WidgetBase.hpp b/Widgets/public/WidgetBase.hpp index 3fcd190..b9bf46c 100644 --- a/Widgets/public/WidgetBase.hpp +++ b/Widgets/public/WidgetBase.hpp @@ -1,3 +1,4 @@ +; #pragma once #include "WidgetConfig.hpp" @@ -7,39 +8,47 @@ namespace tp { template class Widget { public: - Widget() { - this->mArea = { 0, 0, 100, 100 }; - } + using WidgetConfig = WidgetConfig; + using WidgetNode = WidgetConfig::Node; + using GlobalGUIConfig = GlobalGUIConfig; + + Widget() { this->mArea = { 0, 0, 100, 100 }; } + + virtual void populateConfig() {} [[nodiscard]] const RGBA& getColor(const std::string& name) const { const auto& node = cfg->values.get(name); - if (node.type == WidgetConfig::Node::REF) { - return globalCfg->configs.get(node.refGroup).values.get(node.refName).color; + if (node.type == WidgetNode::REF) { + return mGlobalCfg.configs.get(node.refGroup).values.get(node.refName).color; } return cfg->values.get(name).color; } [[nodiscard]] halnf getValue(const std::string& name) const { const auto& node = cfg->values.get(name); - if (node.type == WidgetConfig::Node::REF) { - return globalCfg->configs.get(node.refGroup).values.get(node.refName).value; + if (node.type == WidgetNode::REF) { + return mGlobalCfg.configs.get(node.refGroup).values.get(node.refName).value; } return cfg->values.get(name).value; } - void addColor(const std::string& name, const RGBA& val) { cfg->values.put(name, WidgetConfig::Node(val)); } - void addValue(const std::string& name, halnf val) { cfg->values.put(name, WidgetConfig::Node(val)); } + void addColor(const std::string& name, const RGBA& val) { cfg->values.put(name, WidgetNode(val)); } + void addValue(const std::string& name, halnf val) { cfg->values.put(name, WidgetNode(val)); } void addColor(const std::string& name, const std::string& presetName) { - cfg->values.put(name, WidgetConfig::Node(presetName)); + cfg->values.put(name, WidgetNode(presetName)); } void addValue(const std::string& name, const std::string& presetName) { - cfg->values.put(name, WidgetConfig::Node(presetName)); + cfg->values.put(name, WidgetNode(presetName)); } - void createConfig(const std::string& name) { - globalCfg->configs.put(name, {}); - cfg = &globalCfg->configs.get(name); + bool createConfig(const std::string& name) { + auto idx = mGlobalCfg.configs.presents(name); + if (idx) return false; + mGlobalCfg.configs.put(name, {}); + cfg = &mGlobalCfg.configs.get(name); + populateConfig(); + return true; } virtual void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) { @@ -57,10 +66,19 @@ namespace tp { } } + void addOperator(const std::string& name, WidgetConfig::WidgetCallback callback) { + cfg->mOperators.put(name, callback); + } + + Buffer& getShortcuts(const std::string& name) { return cfg->mShortcuts[name]; } + public: - GlobalGUIConfig* globalCfg = gGlobalGUIConfig; + static GlobalGUIConfig mGlobalCfg; WidgetConfig* cfg = nullptr; RectF mArea; bool mVisible = false; }; + + template + GlobalGUIConfig Widget::mGlobalCfg; } \ No newline at end of file diff --git a/Widgets/public/WidgetConfig.hpp b/Widgets/public/WidgetConfig.hpp index 3455c48..cbf37df 100644 --- a/Widgets/public/WidgetConfig.hpp +++ b/Widgets/public/WidgetConfig.hpp @@ -5,10 +5,29 @@ #include "Rect.hpp" #include "InputCodes.hpp" +#include "Buffer.hpp" namespace tp { + struct WidgetShortcut { + struct Condition { + std::string name; + std::string state; + }; + + WidgetShortcut() = default; + WidgetShortcut(const InitialierList&) {} + }; + + template struct WidgetConfig { + + struct WidgetCallback { + using CallbackType = void (*)(void* self, const Events&); + void* self; + CallbackType callback; + }; + struct Node { enum Type { NONE, VAL, COL, REF }; @@ -40,34 +59,40 @@ namespace tp { }; Map values; + Map mOperators; + Map> mShortcuts; }; + template struct GlobalGUIConfig { + using WidgetConfig = WidgetConfig; + using WidgetNode = WidgetConfig::Node; + GlobalGUIConfig() { configs.put("Presets", {}); auto& presets = configs.get("Presets"); - presets.values.put("FontSize", WidgetConfig::Node(15.f)); - presets.values.put("FontSizeDim", WidgetConfig::Node(12.f)); - presets.values.put("Rounding", WidgetConfig::Node(5.f)); - presets.values.put("Padding", WidgetConfig::Node(5.f)); - presets.values.put("HandleSize", WidgetConfig::Node(5.f)); + presets.values.put("FontSize", WidgetNode(15.f)); + presets.values.put("FontSizeDim", WidgetNode(12.f)); + presets.values.put("Rounding", WidgetNode(5.f)); + presets.values.put("Padding", WidgetNode(5.f)); + presets.values.put("HandleSize", WidgetNode(5.f)); - presets.values.put("Background", WidgetConfig::Node(RGBA{ 0.03f, 0.03f, 0.03f, 1.f })); - presets.values.put("Base", WidgetConfig::Node(RGBA{ 0.07f, 0.07f, 0.07f, 1.f })); - presets.values.put("Accent", WidgetConfig::Node(RGBA{ 0.13f, 0.13f, 0.13f, 1.f })); - presets.values.put("Interaction", WidgetConfig::Node(RGBA{ 0.33f, 0.33f, 0.3f, 1.f })); - presets.values.put("Action", WidgetConfig::Node(RGBA{ 0.44f, 0.44f, 0.4f, 1.f })); - presets.values.put("Front", WidgetConfig::Node(RGBA{ 1.f, 1.f, 1.f, 1.f })); - presets.values.put("FrontDim", WidgetConfig::Node(RGBA{ 0.7f, 0.7f, 0.7f, 1.f })); + presets.values.put("Background", WidgetNode(RGBA{ 0.03f, 0.03f, 0.03f, 1.f })); + presets.values.put("Base", WidgetNode(RGBA{ 0.07f, 0.07f, 0.07f, 1.f })); + presets.values.put("Accent", WidgetNode(RGBA{ 0.13f, 0.13f, 0.13f, 1.f })); + presets.values.put("Interaction", WidgetNode(RGBA{ 0.33f, 0.33f, 0.3f, 1.f })); + presets.values.put("Action", WidgetNode(RGBA{ 0.44f, 0.44f, 0.4f, 1.f })); + presets.values.put("Front", WidgetNode(RGBA{ 1.f, 1.f, 1.f, 1.f })); + presets.values.put("FrontDim", WidgetNode(RGBA{ 0.7f, 0.7f, 0.7f, 1.f })); + } + + ~GlobalGUIConfig() { configs.removeAll(); } + + void processShortcuts(const Events& events) { + // } Map configs; - - ~GlobalGUIConfig() { - configs.removeAll(); - } }; - - extern GlobalGUIConfig* gGlobalGUIConfig; } \ No newline at end of file From 86a41c1876a27473a3a28a5eef89d27677d48114 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Mon, 29 Apr 2024 12:37:39 +0300 Subject: [PATCH 5/6] tmp --- 3DEditor/CMakeLists.txt | 4 ++-- 3DEditor/applications/Entry.cpp | 3 ++- CMakeLists.txt | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/3DEditor/CMakeLists.txt b/3DEditor/CMakeLists.txt index 4ade195..e11e387 100644 --- a/3DEditor/CMakeLists.txt +++ b/3DEditor/CMakeLists.txt @@ -15,8 +15,8 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets Math Ra target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS}) ### -------------------------- Applications -------------------------- ### -add_executable(edit3d ./applications/Entry.cpp ./applications/SceneLoad.cpp) -target_link_libraries(edit3d ${PROJECT_NAME} Lua ImageIO) +add_executable(3DEditorApp ./applications/Entry.cpp ./applications/SceneLoad.cpp) +target_link_libraries(3DEditorApp ${PROJECT_NAME} Lua ImageIO) file(COPY "rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") file(COPY "rsc/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") diff --git a/3DEditor/applications/Entry.cpp b/3DEditor/applications/Entry.cpp index fdd62de..fb1e37e 100644 --- a/3DEditor/applications/Entry.cpp +++ b/3DEditor/applications/Entry.cpp @@ -15,7 +15,7 @@ public: // mGui = new EditorWidget(canvas, &geometry, renderResolution); mGui = new ShortcutsTest(); - + loadMeshes(geometry, "rsc/scene.obj"); geometry.mCamera.lookAtPoint({ 0, 0, 0 }, { 3, 3, 2 }, { 0, 0, 1 }); @@ -24,6 +24,7 @@ public: ~EditorGUI() override { delete mGui; } void processFrame(EventHandler* eventHandler) override { + auto rec = RectF({ 0, 0 }, mWindow->getSize()); mGui->proc(*eventHandler, rec, rec); } diff --git a/CMakeLists.txt b/CMakeLists.txt index 85f36c2..c211e67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,4 +24,4 @@ add_subdirectory(Widgets) add_subdirectory(LibraryViewer) add_subdirectory(RasterRender) add_subdirectory(Sketch3D) -add_subdirectory(3DEditor) \ No newline at end of file +add_subdirectory(3DEditor) From e2072d257fd75361eb2062a6c928fe0800afdab1 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Fri, 3 May 2024 15:09:26 +0300 Subject: [PATCH 6/6] tmp --- Objects/applications/GUIEntry.cpp | 6 +- Widgets/CMakeLists.txt | 11 +- Widgets/examples/{Entry.cpp => ChatGUI.cpp} | 8 +- .../examples/{ExampleGUI.hpp => ChatGUI.hpp} | 230 +++++++++++++----- Widgets/examples/SimpleGUI.cpp | 50 ++++ Widgets/public/ButtonWidget.hpp | 45 ++-- Widgets/public/LabelWidget.hpp | 35 +-- Widgets/public/ScrollableWidget.hpp | 119 +++++---- Widgets/public/SliderWidget.hpp | 49 ++-- Widgets/public/SplitViewWidget.hpp | 55 +++-- Widgets/public/TextInputWidget.hpp | 42 +++- Widgets/public/WidgetBase.hpp | 56 +---- Widgets/public/WidgetConfig.hpp | 98 -------- Widgets/public/WidgetManager.hpp | 131 ++++++++++ 14 files changed, 594 insertions(+), 341 deletions(-) rename Widgets/examples/{Entry.cpp => ChatGUI.cpp} (74%) rename Widgets/examples/{ExampleGUI.hpp => ChatGUI.hpp} (51%) create mode 100644 Widgets/examples/SimpleGUI.cpp delete mode 100644 Widgets/public/WidgetConfig.hpp create mode 100644 Widgets/public/WidgetManager.hpp diff --git a/Objects/applications/GUIEntry.cpp b/Objects/applications/GUIEntry.cpp index 5b0c4e8..b5c518e 100644 --- a/Objects/applications/GUIEntry.cpp +++ b/Objects/applications/GUIEntry.cpp @@ -6,9 +6,9 @@ using namespace tp; using namespace obj; -class ExampleGUI : public Application { +class SimpleGUI : public Application { public: - ExampleGUI() { gui.cd(objects_api::create(), "root"); } + SimpleGUI() { gui.cd(objects_api::create(), "root"); } void processFrame(EventHandler* eventHandler) override {} @@ -28,7 +28,7 @@ int main() { if (module.initialize()) { { - ExampleGUI gui; + SimpleGUI gui; gui.run(); } module.deinitialize(); diff --git a/Widgets/CMakeLists.txt b/Widgets/CMakeLists.txt index 5047dae..dc1b591 100644 --- a/Widgets/CMakeLists.txt +++ b/Widgets/CMakeLists.txt @@ -10,7 +10,12 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Math Graphics Imgui) ### -------------------------- Applications -------------------------- ### -add_executable(ExampleGui examples/Entry.cpp) -target_link_libraries(ExampleGui ${PROJECT_NAME} ${GLEW_LIB}) -target_include_directories(ExampleGui PUBLIC ../Externals/glfw/include ${GLEW_INCLUDE_DIR}) +add_executable(SimpleGui examples/SimpleGUI.cpp) +target_link_libraries(SimpleGui ${PROJECT_NAME} ${GLEW_LIB}) +target_include_directories(SimpleGui PUBLIC ../Externals/glfw/include ${GLEW_INCLUDE_DIR}) + +add_executable(ChatGui examples/ChatGUI.cpp) +target_link_libraries(ChatGui ${PROJECT_NAME} ${GLEW_LIB}) +target_include_directories(ChatGui PUBLIC ../Externals/glfw/include ${GLEW_INCLUDE_DIR}) + file(COPY "examples/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") \ No newline at end of file diff --git a/Widgets/examples/Entry.cpp b/Widgets/examples/ChatGUI.cpp similarity index 74% rename from Widgets/examples/Entry.cpp rename to Widgets/examples/ChatGUI.cpp index 17a643b..580b979 100644 --- a/Widgets/examples/Entry.cpp +++ b/Widgets/examples/ChatGUI.cpp @@ -1,5 +1,5 @@ -#include "ExampleGUI.hpp" +#include "ChatGUI.hpp" #include "GraphicApplication.hpp" @@ -7,16 +7,20 @@ using namespace tp; class ExampleGUI : public Application { public: - ExampleGUI() = default; + ExampleGUI() { mGui.setupConfig(mWidgetManager); } void processFrame(EventHandler* eventHandler) override { auto rec = RectF({ 0, 0 }, mWindow->getSize()); + + mGui.updateConfigCache(mWidgetManager); + mGui.proc(*eventHandler, rec, rec); } void drawFrame(Canvas* canvas) override { mGui.draw(*canvas); } private: + WidgetManager mWidgetManager; ComplexWidget mGui; }; diff --git a/Widgets/examples/ExampleGUI.hpp b/Widgets/examples/ChatGUI.hpp similarity index 51% rename from Widgets/examples/ExampleGUI.hpp rename to Widgets/examples/ChatGUI.hpp index 474151e..805cd4c 100644 --- a/Widgets/examples/ExampleGUI.hpp +++ b/Widgets/examples/ChatGUI.hpp @@ -7,15 +7,7 @@ namespace tp { template class UserWidget : public Widget { public: - UserWidget() { - this->createConfig("User"); - this->addColor("Base", "Base"); - this->addValue("Size", "FontSize"); - this->addValue("Padding", "Padding"); - this->addColor("ColUser", "Front"); - this->addColor("Accent", "Accent"); - this->addValue("Rounding", "Rounding"); - } + UserWidget() { this->mId = "UserWidget"; } void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { this->mArea = aArea; @@ -28,34 +20,48 @@ namespace tp { void draw(Canvas& canvas) override { if (!this->mVisible) return; - if (mIsHover) canvas.rect(this->mArea, this->getColor("Accent"), this->getValue("Rounding")); - else canvas.rect(this->mArea, this->getColor("Base"), this->getValue("Rounding")); + if (mIsHover) canvas.rect(this->mArea, mAccentColor, mRounding); + else canvas.rect(this->mArea, mBaseColor, mRounding); - const auto padding = this->getValue("Padding"); - const auto size = this->getValue("Size"); - const auto colUser = this->getColor("ColUser"); + canvas.text(mUser.c_str(), this->mArea, mFontSize, Canvas::CC, mPadding, mUserColor); + } - canvas.text(mUser.c_str(), this->mArea, size, Canvas::CC, padding, colUser); + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Base", "Base"); + wm.addReference(this->mId, "Size", "FontSize"); + wm.addReference(this->mId, "Padding", "Padding"); + wm.addReference(this->mId, "ColUser", "Front"); + wm.addReference(this->mId, "Accent", "Accent"); + wm.addReference(this->mId, "Rounding", "Rounding"); + } + + void updateConfigCache(const WidgetManager& wm) override { + mBaseColor = wm.getColor(this->mId, "Base"); + mFontSize = wm.getNumber(this->mId, "Size"); + mPadding = wm.getNumber(this->mId, "Padding"); + mUserColor = wm.getColor(this->mId, "ColUser"); + mAccentColor = wm.getColor(this->mId, "Accent"); + mRounding = wm.getNumber(this->mId, "Rounding"); } public: std::string mUser = "UserName"; bool mIsHover = false; + + RGBA mBaseColor; + RGBA mUserColor; + RGBA mAccentColor; + halnf mPadding = 0; + halnf mFontSize = 0; + halnf mRounding = 0; }; template class MessageWidget : public Widget { public: - MessageWidget() { - this->createConfig("Message"); - this->addColor("Base", "Base"); - this->addValue("Size", "FontSize"); - this->addValue("SizeUser", "FontSizeDim"); - this->addValue("Padding", "Padding"); - this->addColor("ColUser", "Front"); - this->addColor("Col", "FrontDim"); - this->addValue("Rounding", "Rounding"); - } + MessageWidget() { this->mId = "MessageWidget"; } void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { this->mArea = aArea; @@ -67,14 +73,7 @@ namespace tp { void draw(Canvas& canvas) override { if (!this->mVisible) return; - - if (mIsHover) canvas.rect(this->mArea, this->getColor("Base"), this->getValue("Rounding")); - - const auto padding = this->getValue("Padding"); - const auto size = this->getValue("Size"); - const auto sizeUser = this->getValue("SizeUser"); - const auto col = this->getColor("Col"); - const auto colUser = this->getColor("ColUser"); + if (mIsHover) canvas.rect(this->mArea, mBaseColor, mRounding); auto userName = this->mArea; userName.w = 25; @@ -83,22 +82,51 @@ namespace tp { content.y = userName.y + userName.w; content.w = this->mArea.w - userName.w; - canvas.text(mContent.c_str(), content, size, Canvas::LC, padding, col); - canvas.text(mUser.c_str(), userName, sizeUser, Canvas::LC, padding, colUser); + canvas.text(mContent.c_str(), content, mFontSize, Canvas::LC, mPadding, mUserColorDim); + canvas.text(mUser.c_str(), userName, mFontSizeDim, Canvas::LC, mPadding, mUserColor); + } + + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Base", "Base"); + wm.addReference(this->mId, "Size", "FontSize"); + wm.addReference(this->mId, "SizeUser", "FontSizeDim"); + wm.addReference(this->mId, "Padding", "Padding"); + wm.addReference(this->mId, "UserColor", "Front"); + wm.addReference(this->mId, "UserColorDim", "FrontDim"); + wm.addReference(this->mId, "Rounding", "Rounding"); + } + + void updateConfigCache(const WidgetManager& wm) override { + mBaseColor = wm.getColor(this->mId, "Base"); + mFontSize = wm.getNumber(this->mId, "Size"); + mFontSizeDim = wm.getNumber(this->mId, "SizeUser"); + mPadding = wm.getNumber(this->mId, "Padding"); + mUserColor = wm.getColor(this->mId, "UserColor"); + mUserColorDim = wm.getColor(this->mId, "UserColorDim"); + mRounding = wm.getNumber(this->mId, "Rounding"); } public: std::string mContent = "Message Content"; std::string mUser = "UserName"; bool mIsHover = false; + + RGBA mBaseColor; + RGBA mUserColor; + RGBA mUserColorDim; + halnf mPadding = 0; + halnf mFontSize = 0; + halnf mFontSizeDim = 0; + halnf mRounding = 0; }; template class LoginWidget : public Widget { public: explicit LoginWidget() { - this->createConfig("Login"); - this->addColor("Back", "Background"); + this->mId = "Login"; + mPass.mId = "pass"; mUser.mId = "user"; mButton.mLabel.mLabel = "Login"; @@ -120,26 +148,45 @@ namespace tp { } void draw(Canvas& canvas) override { - canvas.rect(this->mArea, this->getColor("Back")); + canvas.rect(this->mArea, mBGColor); mButton.draw(canvas); mUser.draw(canvas); mPass.draw(canvas); } + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Back", "Base"); + + mUser.setupConfig(wm); + mPass.setupConfig(wm); + mButton.setupConfig(wm); + } + + void updateConfigCache(const WidgetManager& wm) override { + mBGColor = wm.getColor(this->mId, "Back"); + + mUser.updateConfigCache(wm); + mPass.updateConfigCache(wm); + mButton.updateConfigCache(wm); + } + public: TextInputWidget mUser; TextInputWidget mPass; ButtonWidget mButton; bool mLogged = false; + + RGBA mBGColor; }; template class ActiveChatWidget : public Widget { public: ActiveChatWidget() { - this->createConfig("ActiveChat"); - this->addColor("Back", "Background"); - this->addValue("Padding", "Padding"); + this->mId = "ActiveWidget"; + mSend.mLabel.mLabel = "Send"; mMessage.mId = "Message"; } @@ -152,16 +199,16 @@ namespace tp { auto input = this->mArea; input.y = history.w + 10; - input.w = 40 - this->getValue("Padding"); - input.x += this->getValue("Padding"); - input.z -= this->getValue("Padding"); + input.w = 40 - mPadding; + input.x += mPadding; + input.z -= mPadding; auto inputMessage = input; inputMessage.z -= 100; auto inputSend = input; - inputSend.x = inputMessage.x + inputMessage.z + this->getValue("Padding"); - inputSend.z = 100 - this->getValue("Padding") * 2; + inputSend.x = inputMessage.x + inputMessage.z + mPadding; + inputSend.z = 100 - mPadding * 2; mSend.proc(events, this->mArea, inputSend); mMessage.proc(events, this->mArea, inputMessage); @@ -174,26 +221,53 @@ namespace tp { } void draw(Canvas& canvas) override { - canvas.rect(this->mArea, this->getColor("Back")); + canvas.rect(this->mArea, mBGColor); mHistoryView.draw(canvas); mMessage.draw(canvas); mSend.draw(canvas); } + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + + wm.addReference(this->mId, "Back", "Background"); + wm.addReference(this->mId, "Padding", "Padding"); + + mHistoryView.setupConfig(wm); + mMessage.setupConfig(wm); + mSend.setupConfig(wm); + + MessageWidget().setupConfig(wm); + } + + void updateConfigCache(const WidgetManager& wm) override { + mBGColor = wm.getColor(this->mId, "Back"); + mPadding = wm.getNumber(this->mId, "Padding"); + + mHistoryView.updateConfigCache(wm); + mMessage.updateConfigCache(wm); + mSend.updateConfigCache(wm); + + for (auto message : mMessages) { + message->updateConfigCache(wm); + } + } + public: Buffer> mMessages; ScrollableWindow mHistoryView; TextInputWidget mMessage; ButtonWidget mSend; + + RGBA mBGColor; + halnf mPadding = 0; }; template class ChattingWidget : public Widget { public: ChattingWidget() { - this->createConfig("Chatting"); - this->addColor("Back", "Background"); - this->addValue("Padding", "Padding"); + this->mId = "Chatting"; // todo : fetch code mUsers.append(UserWidget()); @@ -225,34 +299,54 @@ namespace tp { this->mArea = aArea; mSplitView.proc(events, aArea, aArea); - - const auto padding = this->getValue("Padding"); mSideView.proc(events, this->mArea, mSplitView.getSecond()); - mActive.proc(events, aArea, mSplitView.getFirst()); } void draw(Canvas& canvas) override { - canvas.rect(this->mArea, this->getColor("Back")); + canvas.rect(this->mArea, mBGColor); mSplitView.draw(canvas); mSideView.draw(canvas); mActive.draw(canvas); } + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + + wm.addReference(this->mId, "Back", "Background"); + + mSideView.setupConfig(wm); + mActive.setupConfig(wm); + mSplitView.setupConfig(wm); + + UserWidget().setupConfig(wm); + } + + void updateConfigCache(const WidgetManager& wm) override { + mBGColor = wm.getColor(this->mId, "Back"); + + mSideView.updateConfigCache(wm); + mActive.updateConfigCache(wm); + mSplitView.updateConfigCache(wm); + + for (auto user : mUsers) { + user->updateConfigCache(wm); + } + } + public: Buffer> mUsers; ScrollableWindow mSideView; ActiveChatWidget mActive; SplitView mSplitView; + + RGBA mBGColor; }; template class ComplexWidget : public Widget { public: - ComplexWidget() { - this->createConfig("chat"); - this->addColor("Back", "Background"); - } + ComplexWidget() { this->mId = "Chat"; } void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { this->mArea = aArea; @@ -268,14 +362,32 @@ namespace tp { } void draw(Canvas& canvas) override { - canvas.rect(this->mArea, this->getColor("Back")); + canvas.rect(this->mArea, mBGColor); if (mLogged) mChatting.draw(canvas); else mLogin.draw(canvas); } + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + + wm.addReference(this->mId, "Back", "Background"); + + mLogin.setupConfig(wm); + mChatting.setupConfig(wm); + } + + void updateConfigCache(const WidgetManager& wm) override { + mBGColor = wm.getColor(this->mId, "Back"); + + mLogin.updateConfigCache(wm); + mChatting.updateConfigCache(wm); + } + private: bool mLogged = false; LoginWidget mLogin; ChattingWidget mChatting; + + RGBA mBGColor; }; } \ No newline at end of file diff --git a/Widgets/examples/SimpleGUI.cpp b/Widgets/examples/SimpleGUI.cpp new file mode 100644 index 0000000..fd4ec5e --- /dev/null +++ b/Widgets/examples/SimpleGUI.cpp @@ -0,0 +1,50 @@ + +#include "ChatGUI.hpp" + +#include "GraphicApplication.hpp" + +using namespace tp; + +class SimpleGUI : public Application { +public: + SimpleGUI() { + mGui.setupConfig(mWidgetManager); + + mButton.setupConfig(mWidgetManager); + mSlider.setupConfig(mWidgetManager); + mLabel.setupConfig(mWidgetManager); + + mGui.mContents.append(&mButton); + mGui.mContents.append(&mSlider); + mGui.mContents.append(&mLabel); + } + + void processFrame(EventHandler* eventHandler) override { + + mGui.updateConfigCache(mWidgetManager); + + mSlider.updateConfigCache(mWidgetManager); + mLabel.updateConfigCache(mWidgetManager); + mButton.updateConfigCache(mWidgetManager); + + const auto rec = RectF({ 0, 0 }, mWindow->getSize()); + mGui.proc(*eventHandler, rec, rec); + } + + void drawFrame(Canvas* canvas) override { mGui.draw(*canvas); } + +private: + WidgetManager mWidgetManager; + ScrollableWindow mGui; + + ButtonWidget mButton; + LabelWidget mLabel; + SliderWidget mSlider; +}; + +int main() { + { + SimpleGUI gui; + gui.run(); + } +} diff --git a/Widgets/public/ButtonWidget.hpp b/Widgets/public/ButtonWidget.hpp index 8df41bc..4eb748c 100644 --- a/Widgets/public/ButtonWidget.hpp +++ b/Widgets/public/ButtonWidget.hpp @@ -9,22 +9,13 @@ namespace tp { public: ButtonWidget() { this->mArea = { 0, 0, 100, 100 }; - this->createConfig("Button"); - this->addColor("Pressed", "Action"); - this->addColor("Hovered", "Interaction"); - this->addColor("Default", "Accent"); - this->addValue("Rounding", "Rounding"); + this->mId = "Button"; } ButtonWidget(const std::string& label, const tp::RectF& aArea) { + this->mId = "Button"; this->mArea = aArea; this->mLabel.mLabel = label; - - this->createConfig("Button"); - this->addColor("Pressed", "Action"); - this->addColor("Hovered", "Interaction"); - this->addColor("Default", "Accent"); - this->addValue("Rounding", "Rounding"); } void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { @@ -60,19 +51,45 @@ namespace tp { if (!this->mVisible) return; if (mIsPressed) { - canvas.rect(this->mArea, this->getColor("Pressed"), this->getValue("Rounding")); + canvas.rect(this->mArea, pressedColor, rounding); } else if (mIsHover) { - canvas.rect(this->mArea, this->getColor("Hovered"), this->getValue("Rounding")); + canvas.rect(this->mArea, hoveredColor, rounding); } else { - canvas.rect(this->mArea, this->getColor("Default"), this->getValue("Rounding")); + canvas.rect(this->mArea, accentColor, rounding); } mLabel.draw(canvas); } + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Pressed", "Action"); + wm.addReference(this->mId, "Hovered", "Interaction"); + wm.addReference(this->mId, "Default", "Accent"); + wm.addReference(this->mId, "Rounding", "Rounding"); + + mLabel.setupConfig(wm); + } + + void updateConfigCache(const WidgetManager& wm) override { + pressedColor = wm.getColor(this->mId, "Pressed"); + hoveredColor = wm.getColor(this->mId, "Hovered"); + accentColor = wm.getColor(this->mId, "Default"); + rounding = wm.getNumber(this->mId, "Rounding"); + + mLabel.updateConfigCache(wm); + } + public: LabelWidget mLabel; + bool mIsHover = false; bool mIsPressed = false; bool mIsReleased = false; + + RGBA pressedColor; + RGBA hoveredColor; + RGBA accentColor; + halnf rounding = 0; }; } \ No newline at end of file diff --git a/Widgets/public/LabelWidget.hpp b/Widgets/public/LabelWidget.hpp index 945436e..5fba4d1 100644 --- a/Widgets/public/LabelWidget.hpp +++ b/Widgets/public/LabelWidget.hpp @@ -6,14 +6,9 @@ namespace tp { template class LabelWidget : public Widget { public: - LabelWidget() { - this->createConfig("Label"); - this->addValue("Size", "FontSize"); - this->addValue("Padding", "Padding"); - this->addColor("Default", "Front"); - } + LabelWidget() { this->mId = "Label"; } - void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { + void proc(const Events&, const tp::RectF& areaParent, const tp::RectF& aArea) override { this->mArea = aArea; this->mVisible = areaParent.isOverlap(aArea); if (!this->mVisible) return; @@ -21,18 +16,28 @@ namespace tp { void draw(Canvas& canvas) override { if (!this->mVisible) return; + canvas.text(mLabel.c_str(), this->mArea, fontSize, Canvas::CC, padding, fontColor); + } - canvas.text( - mLabel.c_str(), - this->mArea, - this->getValue("Size"), - Canvas::CC, - this->getValue("Padding"), - this->getColor("Default") - ); + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Size", "FontSize"); + wm.addReference(this->mId, "Padding", "Padding"); + wm.addReference(this->mId, "Default", "Front"); + } + + void updateConfigCache(const WidgetManager& wm) override { + fontSize = wm.getNumber(this->mId, "Size"); + padding = wm.getNumber(this->mId, "Padding"); + fontColor = wm.getColor(this->mId, "Default"); } public: std::string mLabel = "Label"; + + halnf fontSize = 10; + halnf padding = 0; + RGBA fontColor = { 1, 1, 1, 1 }; }; } \ No newline at end of file diff --git a/Widgets/public/ScrollableWidget.hpp b/Widgets/public/ScrollableWidget.hpp index d955825..da93640 100644 --- a/Widgets/public/ScrollableWidget.hpp +++ b/Widgets/public/ScrollableWidget.hpp @@ -8,17 +8,7 @@ namespace tp { template class ScrollBarWidget : public Widget { public: - ScrollBarWidget() { - this->createConfig("ScrollBar"); - this->addColor("Default", "Base"); - this->addColor("Handle", "Accent"); - this->addColor("Hovered", "Interaction"); - this->addColor("Scrolling", "Action"); - this->addValue("Padding", "Padding"); - this->addValue("HandleSize", 20.f); - this->addValue("MinSize", 20.f); - this->addValue("Rounding", "Rounding"); - } + ScrollBarWidget() { this->mId = "ScrollBar"; } // takes whole area void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { @@ -79,28 +69,22 @@ namespace tp { if (mSizeFraction > 1.f) return; // if (!areaParent.isOverlap(getHandle())) return; - tp::RGBA col = this->getColor("Handle"); + tp::RGBA col = mHandleColor; if (mIsScrolling) { - col = this->getColor("Scrolling"); + col = mScrollingColor; } else if (mHovered) { - col = this->getColor("Hovered"); + col = mHoveredColor; } - canvas.rect(area, this->getColor("Default"), this->getValue("Rounding")); + canvas.rect(area, mDefaultColor, mRounding); - canvas.rect(getHandleHandle(), col, this->getValue("Rounding")); + canvas.rect(getHandleHandle(), col, mRounding); } RectF getHandleHandle() const { - auto minSize = this->getValue("MinSize"); - if (mIsScrolling) { - minSize = this->getValue("MinSize") * 2; - } else if (mHovered) { - minSize = this->getValue("MinSize") * 2; - } auto area = getHandle(); - auto sliderSize = tp::clamp(area.w * mSizeFraction, minSize, area.w); + auto sliderSize = tp::clamp(area.w * mSizeFraction, mMinSize * 2, area.w); auto diffSize = sliderSize - area.w * mSizeFraction; return { area.x, area.y + (area.w - diffSize) * mPositionFraction, area.z, sliderSize }; } @@ -109,14 +93,39 @@ namespace tp { if (mSizeFraction > 1.f) { return this->mArea; } - return { this->mArea.x, this->mArea.y, this->mArea.z - this->getValue("HandleSize"), this->mArea.w }; + return { this->mArea.x, this->mArea.y, this->mArea.z - mHandleSize, this->mArea.w }; } RectF getHandle() const { - return { this->mArea.x + this->mArea.z - this->getValue("HandleSize") + this->getValue("Padding"), - this->mArea.y + this->getValue("Padding"), - this->getValue("HandleSize") - this->getValue("Padding") * 2, - this->mArea.w - this->getValue("Padding") * 2 }; + return { this->mArea.x + this->mArea.z - mHandleSize + mPadding, + this->mArea.y + mPadding, + mHandleSize - mPadding * 2, + this->mArea.w - mPadding * 2 }; + } + + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + + wm.addReference(this->mId, "Default", "Base"); + wm.addReference(this->mId, "Handle", "Accent"); + wm.addReference(this->mId, "Hovered", "Interaction"); + wm.addReference(this->mId, "Scrolling", "Action"); + wm.addReference(this->mId, "Padding", "Padding"); + wm.addNumber(this->mId, "HandleSize", 20.f); + wm.addNumber(this->mId, "MinSize", 20.f); + wm.addReference(this->mId, "Rounding", "Rounding"); + } + + void updateConfigCache(const WidgetManager& wm) override { + mDefaultColor = wm.getColor(this->mId, "Default"); + mHandleColor = wm.getColor(this->mId, "Handle"); + mHoveredColor = wm.getColor(this->mId, "Hovered"); + mScrollingColor = wm.getColor(this->mId, "Scrolling"); + mPadding = wm.getNumber(this->mId, "Padding"); + mHandleSize = wm.getNumber(this->mId, "HandleSize"); + mMinSize = wm.getNumber(this->mId, "MinSize"); + mRounding = wm.getNumber(this->mId, "Rounding"); } public: @@ -126,16 +135,21 @@ namespace tp { halnf mSizeFraction = 1.f; halnf mPositionFraction = 0.f; bool mHovered = false; + + RGBA mDefaultColor; + RGBA mHandleColor; + RGBA mHoveredColor; + RGBA mScrollingColor; + halnf mPadding = 0; + halnf mHandleSize = 10; + halnf mMinSize = 10; + halnf mRounding = 10; }; template class ScrollableWindow : public Widget { public: - ScrollableWindow() { - this->createConfig("ScrollableWindow"); - this->addColor("Default", "Base"); - this->addValue("Padding", "Padding"); - } + ScrollableWindow() { this->mId = "ScrollableWindow"; } ~ScrollableWindow() = default; @@ -148,7 +162,7 @@ namespace tp { updateContents(); updateContentSize(); - const auto padding = this->getValue("Padding"); + const auto padding = mPadding; mScroller.mSizeFraction = this->mArea.w / mContentSize; mScroller.proc(events, this->mArea, this->mArea); @@ -180,16 +194,37 @@ namespace tp { canvas.popClamp(); } + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + + wm.addReference(this->mId, "Default", "Base"); + wm.addReference(this->mId, "Padding", "Padding"); + wm.addReference(this->mId, "Rounding", "Rounding"); + + mScroller.setupConfig(wm); + } + + void updateConfigCache(const WidgetManager& wm) override { + mDefaultColor = wm.getColor(this->mId, "Default"); + mPadding = wm.getNumber(this->mId, "Padding"); + + mScroller.updateConfigCache(wm); + + for (auto item : mContents) { + item->updateConfigCache(wm); + } + } + private: void updateContents() { if (mContents.size()) { - const auto padding = this->getValue("Padding"); - const halnf offset = mContents.first()->mArea.y + padding; + const halnf offset = mContents.first()->mArea.y + mPadding; halnf start = 0; for (auto widget : mContents) { widget->mArea.y = start; - start += widget->mArea.w + padding; + start += widget->mArea.w + mPadding; } for (auto widget : mContents) { @@ -201,17 +236,15 @@ namespace tp { void updateContentSize() { mContentSize = 0; if (mContents.size()) { - const auto padding = this->getValue("Padding"); mContentSize = mContents.last()->mArea.y - mContents.first()->mArea.y; mContentSize += mContents.last()->mArea.w; - mContentSize += 2 * padding; + mContentSize += 2 * mPadding; } } void setOffset(const halnf offset) { if (!mContents.size()) return; - const auto padding = this->getValue("Padding"); - auto newOffset = offset - mContents.first()->mArea.y + padding; + auto newOffset = offset - mContents.first()->mArea.y + mPadding; for (auto widget : mContents) { widget->mArea.y += newOffset; } @@ -219,7 +252,11 @@ namespace tp { public: halnf mContentSize = 0; + Buffer*> mContents; ScrollBarWidget mScroller; + + RGBA mDefaultColor; + halnf mPadding = 0; }; } \ No newline at end of file diff --git a/Widgets/public/SliderWidget.hpp b/Widgets/public/SliderWidget.hpp index 098d44e..70aa657 100644 --- a/Widgets/public/SliderWidget.hpp +++ b/Widgets/public/SliderWidget.hpp @@ -7,17 +7,7 @@ namespace tp { template class SliderWidget : public Widget { public: - SliderWidget() { - this->createConfig("SliderWidget"); - this->addColor("Default", "Base"); - this->addColor("Handle", "Accent"); - this->addColor("Hovered", "Interaction"); - this->addColor("Scrolling", "Action"); - this->addValue("Padding", "Padding"); - this->addValue("HandleSize", 20.f); - this->addValue("MinSize", 20.f); - this->addValue("Rounding", "Rounding"); - } + SliderWidget() { this->mId = "SliderWidget"; } void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { this->mArea = aArea; @@ -31,7 +21,6 @@ namespace tp { } if (mIsSliding) { - const auto handleSize = this->getValue("HandleSize"); mFactor = (events.getPointer().x - this->mArea.x - handleSize / 2.f) / (this->mArea.z - handleSize); } @@ -40,26 +29,47 @@ namespace tp { void draw(Canvas& canvas) override { if (!this->mVisible) return; - canvas.rect(this->mArea, this->getColor("Default"), this->getValue("Rounding")); - canvas.rect(getHandle(), this->getColor("Handle"), this->getValue("Rounding")); + canvas.rect(this->mArea, defaultColor, rounding); + canvas.rect(getHandle(), handleColor, rounding); } RectF getHandle() const { - const auto handle = this->getValue("HandleSize"); - const auto halfHandle = handle / 2.f; - const auto left = this->mArea.x + (this->mArea.z - handle) * mFactor; - return { left, this->mArea.y, handle, this->mArea.w }; + const auto halfHandle = handleSize / 2.f; + const auto left = this->mArea.x + (this->mArea.z - handleSize) * mFactor; + return { left, this->mArea.y, handleSize, this->mArea.w }; + } + + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Default", "Base"); + wm.addReference(this->mId, "Handle", "Accent"); + wm.addNumber(this->mId, "HandleSize", 20.f); + wm.addReference(this->mId, "Rounding", "Rounding"); + } + + void updateConfigCache(const WidgetManager& wm) override { + defaultColor = wm.getColor(this->mId, "Default"); + handleColor = wm.getColor(this->mId, "Handle"); + handleSize = wm.getNumber(this->mId, "HandleSize"); + rounding = wm.getNumber(this->mId, "Rounding"); } public: halnf mFactor = 0.f; bool mIsSliding = false; + + RGBA defaultColor; + RGBA handleColor; + halnf handleSize = 0; + halnf rounding = 0; }; template class NamedSliderWidget : public Widget { public: - NamedSliderWidget(const char* name = "Value") { + explicit NamedSliderWidget(const char* name = "Value") { + this->mId = "NamedSliderWidget"; mLabel.mLabel = name; this->mArea = { 0, 0, 100, 30 }; } @@ -89,6 +99,7 @@ namespace tp { mLabel.draw(canvas); } + public: public: SliderWidget mSlider; LabelWidget mLabel; diff --git a/Widgets/public/SplitViewWidget.hpp b/Widgets/public/SplitViewWidget.hpp index 2ee1ad8..6731efa 100644 --- a/Widgets/public/SplitViewWidget.hpp +++ b/Widgets/public/SplitViewWidget.hpp @@ -6,14 +6,7 @@ namespace tp { template class SplitView : public Widget { public: - SplitView() { - this->createConfig("SplitView"); - this->addColor("Handle", "Accent"); - this->addColor("Hovered", "Interaction"); - this->addColor("Resizing", "Action"); - this->addValue("Min", 200.f); - this->addValue("HandleSize", 7.f); - } + SplitView() { this->mId = "SplitView"; } void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { this->mArea = aArea; @@ -38,9 +31,9 @@ namespace tp { mFactor += diff / this->mArea.z; } - mFactor = tp::clamp(mFactor, this->getValue("Min") / this->mArea.z, 1 - this->getValue("Min") / this->mArea.z); + mFactor = tp::clamp(mFactor, mMinSize / this->mArea.z, 1 - mMinSize / this->mArea.z); - if (this->getValue("Min") * 2.f > this->mArea.z) { + if (mMinSize * 2.f > this->mArea.z) { mFactor = 0.5f; } } @@ -49,34 +42,52 @@ namespace tp { void draw(Canvas& canvas) override { if (!this->mVisible) return; - if (mResizeInProcess) canvas.rect(getHandle(), this->getColor("Resizing")); - else if (mIsHover) canvas.rect(getHandle(), this->getColor("Hovered")); - else canvas.rect(getHandle(), this->getColor("Handle")); + if (mResizeInProcess) canvas.rect(getHandle(), mResizingColor); + else if (mIsHover) canvas.rect(getHandle(), mHoveredColor); + else canvas.rect(getHandle(), mHandleColor); } RectF getFirst() const { - return { - this->mArea.x, this->mArea.y, mFactor * this->mArea.z - this->getValue("HandleSize") / 2.f, this->mArea.w - }; + return { this->mArea.x, this->mArea.y, mFactor * this->mArea.z - mHandleSize / 2.f, this->mArea.w }; } RectF getSecond() const { - return { this->mArea.x + mFactor * this->mArea.z + this->getValue("HandleSize") / 2.f, + return { this->mArea.x + mFactor * this->mArea.z + mHandleSize / 2.f, this->mArea.y, - (1.f - mFactor) * this->mArea.z - this->getValue("HandleSize") / 2.f, + (1.f - mFactor) * this->mArea.z - mHandleSize / 2.f, this->mArea.w }; } RectF getHandle() const { - return { this->mArea.x + mFactor * this->mArea.z - this->getValue("HandleSize") / 2.f, - this->mArea.y, - this->getValue("HandleSize"), - this->mArea.w }; + return { this->mArea.x + mFactor * this->mArea.z - mHandleSize / 2.f, this->mArea.y, mHandleSize, this->mArea.w }; + } + + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Handle", "Accent"); + wm.addReference(this->mId, "Hovered", "Interaction"); + wm.addReference(this->mId, "Resizing", "Action"); + wm.addNumber(this->mId, "Min", 200.f); + wm.addNumber(this->mId, "HandleSize", 7.f); + } + + void updateConfigCache(const WidgetManager& wm) override { + mHandleColor = wm.getColor(this->mId, "Handle"); + mHoveredColor = wm.getColor(this->mId, "Hovered"); + mResizingColor = wm.getColor(this->mId, "Resizing"); + mMinSize = wm.getNumber(this->mId, "Min"); + mHandleSize = wm.getNumber(this->mId, "HandleSize"); } public: halnf mFactor = 0.7f; bool mResizeInProcess = false; bool mIsHover = false; + + RGBA mHandleColor; + RGBA mHoveredColor; + RGBA mResizingColor; + halnf mMinSize = 0; + halnf mHandleSize = 0; }; } \ No newline at end of file diff --git a/Widgets/public/TextInputWidget.hpp b/Widgets/public/TextInputWidget.hpp index 11089cb..2dfd40b 100644 --- a/Widgets/public/TextInputWidget.hpp +++ b/Widgets/public/TextInputWidget.hpp @@ -9,14 +9,7 @@ namespace tp { template class TextInputWidget : public Widget { public: - TextInputWidget() { - this->createConfig("TextInput"); - this->addColor("Accent", "Accent"); - this->addColor("Base", "Base"); - this->addValue("Rounding", "Rounding"); - this->addColor("Hovered", "Interaction"); - this->addValue("Padding", "Padding"); - } + TextInputWidget() { this->mId = "TextInput"; } void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { this->mArea = aArea; @@ -29,8 +22,8 @@ namespace tp { nChanged = false; - const auto col = this->getColor("Accent"); - const auto colSel = this->getColor("Hovered"); + const auto col = mAccentColor; + const auto colSel = mHoveredColor; ImGui::GetStyle().Colors[ImGuiCol_FrameBg] = { col.r, col.g, col.b, col.a }; ImGui::GetStyle().Colors[ImGuiCol_TextSelectedBg] = { colSel.r, colSel.g, colSel.b, colSel.a }; @@ -38,8 +31,8 @@ namespace tp { ImGui::SetNextWindowPos({ this->mArea.x, this->mArea.y }); ImGui::SetNextWindowSize({ this->mArea.z, this->mArea.w }); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0, 0 }); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, this->getValue("Rounding") * 1.5f); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { this->getValue("Padding"), this->getValue("Padding") }); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, mRounding * 1.5f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { mPadding, mPadding }); // ImGui::PushID((int) alni(this)); ImGui::Begin( @@ -65,11 +58,36 @@ namespace tp { ImGui::PopStyleVar(3); } + public: + void setupConfig(WidgetManager& wm) { + if (!wm.createWidgetConfig(this->mId)) return; + wm.addReference(this->mId, "Accent", "Accent"); + wm.addReference(this->mId, "Base", "Base"); + wm.addReference(this->mId, "Rounding", "Rounding"); + wm.addReference(this->mId, "Hovered", "Accent"); + wm.addReference(this->mId, "Padding", "Padding"); + } + + void updateConfigCache(const WidgetManager& wm) override { + mAccentColor = wm.getColor(this->mId, "Accent"); + mBaseColor = wm.getColor(this->mId, "Base"); + mHoveredColor = wm.getColor(this->mId, "Hovered"); + mRounding = wm.getNumber(this->mId, "Rounding"); + mPadding = wm.getNumber(this->mId, "Padding"); + } + + public: enum { mMaxBufferSize = 512 }; char mBuff[mMaxBufferSize] = ""; bool nChanged = false; std::string mValue; std::string mId = "id"; bool mMultiline = false; + + RGBA mAccentColor; + RGBA mHoveredColor; + RGBA mBaseColor; + halnf mRounding = 0; + halnf mPadding = 0; }; } \ No newline at end of file diff --git a/Widgets/public/WidgetBase.hpp b/Widgets/public/WidgetBase.hpp index b9bf46c..8eae05f 100644 --- a/Widgets/public/WidgetBase.hpp +++ b/Widgets/public/WidgetBase.hpp @@ -1,56 +1,14 @@ -; #pragma once -#include "WidgetConfig.hpp" +#include "WidgetManager.hpp" namespace tp { template class Widget { public: - using WidgetConfig = WidgetConfig; - using WidgetNode = WidgetConfig::Node; - using GlobalGUIConfig = GlobalGUIConfig; - Widget() { this->mArea = { 0, 0, 100, 100 }; } - virtual void populateConfig() {} - - [[nodiscard]] const RGBA& getColor(const std::string& name) const { - const auto& node = cfg->values.get(name); - if (node.type == WidgetNode::REF) { - return mGlobalCfg.configs.get(node.refGroup).values.get(node.refName).color; - } - return cfg->values.get(name).color; - } - - [[nodiscard]] halnf getValue(const std::string& name) const { - const auto& node = cfg->values.get(name); - if (node.type == WidgetNode::REF) { - return mGlobalCfg.configs.get(node.refGroup).values.get(node.refName).value; - } - return cfg->values.get(name).value; - } - - void addColor(const std::string& name, const RGBA& val) { cfg->values.put(name, WidgetNode(val)); } - void addValue(const std::string& name, halnf val) { cfg->values.put(name, WidgetNode(val)); } - - void addColor(const std::string& name, const std::string& presetName) { - cfg->values.put(name, WidgetNode(presetName)); - } - void addValue(const std::string& name, const std::string& presetName) { - cfg->values.put(name, WidgetNode(presetName)); - } - - bool createConfig(const std::string& name) { - auto idx = mGlobalCfg.configs.presents(name); - if (idx) return false; - mGlobalCfg.configs.put(name, {}); - cfg = &mGlobalCfg.configs.get(name); - populateConfig(); - return true; - } - virtual void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) { mVisible = areaParent.isOverlap(aArea); if (!mVisible) { @@ -66,19 +24,11 @@ namespace tp { } } - void addOperator(const std::string& name, WidgetConfig::WidgetCallback callback) { - cfg->mOperators.put(name, callback); - } - - Buffer& getShortcuts(const std::string& name) { return cfg->mShortcuts[name]; } + virtual void updateConfigCache(const WidgetManager& wm) = 0; public: - static GlobalGUIConfig mGlobalCfg; - WidgetConfig* cfg = nullptr; + std::string mId; RectF mArea; bool mVisible = false; }; - - template - GlobalGUIConfig Widget::mGlobalCfg; } \ No newline at end of file diff --git a/Widgets/public/WidgetConfig.hpp b/Widgets/public/WidgetConfig.hpp deleted file mode 100644 index cbf37df..0000000 --- a/Widgets/public/WidgetConfig.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include "Animations.hpp" -#include "Map.hpp" -#include "Rect.hpp" - -#include "InputCodes.hpp" -#include "Buffer.hpp" - -namespace tp { - - struct WidgetShortcut { - struct Condition { - std::string name; - std::string state; - }; - - WidgetShortcut() = default; - WidgetShortcut(const InitialierList&) {} - }; - - template - struct WidgetConfig { - - struct WidgetCallback { - using CallbackType = void (*)(void* self, const Events&); - void* self; - CallbackType callback; - }; - - struct Node { - enum Type { NONE, VAL, COL, REF }; - - halnf value = 0.f; - RGBA color = {}; - - Type type = NONE; - - std::string refGroup; - std::string refName; - - Node() = default; - - explicit Node(halnf val) { - type = VAL; - value = val; - } - - explicit Node(const RGBA& val) { - type = COL; - color = val; - } - - explicit Node(const std::string& val) { - refGroup = "Presets"; - refName = val; - type = REF; - } - }; - - Map values; - Map mOperators; - Map> mShortcuts; - }; - - template - struct GlobalGUIConfig { - using WidgetConfig = WidgetConfig; - using WidgetNode = WidgetConfig::Node; - - GlobalGUIConfig() { - configs.put("Presets", {}); - auto& presets = configs.get("Presets"); - - presets.values.put("FontSize", WidgetNode(15.f)); - presets.values.put("FontSizeDim", WidgetNode(12.f)); - presets.values.put("Rounding", WidgetNode(5.f)); - presets.values.put("Padding", WidgetNode(5.f)); - presets.values.put("HandleSize", WidgetNode(5.f)); - - presets.values.put("Background", WidgetNode(RGBA{ 0.03f, 0.03f, 0.03f, 1.f })); - presets.values.put("Base", WidgetNode(RGBA{ 0.07f, 0.07f, 0.07f, 1.f })); - presets.values.put("Accent", WidgetNode(RGBA{ 0.13f, 0.13f, 0.13f, 1.f })); - presets.values.put("Interaction", WidgetNode(RGBA{ 0.33f, 0.33f, 0.3f, 1.f })); - presets.values.put("Action", WidgetNode(RGBA{ 0.44f, 0.44f, 0.4f, 1.f })); - presets.values.put("Front", WidgetNode(RGBA{ 1.f, 1.f, 1.f, 1.f })); - presets.values.put("FrontDim", WidgetNode(RGBA{ 0.7f, 0.7f, 0.7f, 1.f })); - } - - ~GlobalGUIConfig() { configs.removeAll(); } - - void processShortcuts(const Events& events) { - // - } - - Map configs; - }; -} \ No newline at end of file diff --git a/Widgets/public/WidgetManager.hpp b/Widgets/public/WidgetManager.hpp new file mode 100644 index 0000000..e254a7d --- /dev/null +++ b/Widgets/public/WidgetManager.hpp @@ -0,0 +1,131 @@ +#pragma once + +#include "Animations.hpp" +#include "Map.hpp" +#include "Rect.hpp" + +#include "InputCodes.hpp" +#include "Buffer.hpp" + +namespace tp { + + struct WidgetConfig { + + struct WidgetShortcut { + struct Condition { + std::string name; + std::string state; + }; + + std::string callbackName; + + WidgetShortcut() = default; + WidgetShortcut(const InitialierList&) {} + }; + + struct WidgetParameter { + enum Type { NONE, VAL, COL, REF }; + + halnf value = 0.f; + RGBA color = {}; + + std::string refName; + std::string refWidgetId; + + Type type = NONE; + + WidgetParameter() = default; + + explicit WidgetParameter(halnf val) { + type = VAL; + value = val; + } + + explicit WidgetParameter(const RGBA& val) { + type = COL; + color = val; + } + + explicit WidgetParameter(const std::string& widgetId, const std::string& val) { + type = REF; + refName = val; + refWidgetId = widgetId; + } + }; + + Map mParameters; + Buffer mShortcuts; + }; + + class WidgetManager { + public: + WidgetManager() { + createWidgetConfig("Default"); + + addNumber("Default", "FontSize", 15.f); + addNumber("Default", "FontSizeDim", 12.f); + addNumber("Default", "Rounding", 5.f); + addNumber("Default", "Padding", 5.f); + addNumber("Default", "HandleSize", 5.f); + + addColor("Default", "Background", RGBA{ 0.03f, 0.03f, 0.03f, 1.f }); + addColor("Default", "Base", RGBA{ 0.07f, 0.07f, 0.07f, 1.f }); + addColor("Default", "Accent", RGBA{ 0.13f, 0.13f, 0.13f, 1.f }); + addColor("Default", "Interaction", RGBA{ 0.33f, 0.33f, 0.3f, 1.f }); + addColor("Default", "Action", RGBA{ 0.44f, 0.44f, 0.4f, 1.f }); + addColor("Default", "Front", RGBA{ 1.f, 1.f, 1.f, 1.f }); + addColor("Default", "FrontDim", RGBA{ 0.7f, 0.7f, 0.7f, 1.f }); + } + + ~WidgetManager() { mConfigurations.removeAll(); } + + bool createWidgetConfig(const std::string& widgetId) { + auto idx = mConfigurations.presents(widgetId); + if (idx) return false; + mConfigurations.put(widgetId, {}); + return true; + } + + [[nodiscard]] const RGBA& getColor(const std::string& widgetId, const std::string& name) const { + const WidgetConfig& config = mConfigurations.get(widgetId); + const WidgetConfig::WidgetParameter& parameter = config.mParameters.get(name); + + if (parameter.type == WidgetConfig::WidgetParameter::REF) { + return mConfigurations.get(parameter.refWidgetId).mParameters.get(parameter.refName).color; + } else { + return parameter.color; + } + } + + [[nodiscard]] halnf getNumber(const std::string& widgetId, const std::string& name) const { + const WidgetConfig& config = mConfigurations.get(widgetId); + const WidgetConfig::WidgetParameter& parameter = config.mParameters.get(name); + + if (parameter.type == WidgetConfig::WidgetParameter::REF) { + return mConfigurations.get(parameter.refWidgetId).mParameters.get(parameter.refName).value; + } else { + return parameter.value; + } + } + + void addColor(const std::string& widgetId, const std::string& name, const RGBA& val) { + WidgetConfig& config = mConfigurations.get(widgetId); + config.mParameters.put(name, WidgetConfig::WidgetParameter(val)); + } + + void addNumber(const std::string& widgetId, const std::string& name, halnf val) { + WidgetConfig& config = mConfigurations.get(widgetId); + config.mParameters.put(name, WidgetConfig::WidgetParameter(val)); + } + + void addReference(const std::string& widgetId, const std::string& refName, const std::string& name) { + WidgetConfig& config = mConfigurations.get(widgetId); + config.mParameters.put(refName, WidgetConfig::WidgetParameter("Default", name)); + } + + private: + Map mConfigurations; + RGBA mErrorColor = { 0, 0, 0, 1 }; + halnf mErrorNumber = 0; + }; +} \ No newline at end of file