diff --git a/modules/v4d/include/opencv2/v4d/v4d.hpp b/modules/v4d/include/opencv2/v4d/v4d.hpp index a77576c4d..eb79f4824 100644 --- a/modules/v4d/include/opencv2/v4d/v4d.hpp +++ b/modules/v4d/include/opencv2/v4d/v4d.hpp @@ -116,7 +116,8 @@ using namespace cv::v4d::detail; class NVG; class CV_EXPORTS V4D { - friend class NanoVGContext; + friend class detail::NanoVGContext; + friend class detail::FrameBufferContext; const cv::Size initialSize_; cv::Rect viewport_; float scale_; diff --git a/modules/v4d/src/detail/clvacontext.cpp b/modules/v4d/src/detail/clvacontext.cpp index 891c00bc5..432caee3d 100644 --- a/modules/v4d/src/detail/clvacontext.cpp +++ b/modules/v4d/src/detail/clvacontext.cpp @@ -11,8 +11,8 @@ namespace cv { namespace v4d { namespace detail { -CLVAContext::CLVAContext(FrameBufferContext& clglContext) : - mainFbContext_(clglContext) { +CLVAContext::CLVAContext(FrameBufferContext& mainFbContext) : + mainFbContext_(mainFbContext) { } cv::Size CLVAContext::getVideoFrameSize() { diff --git a/modules/v4d/src/detail/framebuffercontext.cpp b/modules/v4d/src/detail/framebuffercontext.cpp index 2e006f814..e48b44488 100644 --- a/modules/v4d/src/detail/framebuffercontext.cpp +++ b/modules/v4d/src/detail/framebuffercontext.cpp @@ -7,15 +7,17 @@ #include "opencv2/v4d/util.hpp" #include "opencv2/v4d/v4d.hpp" +#include "glcontext.hpp" +#include "nanovgcontext.hpp" namespace cv { namespace v4d { namespace detail { -FrameBufferContext::FrameBufferContext(const FrameBufferContext& other) : FrameBufferContext(other.frameBufferSize_, true, other.title_, other.major_, other.minor_, other.compat_, other.samples_, other.debug_, other.glfwWindow_, &other) { +FrameBufferContext::FrameBufferContext(V4D& v4d, const FrameBufferContext& other) : FrameBufferContext(v4d, other.frameBufferSize_, true, other.title_, other.major_, other.minor_, other.compat_, other.samples_, other.debug_, other.glfwWindow_, &other) { } -FrameBufferContext::FrameBufferContext(const cv::Size& frameBufferSize, bool offscreen, +FrameBufferContext::FrameBufferContext(V4D& v4d, const cv::Size& frameBufferSize, bool offscreen, const string& title, int major, int minor, bool compat, int samples, bool debug, GLFWwindow* sharedWindow, const FrameBufferContext* parent) : offscreen_(offscreen), title_(title), major_(major), minor_( minor), compat_(compat), samples_(samples), debug_(debug), frameBufferSize_(frameBufferSize), isShared_(sharedWindow != nullptr), parent_(parent) { @@ -94,6 +96,80 @@ FrameBufferContext::FrameBufferContext(const cv::Size& frameBufferSize, bool off #ifndef __EMSCRIPTEN__ context_ = CLExecContext_t::getCurrent(); #endif + + glfwSetWindowUserPointer(getGLFWWindow(), &v4d); + + glfwSetCursorPosCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, double x, double y) { + V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v4d->screen().cursor_pos_callback_event(x, y); + auto cursor = v4d->getMousePosition(); + auto diff = cursor - cv::Vec2f(x, y); + if (v4d->isMouseDrag()) { + v4d->pan(diff[0], -diff[1]); + } + v4d->setMousePosition(x, y); + } + ); + glfwSetMouseButtonCallback(getGLFWWindow(), + [](GLFWwindow* glfwWin, int button, int action, int modifiers) { + V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v4d->screen().mouse_button_callback_event(button, action, modifiers); + if (button == GLFW_MOUSE_BUTTON_RIGHT) { + v4d->setMouseDrag(action == GLFW_PRESS); + } + } + ); + glfwSetKeyCallback(getGLFWWindow(), + [](GLFWwindow* glfwWin, int key, int scancode, int action, int mods) { + V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v4d->screen().key_callback_event(key, scancode, action, mods); + } + ); + glfwSetCharCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, unsigned int codepoint) { + V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v4d->screen().char_callback_event(codepoint); + } + ); + glfwSetDropCallback(getGLFWWindow(), + [](GLFWwindow* glfwWin, int count, const char** filenames) { + V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v4d->screen().drop_callback_event(count, filenames); + } + ); + glfwSetScrollCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, double x, double y) { + V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + std::vector widgets; + find_widgets(&v4d->screen(), widgets); + for (auto* w : widgets) { + auto mousePos = nanogui::Vector2i(v4d->getMousePosition()[0] / v4d->fbCtx().getXPixelRatio(), v4d->getMousePosition()[1] / v4d->fbCtx().getYPixelRatio()); + if(contains_absolute(w, mousePos)) { + v4d->screen().scroll_callback_event(x, y); + return; + } +} + + v4d->zoom(y < 0 ? 1.1 : 0.9); + } + ); + + glfwSetFramebufferSizeCallback(getGLFWWindow(), + [](GLFWwindow* glfwWin, int width, int height) { + V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); + v4d->screen().resize_callback_event(width, height); + cv::Rect& vp = v4d->viewport(); + vp.x = 0; + vp.y = 0; + vp.width = width; + vp.height = height; +#ifndef __EMSCRIPTEN__ + v4d->nvgCtx().fbCtx().teardown(); + v4d->glCtx().fbCtx().teardown(); + v4d->fbCtx().teardown(); + v4d->fbCtx().setup(cv::Size(width, height)); + v4d->glCtx().fbCtx().setup(cv::Size(width, height)); + v4d->nvgCtx().fbCtx().setup(cv::Size(width, height)); +#endif + }); } FrameBufferContext::~FrameBufferContext() { @@ -380,6 +456,8 @@ void FrameBufferContext::releaseToGL(cv::UMat& m) { if (clglSharing_) { GL_CHECK(toGLTexture2D(m, getTexture2D())); } else { + if(m.empty()) + m.create(getSize(), CV_8UC4); upload(m); GL_CHECK(glFlush()); GL_CHECK(glFinish()); diff --git a/modules/v4d/src/detail/framebuffercontext.hpp b/modules/v4d/src/detail/framebuffercontext.hpp index a753b4bd5..ddd09b856 100644 --- a/modules/v4d/src/detail/framebuffercontext.hpp +++ b/modules/v4d/src/detail/framebuffercontext.hpp @@ -143,10 +143,10 @@ public: * Create a FrameBufferContext with given size. * @param frameBufferSize The frame buffer size. */ - FrameBufferContext(const cv::Size& frameBufferSize, bool offscreen, + FrameBufferContext(V4D& v4d, const cv::Size& frameBufferSize, bool offscreen, const string& title, int major, int minor, bool compat, int samples, bool debug, GLFWwindow* sharedWindow, const FrameBufferContext* parent); - FrameBufferContext(const FrameBufferContext& other); + FrameBufferContext(V4D& v4d, const FrameBufferContext& other); /*! * Default destructor. diff --git a/modules/v4d/src/detail/glcontext.cpp b/modules/v4d/src/detail/glcontext.cpp index e26f16914..fb93c9905 100644 --- a/modules/v4d/src/detail/glcontext.cpp +++ b/modules/v4d/src/detail/glcontext.cpp @@ -8,12 +8,15 @@ namespace cv { namespace v4d { namespace detail { -GLContext::GLContext(FrameBufferContext& fbContext) : - mainFbContext_(fbContext), glFbContext_(fbContext) { +GLContext::GLContext(V4D& v4d, FrameBufferContext& fbContext) : + mainFbContext_(fbContext), glFbContext_(v4d, fbContext) { } void GLContext::render(std::function fn) { #ifdef __EMSCRIPTEN__ + fb_.create(mainFbContext_.getSize(), CV_8UC4); + preFB_.create(mainFbContext_.getSize(), CV_8UC4); + postFB_.create(mainFbContext_.getSize(), CV_8UC4); { FrameBufferContext::GLScope mainGlScope(mainFbContext_); FrameBufferContext::FrameBufferScope fbScope(mainFbContext_, fb_); diff --git a/modules/v4d/src/detail/glcontext.hpp b/modules/v4d/src/detail/glcontext.hpp index 9bdd015fb..dd007f52b 100644 --- a/modules/v4d/src/detail/glcontext.hpp +++ b/modules/v4d/src/detail/glcontext.hpp @@ -41,7 +41,7 @@ public: * Creates a OpenGL Context * @param fbContext The framebuffer context */ - GLContext(FrameBufferContext& fbContext); + GLContext(V4D& v4d, FrameBufferContext& fbContext); /*! * Execute function object fn inside a gl context. * The context takes care of setting up opengl states. diff --git a/modules/v4d/src/detail/nanovgcontext.cpp b/modules/v4d/src/detail/nanovgcontext.cpp index fe24e4516..82084f6cc 100644 --- a/modules/v4d/src/detail/nanovgcontext.cpp +++ b/modules/v4d/src/detail/nanovgcontext.cpp @@ -8,8 +8,8 @@ namespace cv { namespace v4d { namespace detail { -NanoVGContext::NanoVGContext(FrameBufferContext& fbContext) : - mainFbContext_(fbContext), nvgFbContext_(fbContext) { +NanoVGContext::NanoVGContext(V4D& v4d, FrameBufferContext& fbContext) : + mainFbContext_(fbContext), nvgFbContext_(v4d, fbContext) { screen_ = new nanogui::Screen(); screen_->initialize(nvgFbContext_.getGLFWWindow(), false); context_ = screen_->nvg_context(); diff --git a/modules/v4d/src/detail/nanovgcontext.hpp b/modules/v4d/src/detail/nanovgcontext.hpp index 6eb2cc421..eefb90975 100644 --- a/modules/v4d/src/detail/nanovgcontext.hpp +++ b/modules/v4d/src/detail/nanovgcontext.hpp @@ -65,7 +65,7 @@ public: * @param context The native NVGContext * @param fbContext The framebuffer context */ - NanoVGContext(FrameBufferContext& fbContext); + NanoVGContext(V4D& v4d, FrameBufferContext& fbContext); /*! * Execute function object fn inside a nanovg context. * The context takes care of setting up opengl and nanovg states. diff --git a/modules/v4d/src/v4d.cpp b/modules/v4d/src/v4d.cpp index cf10a4e9f..c383eaff6 100644 --- a/modules/v4d/src/v4d.cpp +++ b/modules/v4d/src/v4d.cpp @@ -79,15 +79,19 @@ V4D::V4D(const cv::Size& size, bool offscreen, const string& title, int major, i bool compat, int samples, bool debug) : initialSize_(size), viewport_(0, 0, size.width, size.height), scale_(1), mousePos_(0, 0), stretch_( false), offscreen_(offscreen) { - mainFbContext_ = new detail::FrameBufferContext(size, offscreen, title, + screen_ = new nanogui::Screen(); + mainFbContext_ = new detail::FrameBufferContext(*this, size, offscreen, title, major, minor, compat, samples, debug, nullptr, nullptr); clvaContext_ = new detail::CLVAContext(*mainFbContext_); - glContext_ = new detail::GLContext(*mainFbContext_); - nvgContext_ = new detail::NanoVGContext(*mainFbContext_); + glContext_ = new detail::GLContext(*this, *mainFbContext_); + nvgContext_ = new detail::NanoVGContext(*this, *mainFbContext_); - if (!initializeGUI()) - assert(false); + fbCtx().makeCurrent(); + screen().initialize(getGLFWWindow(), false); + form_ = new FormHelper(&screen()); + + this->setWindowSize(initialSize_); } V4D::~V4D() { @@ -108,112 +112,6 @@ V4D::~V4D() { delete mainFbContext_; } -bool V4D::initializeGUI() { - try { - screen_ = new nanogui::Screen(); - screen().initialize(getGLFWWindow(), false); - form_ = new FormHelper(&screen()); - - this->setWindowSize(initialSize_); - - glfwSetWindowUserPointer(getGLFWWindow(), this); - - glfwSetCursorPosCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, double x, double y) { - V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); - v4d->screen().cursor_pos_callback_event(x, y); - auto cursor = v4d->getMousePosition(); - auto diff = cursor - cv::Vec2f(x, y); - if (v4d->isMouseDrag()) { - v4d->pan(diff[0], -diff[1]); - } - v4d->setMousePosition(x, y); - } - ); - glfwSetMouseButtonCallback(getGLFWWindow(), - [](GLFWwindow* glfwWin, int button, int action, int modifiers) { - V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); - v4d->screen().mouse_button_callback_event(button, action, modifiers); - if (button == GLFW_MOUSE_BUTTON_RIGHT) { - v4d->setMouseDrag(action == GLFW_PRESS); - } - } - ); - glfwSetKeyCallback(getGLFWWindow(), - [](GLFWwindow* glfwWin, int key, int scancode, int action, int mods) { - V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); - v4d->screen().key_callback_event(key, scancode, action, mods); - } - ); - glfwSetCharCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, unsigned int codepoint) { - V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); - v4d->screen().char_callback_event(codepoint); - } - ); - glfwSetDropCallback(getGLFWWindow(), - [](GLFWwindow* glfwWin, int count, const char** filenames) { - V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); - v4d->screen().drop_callback_event(count, filenames); - } - ); - glfwSetScrollCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, double x, double y) { - V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); - std::vector widgets; - find_widgets(&v4d->screen(), widgets); - for (auto* w : widgets) { - auto mousePos = nanogui::Vector2i(v4d->getMousePosition()[0] / v4d->fbCtx().getXPixelRatio(), v4d->getMousePosition()[1] / v4d->fbCtx().getYPixelRatio()); - if(contains_absolute(w, mousePos)) { - v4d->screen().scroll_callback_event(x, y); - return; - } - } - - v4d->zoom(y < 0 ? 1.1 : 0.9); - } - ); - -// glfwSetWindowSizeCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, int width, int height) { -// V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); -// GLFWmonitor* monitor = glfwGetPrimaryMonitor(); -// const GLFWvidmode* mode = glfwGetVideoMode(monitor); -// int w = mode->width; -// int h = mode->height; -// -//// v4d->screen().resize_callback_event(width, height); -// if (width <= w && height <= h) { -// cerr << "winsize: " << width << ":" << height << endl; -// v4d->nvgCtx().fbCtx().teardown(); -// v4d->glCtx().fbCtx().teardown(); -// v4d->fbCtx().teardown(); -// v4d->fbCtx().setup(cv::Size(width, height)); -// v4d->glCtx().fbCtx().setup(cv::Size(width, height)); -// v4d->nvgCtx().fbCtx().setup(cv::Size(width, height)); -// } -// }); - glfwSetFramebufferSizeCallback(getGLFWWindow(), - [](GLFWwindow* glfwWin, int width, int height) { - V4D* v4d = reinterpret_cast(glfwGetWindowUserPointer(glfwWin)); - v4d->screen().resize_callback_event(width, height); - cv::Rect& vp = v4d->viewport(); - vp.x = 0; - vp.y = 0; - vp.width = width; - vp.height = height; -#ifndef __EMSCRIPTEN__ - v4d->nvgCtx().fbCtx().teardown(); - v4d->glCtx().fbCtx().teardown(); - v4d->fbCtx().teardown(); - v4d->fbCtx().setup(cv::Size(width, height)); - v4d->glCtx().fbCtx().setup(cv::Size(width, height)); - v4d->nvgCtx().fbCtx().setup(cv::Size(width, height)); -#endif - }); - } catch (std::exception& ex) { - cerr << "V4D initialization failed: " << ex.what() << endl; - return false; - } - return true; -} - cv::ogl::Texture2D& V4D::texture() { return mainFbContext_->getTexture2D(); } @@ -259,7 +157,6 @@ GLContext& V4D::glCtx() { nanogui::Screen& V4D::screen() { assert(screen_ != nullptr); - fbCtx().makeCurrent(); return *screen_; }