From e3757770c8ea974e109a8794d50422d00077d6c2 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Wed, 17 Jul 2024 09:40:49 +0300 Subject: [PATCH] Fixes and improvements to the graphics module --- 3DEditor/applications/Entry.cpp | 2 +- Graphics/examples/Example.cpp | 7 +-- Graphics/private/Canvas.cpp | 18 +++++-- Graphics/private/EventHandler.cpp | 33 ++++++++---- Graphics/private/GraphicApplication.cpp | 67 ++++++++++++++++++++++--- Graphics/private/Window.cpp | 12 ++--- Graphics/public/EventHandler.hpp | 13 ++++- Graphics/public/GraphicApplication.hpp | 12 ++++- Graphics/public/Graphics.hpp | 10 ++-- Graphics/public/Window.hpp | 2 +- LibraryViewer/applications/Entry.cpp | 2 +- Objects/applications/GUIEntry.cpp | 2 +- Sketch3D/applications/Entry.cpp | 2 +- Widgets/examples/ChatGUI.cpp | 2 +- Widgets/examples/SimpleGUI.cpp | 2 +- Widgets/private/FloatingWidget.cpp | 3 ++ Widgets/private/WidgetBase.cpp | 4 +- Widgets/private/WorkspaceWidget.cpp | 21 ++++---- Widgets/public/FloatingWidget.hpp | 2 + 19 files changed, 161 insertions(+), 55 deletions(-) diff --git a/3DEditor/applications/Entry.cpp b/3DEditor/applications/Entry.cpp index 7aa2f1d..786018a 100644 --- a/3DEditor/applications/Entry.cpp +++ b/3DEditor/applications/Entry.cpp @@ -19,7 +19,7 @@ public: ~EditorGUI() override { delete mGui; } - void processFrame(EventHandler* eventHandler) override { + void processFrame(EventHandler* eventHandler, halnf delta) override { auto rec = RectF({ 0, 0 }, mWindow->getSize()); mGui->setArea(rec); diff --git a/Graphics/examples/Example.cpp b/Graphics/examples/Example.cpp index 90c5477..39907ef 100644 --- a/Graphics/examples/Example.cpp +++ b/Graphics/examples/Example.cpp @@ -11,7 +11,7 @@ class ExampleApplication : public Application { public: ExampleApplication() = default; - void processFrame(EventHandler* eventHandler) override { + void processFrame(EventHandler* eventHandler, halnf) override { // example } @@ -20,10 +20,11 @@ public: ImGui::ShowDemoWindow(); - ImGui::Text("Frames processed per second: %f", this->mFramesProcessedPerSecond); - ImGui::Text("Frames drawn per second: %f", this->mFramesDrawnPerSecond); + drawDebug(); } + bool forceNewFrame() override { return false; } + virtual ~ExampleApplication() = default; }; diff --git a/Graphics/private/Canvas.cpp b/Graphics/private/Canvas.cpp index 07b1f00..923332f 100644 --- a/Graphics/private/Canvas.cpp +++ b/Graphics/private/Canvas.cpp @@ -37,7 +37,9 @@ Canvas::~Canvas() { delete mContext; } -void Canvas::rect(const RectF& rec, const RGBA& col, halnf round) { +void Canvas::rect(RectF rec, const RGBA& col, halnf round) { + rec.pos += mOrigin; + nvgBeginPath(mContext->vg); if (round == 0) { @@ -50,7 +52,9 @@ void Canvas::rect(const RectF& rec, const RGBA& col, halnf round) { nvgFill(mContext->vg); } -void Canvas::circle(const Vec2F& pos, halnf size, const RGBA& col) { +void Canvas::circle(Vec2F pos, halnf size, const RGBA& col) { + pos += mOrigin; + nvgBeginPath(mContext->vg); nvgCircle(mContext->vg, pos.x, pos.y, size); @@ -58,6 +62,10 @@ void Canvas::circle(const Vec2F& pos, halnf size, const RGBA& col) { nvgFill(mContext->vg); } +void Canvas::setOrigin(const Vec2F& origin) { + mOrigin = origin; +} + void Canvas::pushClamp(const RectF& rec) { RectF intersection = rec; if (mScissors.size()) { @@ -82,7 +90,9 @@ void Canvas::popClamp() { void Canvas::text( const char* string, const RectF& aRec, halnf size, Align align, halnf marging, const RGBA& col ) { + RectF rec = { aRec.x + marging, aRec.y + marging, aRec.z - marging * 2, aRec.w - marging * 2 }; + rec.pos += mOrigin; pushClamp(rec); @@ -121,7 +131,9 @@ void Canvas::text( popClamp(); } -void Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding) { +void Canvas::drawImage(RectF rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding) { + rec.pos += mOrigin; + auto imgPaint = nvgImagePattern(mContext->vg, rec.x, rec.y, rec.z, rec.w, angle, image->id, alpha); nvgBeginPath(mContext->vg); nvgRoundedRect(mContext->vg, rec.x, rec.y, rec.z, rec.w, rounding); diff --git a/Graphics/private/EventHandler.cpp b/Graphics/private/EventHandler.cpp index 8c790ea..e34fc56 100644 --- a/Graphics/private/EventHandler.cpp +++ b/Graphics/private/EventHandler.cpp @@ -42,6 +42,14 @@ bool transitionsReduce[4][4] = { { true, true, true, true }, }; +void EventHandler::processAllEvent() { + mMutex.lock(); + while (mEventQueue.size()) { + processEventUnguarded(); + } + mMutex.unlock(); +} + void EventHandler::processEvent() { mMutex.lock(); @@ -50,10 +58,17 @@ void EventHandler::processEvent() { return; } - auto lastEvent = &mEventQueue.last(); + processEventUnguarded(); - const auto& eventData = lastEvent->second; - const auto& inputId = lastEvent->first; + mMutex.unlock(); +} + +void EventHandler::processEventUnguarded() { + + auto firstEvent = &mEventQueue.first(); + + const auto& eventData = firstEvent->second; + const auto& inputId = firstEvent->first; switch (eventData.type) { case InputEvent::Type::MOUSE_POS: @@ -71,8 +86,6 @@ void EventHandler::processEvent() { mInputStates[(int) inputId].mCurrentState = transitions[currentState][reportedEvent]; - // printf("%i - %i \n", reportedEvent, mInputStates[(int) InputID::MOUSE1].mCurrentState); - if (transitionsReduce[currentState][reportedEvent]) { mEventQueue.popFront(); } @@ -98,13 +111,15 @@ void EventHandler::processEvent() { } mPointerPressure = mInputStates[(int) InputID::MOUSE1].mCurrentState != InputState::State::NONE; - - mMutex.unlock(); } -const Vec2F& EventHandler::getPointer() const { return mPointer; } +void EventHandler::setCursorOrigin(const Vec2F& origin) { + mPointerOrigin = origin; +} -const Vec2F& EventHandler::getPointerPrev() const { return mPointerPrev; } +Vec2F EventHandler::getPointer() const { return mPointer - mPointerOrigin; } + +Vec2F EventHandler::getPointerPrev() const { return mPointerPrev - mPointerOrigin; } bool EventHandler::isPressed(InputID id) const { return mInputStates[(int) id].mCurrentState == InputState::State::PRESSED; diff --git a/Graphics/private/GraphicApplication.cpp b/Graphics/private/GraphicApplication.cpp index 145394e..d6ef14d 100644 --- a/Graphics/private/GraphicApplication.cpp +++ b/Graphics/private/GraphicApplication.cpp @@ -1,6 +1,8 @@ #include "GraphicApplication.hpp" +#include "imgui.h" + using namespace tp; Application::Application() { @@ -12,7 +14,7 @@ Application::Application() { mPerSecondTimer.setDuration(1000.f); } -void Application::run() { +void Application::runDefaultLoop() { auto eventHandler = new EventHandler(); mWindow->setEventHandler(eventHandler); @@ -25,8 +27,8 @@ void Application::run() { // proc first frame by default { - mWindow->processEvents(); - processFrame(eventHandler); + mWindow->processEvents(false); + processFrame(eventHandler, 0); mGraphics->drawBegin(); drawFrame(mGraphics->getCanvas()); @@ -34,17 +36,33 @@ void Application::run() { mWindow->draw(); } + time_ms prevProcTime = get_time(); + + bool isForcedNewFrame = true; + while (!mWindow->shouldClose()) { - mWindow->processEvents(); + mWindow->processEvents(!isForcedNewFrame); + updateGlobalTime(); - if (mProcTimer.isTimeout() || eventHandler->isEvents()) { + if (mProcTimer.isTimeout() || eventHandler->isEvents() || isForcedNewFrame) { + + while ((eventHandler->isEvents() || isForcedNewFrame)) { - while (eventHandler->isEvents()) { eventHandler->processEvent(); - processFrame(eventHandler); + + time_ms currentTime = get_time(); + processFrame(eventHandler, halnf(currentTime - prevProcTime)); + prevProcTime = currentTime; redrawNeeded = true; mFramesProcessed++; + + isForcedNewFrame = forceNewFrame(); + + if (isForcedNewFrame) { + // mWindow->processEvents(); + break; + } } mProcTimer.wait(); @@ -82,13 +100,46 @@ void Application::run() { delete eventHandler; } -void Application::processFrame(EventHandler* eventHandler) {} +void Application::runDebugLoop() { + auto eventHandler = new EventHandler(); + mWindow->setEventHandler(eventHandler); + + time_ms prevProcTime = get_time(); + + while (!mWindow->shouldClose()) { + mWindow->processEvents(); + eventHandler->processAllEvent(); + time_ms currentTime = get_time(); + processFrame(eventHandler, halnf(currentTime - prevProcTime)); + prevProcTime = currentTime; + + + mGraphics->drawBegin(); + drawFrame(mGraphics->getCanvas()); + mGraphics->drawEnd(); + mWindow->draw(); + } + + delete eventHandler; +} + +void Application::run() { + runDefaultLoop(); + // runDebugLoop(); +} + +void Application::processFrame(EventHandler* eventHandler, halnf deltaTime) {} void Application::drawFrame(Canvas* canvas) { // ImGui::Text("Frames processed per second: %f", mFramesProcessedPerSecond); // ImGui::Text("Frames drawn per second: %f", mFramesDrawnPerSecond); } +void Application::drawDebug() { + ImGui::Text("Frames processed per second: %f", this->mFramesProcessedPerSecond); + ImGui::Text("Frames drawn per second: %f", this->mFramesDrawnPerSecond); +} + Application::~Application() { delete mGraphics; Window::destroyWindow(mWindow); diff --git a/Graphics/private/Window.cpp b/Graphics/private/Window.cpp index 3bf1bb6..ac8e958 100644 --- a/Graphics/private/Window.cpp +++ b/Graphics/private/Window.cpp @@ -90,9 +90,9 @@ void Window::destroyWindow(Window* window) { bool Window::shouldClose() const { return glfwWindowShouldClose(mContext->window); } -void Window::processEvents() { - // glfwPollEvents(); - glfwWaitEvents(); +void Window::processEvents(bool wait) { + if (wait) glfwWaitEvents(); + else glfwPollEvents(); checkAxisUpdates(); } @@ -166,12 +166,12 @@ static void mouseButtonCallback(GLFWwindow* window, int button, int action, int auto id = (InputID) ((int) InputID::MOUSE1 + button); if (action == GLFW_PRESS) { - eventHandler->postEvent(id, { InputEvent::Type::BUTTON_ACTION, InputEvent::ButtonAction::PRESS, {} } - ); + // printf("mouse\n"); + eventHandler->postEvent(id, { InputEvent::Type::BUTTON_ACTION, InputEvent::ButtonAction::PRESS, {} }); } else if (action == GLFW_RELEASE) { eventHandler->postEvent(id, { InputEvent::Type::BUTTON_ACTION, InputEvent::ButtonAction::RELEASE, {} }); - // eventHandler->postEvent(id, { InputEvent::Type::BUTTON_ACTION, InputEvent::ButtonAction::NONE, {} }); } + } static void scrollCallback(GLFWwindow* window, double xOffset, double yOffset) { diff --git a/Graphics/public/EventHandler.hpp b/Graphics/public/EventHandler.hpp index a5dca76..e79a874 100644 --- a/Graphics/public/EventHandler.hpp +++ b/Graphics/public/EventHandler.hpp @@ -71,9 +71,13 @@ namespace tp { public: // User interface bool isEvents(); void processEvent(); + void processAllEvent(); - [[nodiscard]] const Vec2F& getPointer() const; - [[nodiscard]] const Vec2F& getPointerPrev() const; + + void setCursorOrigin(const Vec2F& origin); + + [[nodiscard]] Vec2F getPointer() const; + [[nodiscard]] Vec2F getPointerPrev() const; [[nodiscard]] Vec2F getPointerDelta() const; [[nodiscard]] bool isPressed(InputID id) const; @@ -83,6 +87,9 @@ namespace tp { [[nodiscard]] halnf getPointerPressure() const; + private: + void processEventUnguarded(); + private: std::mutex mMutex = {}; @@ -90,6 +97,8 @@ namespace tp { List> mEventQueue; // input states + Vec2F mPointerOrigin = { 0, 0 }; + Vec2F mPointer; Vec2F mPointerPrev; Vec2F mScrollDelta; diff --git a/Graphics/public/GraphicApplication.hpp b/Graphics/public/GraphicApplication.hpp index bc9e930..742a18f 100644 --- a/Graphics/public/GraphicApplication.hpp +++ b/Graphics/public/GraphicApplication.hpp @@ -12,16 +12,24 @@ namespace tp { void run(); - virtual void processFrame(EventHandler* eventHandler); + virtual bool forceNewFrame() { return false; } + + virtual void processFrame(EventHandler* eventHandler, halnf deltaTime); virtual void drawFrame(Canvas* canvas); virtual ~Application(); + void drawDebug(); + + private: + void runDefaultLoop(); + void runDebugLoop(); + protected: bool mInitialized = false; ualni mDrawPerSecond = 60; - ualni mProcPerSecond = 160; + ualni mProcPerSecond = 100; Timer mDrawTimer; Timer mProcTimer; diff --git a/Graphics/public/Graphics.hpp b/Graphics/public/Graphics.hpp index 49dfee6..2f3f775 100644 --- a/Graphics/public/Graphics.hpp +++ b/Graphics/public/Graphics.hpp @@ -55,21 +55,25 @@ namespace tp { ualni id = 0; }; + void setOrigin(const Vec2F& origin); + void pushClamp(const RectF& rec); void popClamp(); - void rect(const RectF& rec, const RGBA& col, halnf round = 0); - void circle(const Vec2F& pos, halnf size, const RGBA& col); + + void rect(RectF rec, const RGBA& col, halnf round = 0); + void circle(Vec2F pos, halnf size, const RGBA& col); void text(const char*, const RectF&, halnf size, Align, halnf padding, const RGBA&); ImageHandle createImageFromTextId(ualni id, Vec2F size); void updateTextureID(ImageHandle handle, ualni id); void deleteImageHandle(ImageHandle image); - void drawImage(const RectF& rec, ImageHandle* image, halnf angle = 0, halnf alpha = 1.f, halnf rounding = 0.f); + void drawImage(RectF rec, ImageHandle* image, halnf angle = 0, halnf alpha = 1.f, halnf rounding = 0.f); private: Buffer mScissors; bool mIsClamping = false; + Vec2F mOrigin = { 0, 0 }; }; class Graphics { diff --git a/Graphics/public/Window.hpp b/Graphics/public/Window.hpp index 6236a64..c37d656 100644 --- a/Graphics/public/Window.hpp +++ b/Graphics/public/Window.hpp @@ -17,7 +17,7 @@ namespace tp { public: void draw(); - void processEvents(); + void processEvents(bool wait = true); void setEventHandler(EventHandler* eventHandler); [[nodiscard]] EventHandler* getEventHandler(); diff --git a/LibraryViewer/applications/Entry.cpp b/LibraryViewer/applications/Entry.cpp index 197d705..8de5b87 100644 --- a/LibraryViewer/applications/Entry.cpp +++ b/LibraryViewer/applications/Entry.cpp @@ -14,7 +14,7 @@ public: gui.updateTracks(); } - void processFrame(EventHandler* eventHandler) override { + void processFrame(EventHandler* eventHandler, halnf delta) override { auto rec = RectF{ { 0, 0 }, mWindow->getSize() }; gui.setVisible(true); diff --git a/Objects/applications/GUIEntry.cpp b/Objects/applications/GUIEntry.cpp index b5c518e..8eef964 100644 --- a/Objects/applications/GUIEntry.cpp +++ b/Objects/applications/GUIEntry.cpp @@ -10,7 +10,7 @@ class SimpleGUI : public Application { public: SimpleGUI() { gui.cd(objects_api::create(), "root"); } - void processFrame(EventHandler* eventHandler) override {} + void processFrame(EventHandler* eventHandler, halnf delta) override {} void drawFrame(Canvas* canvas) override { canvas->rect({ { 0, 0 }, mWindow->getSize() }, RGBA(0.f, 0.f, 0.f, 1.f), 0); diff --git a/Sketch3D/applications/Entry.cpp b/Sketch3D/applications/Entry.cpp index 5a9092c..4e9d353 100644 --- a/Sketch3D/applications/Entry.cpp +++ b/Sketch3D/applications/Entry.cpp @@ -11,7 +11,7 @@ public: Sketch3DApplication() : mGui(*mGraphics->getCanvas(), { 1920, 1080 }) {} - void processFrame(EventHandler* eventHandler) override { + void processFrame(EventHandler* eventHandler, halnf delta) override { auto rec = RectF({ 0, 0 }, mWindow->getSize()); mGui.setVisible(true); diff --git a/Widgets/examples/ChatGUI.cpp b/Widgets/examples/ChatGUI.cpp index 204567c..64558f5 100644 --- a/Widgets/examples/ChatGUI.cpp +++ b/Widgets/examples/ChatGUI.cpp @@ -9,7 +9,7 @@ class ExampleGUI : public Application { public: ExampleGUI() = default; - void processFrame(EventHandler* eventHandler) override { + void processFrame(EventHandler* eventHandler, halnf delta) override { auto rec = RectF({ 0, 0 }, mWindow->getSize()); mGui.updateConfigWrapper(mWidgetManager); diff --git a/Widgets/examples/SimpleGUI.cpp b/Widgets/examples/SimpleGUI.cpp index 900ec77..31f6b53 100644 --- a/Widgets/examples/SimpleGUI.cpp +++ b/Widgets/examples/SimpleGUI.cpp @@ -12,7 +12,7 @@ public: // mGui.mPreview = true; } - void processFrame(EventHandler* eventHandler) override { + void processFrame(EventHandler* eventHandler, halnf) override { const auto rec = RectF({ 0, 0 }, mWindow->getSize()); mGui.setArea(rec); diff --git a/Widgets/private/FloatingWidget.cpp b/Widgets/private/FloatingWidget.cpp index e0f1cc6..9760eb4 100644 --- a/Widgets/private/FloatingWidget.cpp +++ b/Widgets/private/FloatingWidget.cpp @@ -37,6 +37,8 @@ void FloatingWidget::eventUpdateConfiguration(WidgetManager& wm) { } void FloatingWidget::checkFloating(const Events& events) { + mDropped = false; + if (this->mHeader.isHolding() && events.getPointerDelta().length2() > 4) { mFloating = true; } @@ -44,6 +46,7 @@ void FloatingWidget::checkFloating(const Events& events) { if (mFloating && this->mHeader.isReleased()) { mFloating = false; this->mHeader.clearEvents(); + mDropped = true; } if (mFloating) { diff --git a/Widgets/private/WidgetBase.cpp b/Widgets/private/WidgetBase.cpp index 212e74e..f838697 100644 --- a/Widgets/private/WidgetBase.cpp +++ b/Widgets/private/WidgetBase.cpp @@ -19,11 +19,11 @@ void Widget::procWrapper(const Events& events, const RectF& parentArea) { if (mHandlesEvents) { - eventProcess(events); - for (auto child : mChildWidgets) { child->procWrapper(events, mVisibleArea); } + + eventProcess(events); } } diff --git a/Widgets/private/WorkspaceWidget.cpp b/Widgets/private/WorkspaceWidget.cpp index 6aa7345..45aecaf 100644 --- a/Widgets/private/WorkspaceWidget.cpp +++ b/Widgets/private/WorkspaceWidget.cpp @@ -17,17 +17,18 @@ void WorkspaceWidget::eventProcess(const Events& events) { for (auto floatingChild : mFloatingLayer.mChildWidgets) { auto widget = dynamic_cast(floatingChild.data()); if (!widget) continue; - if (widget->isFloating()) { - if (widget->isReleased()) { - auto side = mDockSpace.getPreviewSide(); - if (side != GridLayoutWidget::NONE) { - mFloatingLayer.mChildWidgets.removeNode(mFloatingLayer.mChildWidgets.find(widget)); - widget->setCollapsed(false); - widget->stopFloating(); - mDockSpace.addSideWidget(widget, side); - } - } + if (widget->mDropped) { + auto side = mDockSpace.getPreviewSide(); + if (side != GridLayoutWidget::NONE) { + mFloatingLayer.mChildWidgets.removeNode(mFloatingLayer.mChildWidgets.find(widget)); + widget->setCollapsed(false); + widget->stopFloating(); + mDockSpace.addSideWidget(widget, side); + } + } + + if (widget->isFloating()) { mDockSpace.mHandlesEvents = true; mDockSpace.mPreview = true; } diff --git a/Widgets/public/FloatingWidget.hpp b/Widgets/public/FloatingWidget.hpp index ca18214..29657d8 100644 --- a/Widgets/public/FloatingWidget.hpp +++ b/Widgets/public/FloatingWidget.hpp @@ -32,5 +32,7 @@ namespace tp { public: bool mResizable = true; + + bool mDropped = false; }; } \ No newline at end of file