Fixes and improvements to the graphics module

This commit is contained in:
IlyaShurupov 2024-07-17 09:40:49 +03:00
parent 2fb319840c
commit e3757770c8
19 changed files with 161 additions and 55 deletions

View file

@ -19,7 +19,7 @@ public:
~EditorGUI() override { delete mGui; } ~EditorGUI() override { delete mGui; }
void processFrame(EventHandler* eventHandler) override { void processFrame(EventHandler* eventHandler, halnf delta) override {
auto rec = RectF({ 0, 0 }, mWindow->getSize()); auto rec = RectF({ 0, 0 }, mWindow->getSize());
mGui->setArea(rec); mGui->setArea(rec);

View file

@ -11,7 +11,7 @@ class ExampleApplication : public Application {
public: public:
ExampleApplication() = default; ExampleApplication() = default;
void processFrame(EventHandler* eventHandler) override { void processFrame(EventHandler* eventHandler, halnf) override {
// example // example
} }
@ -20,10 +20,11 @@ public:
ImGui::ShowDemoWindow(); ImGui::ShowDemoWindow();
ImGui::Text("Frames processed per second: %f", this->mFramesProcessedPerSecond); drawDebug();
ImGui::Text("Frames drawn per second: %f", this->mFramesDrawnPerSecond);
} }
bool forceNewFrame() override { return false; }
virtual ~ExampleApplication() = default; virtual ~ExampleApplication() = default;
}; };

View file

@ -37,7 +37,9 @@ Canvas::~Canvas() {
delete mContext; 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); nvgBeginPath(mContext->vg);
if (round == 0) { if (round == 0) {
@ -50,7 +52,9 @@ void Canvas::rect(const RectF& rec, const RGBA& col, halnf round) {
nvgFill(mContext->vg); 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); nvgBeginPath(mContext->vg);
nvgCircle(mContext->vg, pos.x, pos.y, size); 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); nvgFill(mContext->vg);
} }
void Canvas::setOrigin(const Vec2F& origin) {
mOrigin = origin;
}
void Canvas::pushClamp(const RectF& rec) { void Canvas::pushClamp(const RectF& rec) {
RectF intersection = rec; RectF intersection = rec;
if (mScissors.size()) { if (mScissors.size()) {
@ -82,7 +90,9 @@ void Canvas::popClamp() {
void Canvas::text( void Canvas::text(
const char* string, const RectF& aRec, halnf size, Align align, halnf marging, const RGBA& col 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 }; RectF rec = { aRec.x + marging, aRec.y + marging, aRec.z - marging * 2, aRec.w - marging * 2 };
rec.pos += mOrigin;
pushClamp(rec); pushClamp(rec);
@ -121,7 +131,9 @@ void Canvas::text(
popClamp(); 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); auto imgPaint = nvgImagePattern(mContext->vg, rec.x, rec.y, rec.z, rec.w, angle, image->id, alpha);
nvgBeginPath(mContext->vg); nvgBeginPath(mContext->vg);
nvgRoundedRect(mContext->vg, rec.x, rec.y, rec.z, rec.w, rounding); nvgRoundedRect(mContext->vg, rec.x, rec.y, rec.z, rec.w, rounding);

View file

@ -42,6 +42,14 @@ bool transitionsReduce[4][4] = {
{ true, true, true, true }, { true, true, true, true },
}; };
void EventHandler::processAllEvent() {
mMutex.lock();
while (mEventQueue.size()) {
processEventUnguarded();
}
mMutex.unlock();
}
void EventHandler::processEvent() { void EventHandler::processEvent() {
mMutex.lock(); mMutex.lock();
@ -50,10 +58,17 @@ void EventHandler::processEvent() {
return; return;
} }
auto lastEvent = &mEventQueue.last(); processEventUnguarded();
const auto& eventData = lastEvent->second; mMutex.unlock();
const auto& inputId = lastEvent->first; }
void EventHandler::processEventUnguarded() {
auto firstEvent = &mEventQueue.first();
const auto& eventData = firstEvent->second;
const auto& inputId = firstEvent->first;
switch (eventData.type) { switch (eventData.type) {
case InputEvent::Type::MOUSE_POS: case InputEvent::Type::MOUSE_POS:
@ -71,8 +86,6 @@ void EventHandler::processEvent() {
mInputStates[(int) inputId].mCurrentState = transitions[currentState][reportedEvent]; mInputStates[(int) inputId].mCurrentState = transitions[currentState][reportedEvent];
// printf("%i - %i \n", reportedEvent, mInputStates[(int) InputID::MOUSE1].mCurrentState);
if (transitionsReduce[currentState][reportedEvent]) { if (transitionsReduce[currentState][reportedEvent]) {
mEventQueue.popFront(); mEventQueue.popFront();
} }
@ -98,13 +111,15 @@ void EventHandler::processEvent() {
} }
mPointerPressure = mInputStates[(int) InputID::MOUSE1].mCurrentState != InputState::State::NONE; 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 { bool EventHandler::isPressed(InputID id) const {
return mInputStates[(int) id].mCurrentState == InputState::State::PRESSED; return mInputStates[(int) id].mCurrentState == InputState::State::PRESSED;

View file

@ -1,6 +1,8 @@
#include "GraphicApplication.hpp" #include "GraphicApplication.hpp"
#include "imgui.h"
using namespace tp; using namespace tp;
Application::Application() { Application::Application() {
@ -12,7 +14,7 @@ Application::Application() {
mPerSecondTimer.setDuration(1000.f); mPerSecondTimer.setDuration(1000.f);
} }
void Application::run() { void Application::runDefaultLoop() {
auto eventHandler = new EventHandler(); auto eventHandler = new EventHandler();
mWindow->setEventHandler(eventHandler); mWindow->setEventHandler(eventHandler);
@ -25,8 +27,8 @@ void Application::run() {
// proc first frame by default // proc first frame by default
{ {
mWindow->processEvents(); mWindow->processEvents(false);
processFrame(eventHandler); processFrame(eventHandler, 0);
mGraphics->drawBegin(); mGraphics->drawBegin();
drawFrame(mGraphics->getCanvas()); drawFrame(mGraphics->getCanvas());
@ -34,17 +36,33 @@ void Application::run() {
mWindow->draw(); mWindow->draw();
} }
time_ms prevProcTime = get_time();
bool isForcedNewFrame = true;
while (!mWindow->shouldClose()) { 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(); eventHandler->processEvent();
processFrame(eventHandler);
time_ms currentTime = get_time();
processFrame(eventHandler, halnf(currentTime - prevProcTime));
prevProcTime = currentTime;
redrawNeeded = true; redrawNeeded = true;
mFramesProcessed++; mFramesProcessed++;
isForcedNewFrame = forceNewFrame();
if (isForcedNewFrame) {
// mWindow->processEvents();
break;
}
} }
mProcTimer.wait(); mProcTimer.wait();
@ -82,13 +100,46 @@ void Application::run() {
delete eventHandler; 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) { void Application::drawFrame(Canvas* canvas) {
// ImGui::Text("Frames processed per second: %f", mFramesProcessedPerSecond); // ImGui::Text("Frames processed per second: %f", mFramesProcessedPerSecond);
// ImGui::Text("Frames drawn per second: %f", mFramesDrawnPerSecond); // 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() { Application::~Application() {
delete mGraphics; delete mGraphics;
Window::destroyWindow(mWindow); Window::destroyWindow(mWindow);

View file

@ -90,9 +90,9 @@ void Window::destroyWindow(Window* window) {
bool Window::shouldClose() const { return glfwWindowShouldClose(mContext->window); } bool Window::shouldClose() const { return glfwWindowShouldClose(mContext->window); }
void Window::processEvents() { void Window::processEvents(bool wait) {
// glfwPollEvents(); if (wait) glfwWaitEvents();
glfwWaitEvents(); else glfwPollEvents();
checkAxisUpdates(); checkAxisUpdates();
} }
@ -166,12 +166,12 @@ static void mouseButtonCallback(GLFWwindow* window, int button, int action, int
auto id = (InputID) ((int) InputID::MOUSE1 + button); auto id = (InputID) ((int) InputID::MOUSE1 + button);
if (action == GLFW_PRESS) { 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) { } else if (action == GLFW_RELEASE) {
eventHandler->postEvent(id, { InputEvent::Type::BUTTON_ACTION, InputEvent::ButtonAction::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) { static void scrollCallback(GLFWwindow* window, double xOffset, double yOffset) {

View file

@ -71,9 +71,13 @@ namespace tp {
public: // User interface public: // User interface
bool isEvents(); bool isEvents();
void processEvent(); 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]] Vec2F getPointerDelta() const;
[[nodiscard]] bool isPressed(InputID id) const; [[nodiscard]] bool isPressed(InputID id) const;
@ -83,6 +87,9 @@ namespace tp {
[[nodiscard]] halnf getPointerPressure() const; [[nodiscard]] halnf getPointerPressure() const;
private:
void processEventUnguarded();
private: private:
std::mutex mMutex = {}; std::mutex mMutex = {};
@ -90,6 +97,8 @@ namespace tp {
List<std::pair<InputID, InputEvent>> mEventQueue; List<std::pair<InputID, InputEvent>> mEventQueue;
// input states // input states
Vec2F mPointerOrigin = { 0, 0 };
Vec2F mPointer; Vec2F mPointer;
Vec2F mPointerPrev; Vec2F mPointerPrev;
Vec2F mScrollDelta; Vec2F mScrollDelta;

View file

@ -12,16 +12,24 @@ namespace tp {
void run(); 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 void drawFrame(Canvas* canvas);
virtual ~Application(); virtual ~Application();
void drawDebug();
private:
void runDefaultLoop();
void runDebugLoop();
protected: protected:
bool mInitialized = false; bool mInitialized = false;
ualni mDrawPerSecond = 60; ualni mDrawPerSecond = 60;
ualni mProcPerSecond = 160; ualni mProcPerSecond = 100;
Timer mDrawTimer; Timer mDrawTimer;
Timer mProcTimer; Timer mProcTimer;

View file

@ -55,21 +55,25 @@ namespace tp {
ualni id = 0; ualni id = 0;
}; };
void setOrigin(const Vec2F& origin);
void pushClamp(const RectF& rec); void pushClamp(const RectF& rec);
void popClamp(); 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&); void text(const char*, const RectF&, halnf size, Align, halnf padding, const RGBA&);
ImageHandle createImageFromTextId(ualni id, Vec2F size); ImageHandle createImageFromTextId(ualni id, Vec2F size);
void updateTextureID(ImageHandle handle, ualni id); void updateTextureID(ImageHandle handle, ualni id);
void deleteImageHandle(ImageHandle image); 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: private:
Buffer<RectF> mScissors; Buffer<RectF> mScissors;
bool mIsClamping = false; bool mIsClamping = false;
Vec2F mOrigin = { 0, 0 };
}; };
class Graphics { class Graphics {

View file

@ -17,7 +17,7 @@ namespace tp {
public: public:
void draw(); void draw();
void processEvents(); void processEvents(bool wait = true);
void setEventHandler(EventHandler* eventHandler); void setEventHandler(EventHandler* eventHandler);
[[nodiscard]] EventHandler* getEventHandler(); [[nodiscard]] EventHandler* getEventHandler();

View file

@ -14,7 +14,7 @@ public:
gui.updateTracks(); gui.updateTracks();
} }
void processFrame(EventHandler* eventHandler) override { void processFrame(EventHandler* eventHandler, halnf delta) override {
auto rec = RectF{ { 0, 0 }, mWindow->getSize() }; auto rec = RectF{ { 0, 0 }, mWindow->getSize() };
gui.setVisible(true); gui.setVisible(true);

View file

@ -10,7 +10,7 @@ class SimpleGUI : public Application {
public: public:
SimpleGUI() { gui.cd(objects_api::create<DictObject>(), "root"); } SimpleGUI() { gui.cd(objects_api::create<DictObject>(), "root"); }
void processFrame(EventHandler* eventHandler) override {} void processFrame(EventHandler* eventHandler, halnf delta) override {}
void drawFrame(Canvas* canvas) override { void drawFrame(Canvas* canvas) override {
canvas->rect({ { 0, 0 }, mWindow->getSize() }, RGBA(0.f, 0.f, 0.f, 1.f), 0); canvas->rect({ { 0, 0 }, mWindow->getSize() }, RGBA(0.f, 0.f, 0.f, 1.f), 0);

View file

@ -11,7 +11,7 @@ public:
Sketch3DApplication() : Sketch3DApplication() :
mGui(*mGraphics->getCanvas(), { 1920, 1080 }) {} mGui(*mGraphics->getCanvas(), { 1920, 1080 }) {}
void processFrame(EventHandler* eventHandler) override { void processFrame(EventHandler* eventHandler, halnf delta) override {
auto rec = RectF({ 0, 0 }, mWindow->getSize()); auto rec = RectF({ 0, 0 }, mWindow->getSize());
mGui.setVisible(true); mGui.setVisible(true);

View file

@ -9,7 +9,7 @@ class ExampleGUI : public Application {
public: public:
ExampleGUI() = default; ExampleGUI() = default;
void processFrame(EventHandler* eventHandler) override { void processFrame(EventHandler* eventHandler, halnf delta) override {
auto rec = RectF({ 0, 0 }, mWindow->getSize()); auto rec = RectF({ 0, 0 }, mWindow->getSize());
mGui.updateConfigWrapper(mWidgetManager); mGui.updateConfigWrapper(mWidgetManager);

View file

@ -12,7 +12,7 @@ public:
// mGui.mPreview = true; // mGui.mPreview = true;
} }
void processFrame(EventHandler* eventHandler) override { void processFrame(EventHandler* eventHandler, halnf) override {
const auto rec = RectF({ 0, 0 }, mWindow->getSize()); const auto rec = RectF({ 0, 0 }, mWindow->getSize());
mGui.setArea(rec); mGui.setArea(rec);

View file

@ -37,6 +37,8 @@ void FloatingWidget::eventUpdateConfiguration(WidgetManager& wm) {
} }
void FloatingWidget::checkFloating(const Events& events) { void FloatingWidget::checkFloating(const Events& events) {
mDropped = false;
if (this->mHeader.isHolding() && events.getPointerDelta().length2() > 4) { if (this->mHeader.isHolding() && events.getPointerDelta().length2() > 4) {
mFloating = true; mFloating = true;
} }
@ -44,6 +46,7 @@ void FloatingWidget::checkFloating(const Events& events) {
if (mFloating && this->mHeader.isReleased()) { if (mFloating && this->mHeader.isReleased()) {
mFloating = false; mFloating = false;
this->mHeader.clearEvents(); this->mHeader.clearEvents();
mDropped = true;
} }
if (mFloating) { if (mFloating) {

View file

@ -19,11 +19,11 @@ void Widget::procWrapper(const Events& events, const RectF& parentArea) {
if (mHandlesEvents) { if (mHandlesEvents) {
eventProcess(events);
for (auto child : mChildWidgets) { for (auto child : mChildWidgets) {
child->procWrapper(events, mVisibleArea); child->procWrapper(events, mVisibleArea);
} }
eventProcess(events);
} }
} }

View file

@ -17,17 +17,18 @@ void WorkspaceWidget::eventProcess(const Events& events) {
for (auto floatingChild : mFloatingLayer.mChildWidgets) { for (auto floatingChild : mFloatingLayer.mChildWidgets) {
auto widget = dynamic_cast<FloatingWidget*>(floatingChild.data()); auto widget = dynamic_cast<FloatingWidget*>(floatingChild.data());
if (!widget) continue; 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.mHandlesEvents = true;
mDockSpace.mPreview = true; mDockSpace.mPreview = true;
} }

View file

@ -32,5 +32,7 @@ namespace tp {
public: public:
bool mResizable = true; bool mResizable = true;
bool mDropped = false;
}; };
} }