diff --git a/3DEditor/CMakeLists.txt b/3DEditor/CMakeLists.txt new file mode 100644 index 0000000..e11e387 --- /dev/null +++ b/3DEditor/CMakeLists.txt @@ -0,0 +1,22 @@ +project(3DEditor) + +### ---------------------- Externals --------------------- ### +set(BINDINGS_INCLUDE ../Externals/glfw/include ../Externals) +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(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 new file mode 100644 index 0000000..7c8bc87 --- /dev/null +++ b/3DEditor/applications/Entry.cpp @@ -0,0 +1,43 @@ + +#include "EditorWidget.hpp" + +#include "GraphicApplication.hpp" + +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; } + + 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: + Scene geometry; + WidgetManager mWidgetManager; + EditorWidget* mGui; +}; + +int main() { + EditorGUI gui; + gui.run(); +} 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/3DEditor/public/EditorWidget.hpp b/3DEditor/public/EditorWidget.hpp new file mode 100644 index 0000000..4f894a7 --- /dev/null +++ b/3DEditor/public/EditorWidget.hpp @@ -0,0 +1,79 @@ +#include "Widgets.hpp" +#include "Render.hpp" + +namespace tp { + + template + class ViewportWidget : public Widget { + public: + explicit ViewportWidget(Canvas* canvas, Scene* geometry, Vec2F renderResolution) : + mRender(renderResolution) { + + mImage = canvas->createImageFromTextId(mRender.getRenderBuffer(), mRender.getBufferSize()); + mGeometry = geometry; + 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; + + mGeometry->mCamera.rotate(0.01f, 0.0); + } + + void draw(Canvas& canvas) override { + if (!this->mVisible) return; + + mRender.render(*mGeometry, this->mArea.size); + canvas.drawImage(this->mArea, &mImage, PI); + } + + public: + Render mRender; + Scene* mGeometry = nullptr; + Canvas* mCanvas = nullptr; + Canvas::ImageHandle mImage; + }; + + template + class EditorWidget : public Widget { + public: + EditorWidget(Canvas* canvas, Scene* geometry, Vec2F renderResolution) : + mViewport(canvas, geometry, renderResolution) {} + + 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, mBaseColor); + mSplitView.draw(canvas); + mViewport.draw(canvas); + } + + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("3DEditor"); + + mBaseColor = wm.getColor("Base", "Base"); + + mViewport.updateConfigCache(wm); + mSplitView.updateConfigCache(wm); + } + + public: + ViewportWidget mViewport; + SplitView mSplitView; + + RGBA mBaseColor; + }; +} \ No newline at end of file diff --git a/3DEditor/public/Render.hpp b/3DEditor/public/Render.hpp new file mode 100644 index 0000000..818ffe8 --- /dev/null +++ b/3DEditor/public/Render.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "Scene.hpp" +#include "Rect.hpp" + +#include "FrameBuffer.hpp" +#include "Shader.hpp" + +namespace tp { + class Render { + public: + explicit Render(Vec2F renderResolution); + ~Render(); + + void render(const Scene& geometry, Vec2F size); + uint4 getRenderBuffer(); + Vec2F getBufferSize(); + + private: + RenderBuffer mRenderBuffer; + RenderShader mDefaultShader; + }; +} \ No newline at end of file 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/3DEditor/rsc/Font.ttf b/3DEditor/rsc/Font.ttf new file mode 100644 index 0000000..8a63054 Binary files /dev/null and b/3DEditor/rsc/Font.ttf differ 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 61301a1..c211e67 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(3DEditor) 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/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/Graphics/private/EventHandler.cpp b/Graphics/private/EventHandler.cpp index af7d924..d5b9f40 100644 --- a/Graphics/private/EventHandler.cpp +++ b/Graphics/private/EventHandler.cpp @@ -1,8 +1,6 @@ #include "EventHandler.hpp" -#include - using namespace tp; EventHandler::EventHandler() = default; @@ -35,7 +33,6 @@ bool transitionsReduce[4][4] = { { true, false, true, true }, }; - void EventHandler::processEvent() { mMutex.lock(); auto lastEvent = mEventQueue.last(); @@ -45,30 +42,30 @@ void EventHandler::processEvent() { switch (eventData.type) { case InputEvent::Type::MOUSE_POS: - { - mPointer = eventData.mouseEvent; - mEventQueue.popFront(); - break; - } - - case InputEvent::Type::BUTTON_ACTION: - { - auto currentState = (int) mInputStates[(int) inputId].mCurrentState; - auto reportedEvent = (int) eventData.buttonAction; - - mInputStates[(int) inputId].mCurrentState = transitions[currentState][reportedEvent]; - - if (transitionsReduce[currentState][reportedEvent]) { + { + mPointer = eventData.mouseEvent; mEventQueue.popFront(); + break; } - break; - } + case InputEvent::Type::BUTTON_ACTION: + { + auto currentState = (int) mInputStates[(int) inputId].mCurrentState; + auto reportedEvent = (int) eventData.buttonAction; + + mInputStates[(int) inputId].mCurrentState = transitions[currentState][reportedEvent]; + + if (transitionsReduce[currentState][reportedEvent]) { + mEventQueue.popFront(); + } + + break; + } default: - { - mEventQueue.popFront(); - } + { + mEventQueue.popFront(); + } } mPointerPressure = mInputStates[(int) InputID::MOUSE1].mCurrentState != InputState::State::NONE; @@ -78,7 +75,7 @@ void EventHandler::processEvent() { const Vec2F& EventHandler::getPointer() const { return mPointer; } -bool EventHandler::isPressed(InputID id) const { +bool EventHandler::isPressed(InputID id) const { return mInputStates[(int) id].mCurrentState == InputState::State::PRESSED; } @@ -86,13 +83,11 @@ bool EventHandler::isReleased(InputID id) const { return mInputStates[(int) id].mCurrentState == InputState::State::RELEASED; } -halnf EventHandler::getPointerPressure() const { - return mPointerPressure; -} +halnf EventHandler::getPointerPressure() const { return mPointerPressure; } bool EventHandler::isDown(InputID id) const { - return mInputStates[(int) id].mCurrentState == InputState::State::PRESSED || - mInputStates[(int) id].mCurrentState == InputState::State::HOLD; + return mInputStates[(int) id].mCurrentState == InputState::State::PRESSED || + mInputStates[(int) id].mCurrentState == InputState::State::HOLD; } halnf EventHandler::getScrollY() const { return 0; } \ No newline at end of file diff --git a/Graphics/public/Graphics.hpp b/Graphics/public/Graphics.hpp index 6eb5aa6..4d35595 100644 --- a/Graphics/public/Graphics.hpp +++ b/Graphics/public/Graphics.hpp @@ -62,7 +62,7 @@ namespace tp { ImageHandle createImageFromTextId(ualni id, Vec2F size); void deleteImageHandle(ImageHandle image); - void drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding); + void drawImage(const RectF& rec, ImageHandle* image, halnf angle = 0, halnf alpha = 1.f, halnf rounding = 0.f); private: Buffer 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/LibraryViewer/applications/Entry.cpp b/LibraryViewer/applications/Entry.cpp index 1545d69..13e7d84 100644 --- a/LibraryViewer/applications/Entry.cpp +++ b/LibraryViewer/applications/Entry.cpp @@ -18,7 +18,8 @@ using namespace tp; class LibraryViewer : public Application { public: - LibraryViewer() : gui(&library, &player) { + LibraryViewer() : + gui(&library, &player) { library.loadJson(getHome() + "Library.json"); library.checkExisting(); @@ -27,22 +28,22 @@ public: void processFrame(EventHandler* eventHandler) override { auto rec = RectF{ { 0, 0 }, mWindow->getSize() }; + + gui.updateConfigCache(mWidgetManager); gui.proc(*eventHandler, rec, rec); } - void drawFrame(Canvas* canvas) override { - gui.draw(*canvas); - } + void drawFrame(Canvas* canvas) override { gui.draw(*canvas); } private: Player player; Library library; + + tp::WidgetManager mWidgetManager; LibraryWidget gui; }; int main() { - tp::GlobalGUIConfig config; - tp::gGlobalGUIConfig = &config; LibraryViewer lib; lib.run(); diff --git a/LibraryViewer/public/GUI.hpp b/LibraryViewer/public/GUI.hpp index ae899ca..4befe8a 100644 --- a/LibraryViewer/public/GUI.hpp +++ b/LibraryViewer/public/GUI.hpp @@ -18,15 +18,10 @@ namespace tp { col.mColor.setNoTransition({ 0.15f, 0.15f, 0.15f, 0.f }); }; - void proc(const Events& events, const RectF& areaParent, const RectF& area) override { + void procBody(const Events& events) override { mSelected = false; - this->mArea = area; - this->mVisible = area.isOverlap(areaParent); - if (!this->mVisible) return; - if (!mTrack) return; - if (!areaParent.isOverlap(area)) return; - if (area.isInside(events.getPointer())) { + if (this->mArea.isInside(events.getPointer())) { col.set({ 0.15f, 0.15f, 0.15f, 1.f }); mSelected = events.isReleased(InputID::MOUSE1); } else { @@ -34,8 +29,7 @@ namespace tp { } } - void draw(Canvas& canvas) override { - if (!this->mVisible) return; + void drawBody(Canvas& canvas) override { if (!mTrack) return; canvas.rect(this->mArea, col.get(), 4.f); @@ -82,16 +76,7 @@ namespace tp { items.append({ "Date Last Played" }); } - void proc(const Events&, const RectF& areaParent, const RectF& area) override { - this->mArea = area; - this->mVisible = area.isOverlap(areaParent); - if (!this->mVisible) return; - if (!mTrack) return; - // renderUI(); - } - - void draw(Canvas&) override { - if (!this->mVisible) return; + void drawBody(Canvas&) override { if (!mTrack) return; // canvas.rect(this->mArea, { 0.13f, 0.13f, 0.13f, 1.f }, 4.f); renderUI(); @@ -220,11 +205,7 @@ namespace tp { } } - void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { - this->mArea = aArea; - this->mVisible = this->mArea.isOverlap(areaParent); - if (!this->mVisible) return; - + void procBody(const Events& events) override { filter(); mSplitView.proc(events, this->mArea, this->mArea); @@ -242,9 +223,7 @@ namespace tp { // mCurrentTrack.proc(events, this->mArea, mSplitView.getFirst()); } - void draw(Canvas& canvas) override { - if (!this->mVisible) return; - + void drawBody(Canvas& canvas) override { canvas.rect(this->mArea, { 0.1f, 0.1f, 0.1f, 1.f }); mSplitView.draw(canvas); @@ -283,6 +262,14 @@ namespace tp { mCurrentTrackInfo.isSongFilterChanged = false; } + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("LibraryWidget"); + mSplitView.updateConfigCache(wm); + mCurrentTrack.updateConfigCache(wm); + mCurrentTrackInfo.updateConfigCache(wm); + mSongList.updateConfigCache(wm); + } + private: Library* mLibrary = nullptr; Player* mPlayer = nullptr; 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/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/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/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..54ea3c1 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 @@ -32,11 +32,11 @@ bool loadMeshes(tp::Scene& scene, const std::string& objetsPath) { } for (int j = 0; j < curMesh.Indices.size(); j += 3) { - int idx1 = (int) curMesh.Indices[j]; - int idx2 = (int) curMesh.Indices[j + 1]; - int idx3 = (int) curMesh.Indices[j + 2]; + auto idx1 = (uhalni) curMesh.Indices[j]; + auto idx2 = (uhalni) curMesh.Indices[j + 1]; + auto idx3 = (uhalni) curMesh.Indices[j + 2]; // printf("{ %i, %i, %i },\n", idx1, idx2, idx3); - object->mTopology.Indexes.append(Vec3I{ idx1, idx2, idx3 }); + object->mTopology.Indexes.append(Vec3{ idx1, idx2, idx3 }); } if (object->mTopology.Normals.size() != object->mTopology.Points.size()) { @@ -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"); 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}/") diff --git a/Sketch3D/applications/Entry.cpp b/Sketch3D/applications/Entry.cpp index 9cb6be0..f46a6cb 100644 --- a/Sketch3D/applications/Entry.cpp +++ b/Sketch3D/applications/Entry.cpp @@ -8,30 +8,25 @@ using namespace tp; class Sketch3DApplication : public Application { public: - Sketch3DApplication() : mGui(*mGraphics->getCanvas(), {1920, 1080}) {} + Sketch3DApplication() : + mGui(*mGraphics->getCanvas(), { 1920, 1080 }) {} void processFrame(EventHandler* eventHandler) override { - auto rec = RectF( { 0, 0 }, mWindow->getSize() ); + auto rec = RectF({ 0, 0 }, mWindow->getSize()); + mGui.updateConfigCache(mWidgetManager); mGui.proc(*eventHandler, rec, rec); } - void drawFrame(Canvas* canvas) override { - mGui.draw(*canvas); - } + void drawFrame(Canvas* canvas) override { mGui.draw(*canvas); } private: + WidgetManager mWidgetManager; Sketch3DGUI mGui; }; - void runApp() { - tp::GlobalGUIConfig config; - tp::gGlobalGUIConfig = &config; - Sketch3DApplication app; app.run(); } -int main() { - runApp(); -} \ No newline at end of file +int main() { runApp(); } \ No newline at end of file diff --git a/Sketch3D/public/Sketch3DWidget.hpp b/Sketch3D/public/Sketch3DWidget.hpp index 787672a..942164d 100644 --- a/Sketch3D/public/Sketch3DWidget.hpp +++ b/Sketch3D/public/Sketch3DWidget.hpp @@ -9,16 +9,14 @@ namespace tp { class Sketch3DWidget : public Widget { public: Sketch3DWidget(Canvas& canvas, Vec2F renderResolution) : - mRenderer(renderResolution) { + mRenderer(renderResolution) { mImage = canvas.createImageFromTextId(mRenderer.getBuff()->texId(), mRenderer.getBuff()->getSize()); mCanvas = &canvas; mProject.mBackgroundColor = { 0.13f, 0.13f, 0.13f, 1.f }; } - ~Sketch3DWidget() { - mCanvas->deleteImageHandle(mImage); - } + ~Sketch3DWidget() { mCanvas->deleteImageHandle(mImage); } void proc(const Events& events, const RectF& areaParent, const RectF& area) override { @@ -51,20 +49,24 @@ namespace tp { mProject.mCamera.setRatio(this->mArea.w / this->mArea.z); switch (mMode) { - case Mode::MOVE: { + case Mode::MOVE: + { if (mAction) mProject.mCamera.move(relativePos, relativePosPrev); break; } - case Mode::ZOOM: { + case Mode::ZOOM: + { halnf factor = absolutePos.y / mActionPosAbsolutePrev.y; if (mAction) mProject.mCamera.zoom(factor); break; } - case Mode::ROTATE: { + case Mode::ROTATE: + { if (mAction) mProject.mCamera.rotate(-relativeDelta.x * halnf(PI), -relativeDelta.y * halnf(PI)); break; } - case Mode::DRAW: { + case Mode::DRAW: + { mProject.sample(events.getPointerPressure(), this->mArea.w / this->mArea.z, crs); break; } @@ -74,20 +76,15 @@ namespace tp { mActionPosAbsolutePrev = absolutePos; } - void draw(Canvas& canvas) override { - if (!this->mVisible) return; + void drawBody(Canvas& canvas) override { mRenderer.renderToTexture(&mProject, this->mArea.size); canvas.drawImage(this->mArea, &mImage, 0, 1, 12); } - void setColor(const RGBA& color) { - ((PencilBrush*) mProject.mBrushes.get("pencil"))->mCol = color; - } + void setColor(const RGBA& color) { ((PencilBrush*) mProject.mBrushes.get("pencil"))->mCol = color; } public: - enum class Mode { - MOVE, ROTATE, ZOOM, DRAW, NONE - } mMode = Mode::NONE; + enum class Mode { MOVE, ROTATE, ZOOM, DRAW, NONE } mMode = Mode::NONE; Vec2F mActionPosAbsolutePrev = { 0, 0 }; bool mAction = false; @@ -102,12 +99,8 @@ namespace tp { template class Sketch3DGUI : public Widget { public: - Sketch3DGUI(Canvas& canvas, Vec2F renderResolution) : mViewport(canvas, renderResolution) { - this->createConfig("Sketch3D"); - - this->addColor("Background", "Background"); - this->addValue("Rounding", "Rounding"); - + Sketch3DGUI(Canvas& canvas, Vec2F renderResolution) : + mViewport(canvas, renderResolution) { mDrawButton = new ButtonWidget("Draw", { 0, 0, 100, 30 }); mMoveButton = new ButtonWidget("Pan View", { 0, 0, 100, 30 }); mRotateButton = new ButtonWidget("Rotate view", { 0, 0, 100, 30 }); @@ -119,26 +112,22 @@ namespace tp { mOptions.mContents.append(mZoomButton); // add color sliders - mRed = new NamedSliderWidget < Events, Canvas >("Red"); - mGreen = new NamedSliderWidget < Events, Canvas >("Green"); - mBlue = new NamedSliderWidget < Events, Canvas >("Blue"); + mRed = new NamedSliderWidget("Red"); + mGreen = new NamedSliderWidget("Green"); + mBlue = new NamedSliderWidget("Blue"); mOptions.mContents.append(mRed); mOptions.mContents.append(mGreen); mOptions.mContents.append(mBlue); } - ~Sketch3DGUI() { + ~Sketch3DGUI() { for (auto item : mOptions.mContents) { delete item.data(); } } - void proc(const Events& events, const RectF& areaParent, const RectF& area) override { - this->mArea = area; - this->mVisible = area.isOverlap(areaParent); - if (!this->mVisible) return; - + void procBody(const Events& events) override { mSplitView.proc(events, this->mArea, this->mArea); mViewport.proc(events, this->mArea, mSplitView.getFirst()); mOptions.proc(events, this->mArea, mSplitView.getSecond()); @@ -156,16 +145,25 @@ namespace tp { mViewport.setColor(RGBA(mRed->mSlider.mFactor, mGreen->mSlider.mFactor, mBlue->mSlider.mFactor, 1.f)); } - void draw(Canvas& canvas) override { - if (!this->mVisible) return; - - canvas.rect(this->mArea, this->getColor("Background"), this->getValue("Rounding")); + void drawBody(Canvas& canvas) override { + canvas.rect(this->mArea, mBackgroundColor, mRounding); mSplitView.draw(canvas); mViewport.draw(canvas); mOptions.draw(canvas); } + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("Sketch3DGui"); + + mBackgroundColor = wm.getColor("Background", "Background"); + mRounding = wm.getNumber("Rounding", "Rounding"); + + mSplitView.updateConfigCache(wm); + mOptions.updateConfigCache(wm); + mViewport.updateConfigCache(wm); + } + private: Sketch3DWidget mViewport; SplitView mSplitView; @@ -179,5 +177,8 @@ namespace tp { NamedSliderWidget* mRed = nullptr; NamedSliderWidget* mGreen = nullptr; NamedSliderWidget* mBlue = nullptr; + + RGBA mBackgroundColor; + halnf mRounding = 0; }; } \ No newline at end of file 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 51% rename from Widgets/examples/Entry.cpp rename to Widgets/examples/ChatGUI.cpp index c7fc1d1..8c7783e 100644 --- a/Widgets/examples/Entry.cpp +++ b/Widgets/examples/ChatGUI.cpp @@ -1,5 +1,5 @@ -#include "ExampleGUI.hpp" +#include "ChatGUI.hpp" #include "GraphicApplication.hpp" @@ -9,23 +9,22 @@ 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.updateConfigCache(mWidgetManager); + mGui.proc(*eventHandler, rec, rec); } - void drawFrame(Canvas* canvas) override { - mGui.draw(*canvas); - } + void drawFrame(Canvas* canvas) override { mGui.draw(*canvas); } private: + WidgetManager mWidgetManager; ComplexWidget mGui; }; int main() { - GlobalGUIConfig mConfig; - gGlobalGUIConfig = &mConfig; - { ExampleGUI gui; gui.run(); diff --git a/Widgets/examples/ExampleGUI.hpp b/Widgets/examples/ChatGUI.hpp similarity index 63% rename from Widgets/examples/ExampleGUI.hpp rename to Widgets/examples/ChatGUI.hpp index 474151e..8ac8d0e 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() = default; void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { this->mArea = aArea; @@ -28,34 +20,40 @@ 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("UserWidget"); + + mBaseColor = wm.getColor("Base", "Base"); + mFontSize = wm.getNumber("Size", "FontSize"); + mPadding = wm.getNumber("Padding", "Padding"); + mUserColor = wm.getColor("ColUser", "Front"); + mAccentColor = wm.getColor("Accent", "Accent"); + mRounding = wm.getNumber("Rounding", "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() = default; void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { this->mArea = aArea; @@ -67,14 +65,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 +74,40 @@ 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("MessageWidget"); + + mBaseColor = wm.getColor("Base", "Base"); + mFontSize = wm.getNumber("Size", "FontSize"); + mFontSizeDim = wm.getNumber("SizeUser", "FontSizeDim"); + mPadding = wm.getNumber("Padding", "Padding"); + mUserColor = wm.getColor("UserColor", "Front"); + mUserColorDim = wm.getColor("UserColorDim", "FrontDim"); + mRounding = wm.getNumber("Rounding", "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"); mPass.mId = "pass"; mUser.mId = "user"; mButton.mLabel.mLabel = "Login"; @@ -120,26 +129,36 @@ 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("LoginWidget"); + + mBGColor = wm.getColor("Back", "Base"); + + 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"); mSend.mLabel.mLabel = "Send"; mMessage.mId = "Message"; } @@ -152,16 +171,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,27 +193,41 @@ 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("ActiveChat"); + + mBGColor = wm.getColor("Back", "Background"); + mPadding = wm.getNumber("Padding", "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"); - // todo : fetch code mUsers.append(UserWidget()); mUsers.append(UserWidget()); @@ -225,34 +258,44 @@ 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("ChattingWidget"); + + mBGColor = wm.getColor("Back", "Background"); + + 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() = default; void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override { this->mArea = aArea; @@ -268,14 +311,25 @@ 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("ChatGui"); + + mBGColor = wm.getColor("Back", "Background"); + + 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..142bbf7 --- /dev/null +++ b/Widgets/examples/SimpleGUI.cpp @@ -0,0 +1,44 @@ + +#include "ChatGUI.hpp" + +#include "GraphicApplication.hpp" + +using namespace tp; + +class SimpleGUI : public Application { +public: + SimpleGUI() { + 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/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/ButtonWidget.hpp b/Widgets/public/ButtonWidget.hpp index 8df41bc..003cdec 100644 --- a/Widgets/public/ButtonWidget.hpp +++ b/Widgets/public/ButtonWidget.hpp @@ -7,40 +7,15 @@ namespace tp { template class ButtonWidget : public Widget { 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"); - } + ButtonWidget() { this->mArea = { 0, 0, 100, 100 }; } ButtonWidget(const std::string& label, const tp::RectF& aArea) { 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 { - this->mArea = aArea; - this->mVisible = areaParent.isOverlap(aArea); - if (!this->mVisible) return; - - mIsHover = false; - - if (!areaParent.isOverlap(aArea)) { - mIsReleased = false; - mIsPressed = false; - return; - } - - mIsHover = aArea.isInside(events.getPointer()); + void procBody(const Events& events) { + mIsHover = this->mArea.isInside(events.getPointer()); if (events.isPressed(InputID::MOUSE1) && mIsHover) { mIsPressed = true; @@ -53,26 +28,46 @@ namespace tp { if (!mIsHover) mIsPressed = false; - mLabel.proc(events, aArea, aArea); + mLabel.proc(events, this->mArea, this->mArea); } - void draw(Canvas& canvas) override { - if (!this->mVisible) return; - + void drawBody(Canvas& canvas) override { 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("Button"); + + pressedColor = wm.getColor("Pressed", "Action"); + hoveredColor = wm.getColor("Hovered", "Interaction"); + accentColor = wm.getColor("Default", "Accent"); + rounding = wm.getNumber("Rounding", "Rounding"); + + // mPressEvent = wm.getEventState("Activate", { { InputID::MOUSE1, InputState::PRESSED } }); + + mLabel.updateConfigCache(wm); + } + public: LabelWidget mLabel; + bool mIsHover = false; bool mIsPressed = false; bool mIsReleased = false; + + RGBA pressedColor; + RGBA hoveredColor; + RGBA accentColor; + halnf rounding = 0; + + InputState mPressEvent; }; } \ No newline at end of file diff --git a/Widgets/public/LabelWidget.hpp b/Widgets/public/LabelWidget.hpp index 945436e..fcdb7f4 100644 --- a/Widgets/public/LabelWidget.hpp +++ b/Widgets/public/LabelWidget.hpp @@ -6,33 +6,26 @@ 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() = default; + + void drawBody(Canvas& canvas) override { + canvas.text(mLabel.c_str(), this->mArea, fontSize, Canvas::CC, padding, fontColor); } - void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { - this->mArea = aArea; - this->mVisible = areaParent.isOverlap(aArea); - if (!this->mVisible) return; - } + public: + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("Label"); - void draw(Canvas& canvas) override { - if (!this->mVisible) return; - - canvas.text( - mLabel.c_str(), - this->mArea, - this->getValue("Size"), - Canvas::CC, - this->getValue("Padding"), - this->getColor("Default") - ); + fontSize = wm.getNumber("Size", "FontSize"); + padding = wm.getNumber("Padding", "Padding"); + fontColor = wm.getColor("Default", "Front"); } 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..44841f8 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() = default; // 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,28 @@ 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 updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("Scrollbar"); + + mDefaultColor = wm.getColor("Default", "Base"); + mHandleColor = wm.getColor("Handle", "Accent"); + mHoveredColor = wm.getColor("Hovered", "Interaction"); + mScrollingColor = wm.getColor("Scrolling", "Action"); + mPadding = wm.getNumber("Padding", "Padding"); + mHandleSize = wm.getNumber("HandleSize", 20.f); + mMinSize = wm.getNumber("MinSize", 20.f); + mRounding = wm.getNumber("Rounding", "Rounding"); } public: @@ -126,29 +124,29 @@ 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() = default; ~ScrollableWindow() = default; // takes whole area - void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { - this->mArea = aArea; - this->mVisible = areaParent.isOverlap(aArea); - if (!this->mVisible) return; - + void procBody(const Events& events) override { 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); @@ -168,9 +166,7 @@ namespace tp { } } - void draw(Canvas& canvas) override { - if (!this->mVisible) return; - + void drawBody(Canvas& canvas) override { mScroller.draw(canvas); canvas.pushClamp(this->mArea); @@ -180,16 +176,29 @@ namespace tp { canvas.popClamp(); } + public: + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("ScrollableWidget"); + + mDefaultColor = wm.getColor("Default", "Base"); + mPadding = wm.getNumber("Padding", "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 +210,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 +226,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..aa068a8 100644 --- a/Widgets/public/SliderWidget.hpp +++ b/Widgets/public/SliderWidget.hpp @@ -7,23 +7,9 @@ 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"); - } - - void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { - this->mArea = aArea; - this->mVisible = areaParent.isOverlap(aArea); - if (!this->mVisible) return; + SliderWidget() = default; + void procBody(const Events& events) override { if (events.isPressed(InputID::MOUSE1) && this->mArea.isInside(events.getPointer())) { mIsSliding = true; } else if (events.isReleased(InputID::MOUSE1)) { @@ -31,44 +17,50 @@ namespace tp { } if (mIsSliding) { - const auto handleSize = this->getValue("HandleSize"); mFactor = (events.getPointer().x - this->mArea.x - handleSize / 2.f) / (this->mArea.z - handleSize); } mFactor = tp::clamp(mFactor, 0.f, 1.f); } - 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")); + void drawBody(Canvas& canvas) override { + 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 left = this->mArea.x + (this->mArea.z - handleSize) * mFactor; + return { left, this->mArea.y, handleSize, this->mArea.w }; + } + + public: + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("Slider"); + defaultColor = wm.getColor("Default", "Base"); + handleColor = wm.getColor("Handle", "Accent"); + handleSize = wm.getNumber("HandleSize", 20.f); + rounding = wm.getNumber("Rounding", "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") { mLabel.mLabel = name; this->mArea = { 0, 0, 100, 30 }; } - void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { - this->mArea = aArea; - this->mVisible = areaParent.isOverlap(aArea); - if (!this->mVisible) return; - + void procBody(const Events& events) override { const auto widthFirst = this->mArea.z * mFactor; const auto widthSecond = this->mArea.z * (1.f - mFactor); @@ -83,12 +75,17 @@ namespace tp { mSlider.proc(events, this->mArea, rec); } - void draw(Canvas& canvas) override { - if (!this->mVisible) return; + void drawBody(Canvas& canvas) override { mSlider.draw(canvas); mLabel.draw(canvas); } + virtual void updateConfigCache(WidgetManager& wm) { + wm.setActiveId("NamedSlider"); + mSlider.updateConfigCache(wm); + mLabel.updateConfigCache(wm); + } + public: SliderWidget mSlider; LabelWidget mLabel; diff --git a/Widgets/public/SplitViewWidget.hpp b/Widgets/public/SplitViewWidget.hpp index 2ee1ad8..bca050c 100644 --- a/Widgets/public/SplitViewWidget.hpp +++ b/Widgets/public/SplitViewWidget.hpp @@ -6,24 +6,9 @@ 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); - } - - void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { - this->mArea = aArea; - this->mVisible = areaParent.isOverlap(aArea); - - if (!this->mVisible) { - mResizeInProcess = false; - return; - } + SplitView() = default; + void procBody(const Events& events) override { mIsHover = getHandle().isInside(events.getPointer()); if (events.isPressed(InputID::MOUSE1) && mIsHover) { @@ -38,45 +23,55 @@ 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; } } // takes whole area - 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")); + void drawBody(Canvas& canvas) override { + 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 }; + } + + public: + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("SplitView"); + + mHandleColor = wm.getColor("Handle", "Accent"); + mHoveredColor = wm.getColor("Hovered", "Interaction"); + mResizingColor = wm.getColor("Resizing", "Action"); + mMinSize = wm.getNumber("Min", 200.f); + mHandleSize = wm.getNumber("HandleSize", 7.f); } 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..e4f2da4 100644 --- a/Widgets/public/TextInputWidget.hpp +++ b/Widgets/public/TextInputWidget.hpp @@ -9,28 +9,13 @@ 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"); - } - - void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { - this->mArea = aArea; - this->mVisible = areaParent.isOverlap(aArea); - if (!this->mVisible) return; - } - - void draw(Canvas& canvas) override { - if (!this->mVisible) return; + TextInputWidget() = default; + void drawBody(Canvas& canvas) override { 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 +23,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 +50,29 @@ namespace tp { ImGui::PopStyleVar(3); } + public: + void updateConfigCache(WidgetManager& wm) override { + wm.setActiveId("TextInput"); + + mAccentColor = wm.getColor("Accent", "Accent"); + mBaseColor = wm.getColor("Base", "Base"); + mRounding = wm.getNumber("Rounding", "Rounding"); + mHoveredColor = wm.getColor("Hovered", "Accent"); + mPadding = wm.getNumber("Padding", "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 3fcd190..6554a25 100644 --- a/Widgets/public/WidgetBase.hpp +++ b/Widgets/public/WidgetBase.hpp @@ -1,46 +1,14 @@ #pragma once -#include "WidgetConfig.hpp" +#include "EventHandler.hpp" +#include "WidgetManager.hpp" namespace tp { template class Widget { public: - Widget() { - this->mArea = { 0, 0, 100, 100 }; - } - - [[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; - } - 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; - } - 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 std::string& presetName) { - cfg->values.put(name, WidgetConfig::Node(presetName)); - } - void addValue(const std::string& name, const std::string& presetName) { - cfg->values.put(name, WidgetConfig::Node(presetName)); - } - - void createConfig(const std::string& name) { - globalCfg->configs.put(name, {}); - cfg = &globalCfg->configs.get(name); - } + Widget() { this->mArea = { 0, 0, 100, 100 }; } virtual void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) { mVisible = areaParent.isOverlap(aArea); @@ -49,18 +17,27 @@ namespace tp { } this->mArea = aArea; + this->mAreaParent = areaParent; + + procBody(events); } virtual void draw(Canvas& canvas) { if (!mVisible) { return; } + + drawBody(canvas); } + virtual void procBody(const Events& events) {} + virtual void drawBody(Canvas& canvas) {} + + virtual void updateConfigCache(WidgetManager& wm) {} + public: - GlobalGUIConfig* globalCfg = gGlobalGUIConfig; - WidgetConfig* cfg = nullptr; RectF mArea; + RectF mAreaParent; bool mVisible = false; }; } \ No newline at end of file diff --git a/Widgets/public/WidgetConfig.hpp b/Widgets/public/WidgetConfig.hpp deleted file mode 100644 index 3455c48..0000000 --- a/Widgets/public/WidgetConfig.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include "Animations.hpp" -#include "Map.hpp" -#include "Rect.hpp" - -#include "InputCodes.hpp" - -namespace tp { - - struct WidgetConfig { - 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; - }; - - struct GlobalGUIConfig { - 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("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 })); - } - - Map configs; - - ~GlobalGUIConfig() { - configs.removeAll(); - } - }; - - extern GlobalGUIConfig* gGlobalGUIConfig; -} \ No newline at end of file diff --git a/Widgets/public/WidgetManager.hpp b/Widgets/public/WidgetManager.hpp new file mode 100644 index 0000000..8ef875a --- /dev/null +++ b/Widgets/public/WidgetManager.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include "Animations.hpp" +#include "Map.hpp" +#include "Rect.hpp" + +#include "InputCodes.hpp" +#include "Buffer.hpp" + +namespace tp { + + struct WidgetConfig { + + struct Shortcut { + struct Condition { + std::string name; + std::string state; + }; + + std::string callbackName; + + Shortcut() = default; + Shortcut(const InitialierList&) {} + }; + + struct Parameter { + enum Type { NONE, VAL, COL }; + + halnf value = 0.f; + RGBA color = {}; + Type type = NONE; + bool globalReference = false; + std::string globalId; + + Parameter() = default; + + explicit Parameter(halnf val) { + type = VAL; + value = val; + } + + explicit Parameter(const RGBA& val) { + type = COL; + color = val; + } + + explicit Parameter(const std::string& id, const Type& referenceType) { + type = referenceType; + globalId = id; + globalReference = true; + } + }; + + Map mParameters; + Buffer mShortcuts; + }; + + class WidgetManager { + public: + using Parameter = WidgetConfig::Parameter; + + public: + WidgetManager() { initGlobalParameters(); } + ~WidgetManager() { mConfigurations.removeAll(); } + + const RGBA& getColor(const std::string& parameterId, const RGBA& defaultValue) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue)); + return parameter.color; + } + + const RGBA& getColor(const std::string& parameterId, const char* globalRef) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::COL)); + return parameter.color; + } + + halnf getNumber(const std::string& parameterId, halnf defaultValue) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue)); + return parameter.value; + } + + halnf getNumber(const std::string& parameterId, const char* globalRef) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::VAL)); + return parameter.value; + } + + void setActiveId(const std::string& id) { mActiveId = id; } + + private: + WidgetConfig& getWidgetConfig(const std::string& id) { + auto idx = mConfigurations.presents(id); + if (idx) return mConfigurations.getSlotVal(idx); + mConfigurations.put(id, {}); + return mConfigurations.get(id); + } + + Parameter& getParameter(WidgetConfig& config, const std::string& id, const Parameter& defaultValue) { + auto idx = config.mParameters.presents(id); + + if (!idx) { + config.mParameters.put(id, defaultValue); + } + + Parameter& parameter = config.mParameters.get(id); + + if (parameter.globalReference) { + return mGlobalConfig.mParameters.get(parameter.globalId); + } else { + return parameter; + } + } + + void initGlobalParameters() { + auto& params = mGlobalConfig.mParameters; + + params.put("FontSize", Parameter(15.f)); + + params.put("FontSizeDim", Parameter(12.f)); + params.put("Rounding", Parameter(5.f)); + params.put("Padding", Parameter(5.f)); + params.put("HandleSize", Parameter(5.f)); + + params.put("Background", Parameter(RGBA{ 0.03f, 0.03f, 0.03f, 1.f })); + params.put("Base", Parameter(RGBA{ 0.07f, 0.07f, 0.07f, 1.f })); + params.put("Accent", Parameter(RGBA{ 0.13f, 0.13f, 0.13f, 1.f })); + params.put("Interaction", Parameter(RGBA{ 0.33f, 0.33f, 0.3f, 1.f })); + params.put("Action", Parameter(RGBA{ 0.44f, 0.44f, 0.4f, 1.f })); + params.put("Front", Parameter(RGBA{ 1.f, 1.f, 1.f, 1.f })); + params.put("FrontDim", Parameter(RGBA{ 0.7f, 0.7f, 0.7f, 1.f })); + } + + private: + Map mConfigurations; + WidgetConfig mGlobalConfig; + + RGBA mErrorColor = { 0, 0, 0, 1 }; + halnf mErrorNumber = 0; + + std::string mActiveId; + }; +} \ No newline at end of file